UNPKG

@finos/legend-studio

Version:
320 lines (290 loc) 9.57 kB
/** * Copyright (c) 2020-present, Goldman Sachs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { type TestAssertion, type AssertionStatus, AssertFail, type TestResult, TestPassed, TestError, TestFailed, EqualToJson, ExternalFormatData, EqualToJsonAssertFail, MultiExecutionServiceTestResult, AssertPass, } from '@finos/legend-graph'; import { type GeneratorFn, ActionState, assertErrorThrown, ContentType, } from '@finos/legend-shared'; import { action, flow, makeObservable, observable } from 'mobx'; import type { EditorStore } from '../../../EditorStore.js'; import { externalFormatData_setData } from '../../../graphModifier/DSLData_GraphModifierHelper.js'; import { getTestableResultFromAssertionStatus, TESTABLE_RESULT, } from '../../../sidebar-state/testable/GlobalTestRunnerState.js'; import type { TestableTestEditorState } from './TestableEditorState.js'; export enum TEST_ASSERTION_TAB { ASSERTION_SETUP = 'ASSERTION_SETUP', ASSERTION_RESULT = 'ASSERTION_RESULT', } export abstract class TestAssertionStatusState { resultState: TestAssertionResultState; status: AssertionStatus; constructor(resultState: TestAssertionResultState, status: AssertionStatus) { this.resultState = resultState; this.status = status; } } export class AssertFailState extends TestAssertionStatusState { declare status: AssertFail; constructor(resultState: TestAssertionResultState, status: AssertFail) { super(resultState, status); this.status = status; makeObservable(this, { status: observable, }); } } export class EqualToJsonAssertFailState extends AssertFailState { declare status: EqualToJsonAssertFail; diffModal = false; constructor( resultState: TestAssertionResultState, status: EqualToJsonAssertFail, ) { super(resultState, status); this.status = status; makeObservable(this, { diffModal: observable, setDiffModal: action, }); } setDiffModal(val: boolean): void { this.diffModal = val; } } export class UnsupportedAssertionStatusState extends TestAssertionStatusState {} export class TestAssertionResultState { testResult: TestResult | undefined; statusState: | TestAssertionStatusState | Map<string, TestAssertionResultState> | undefined; readonly editorStore: EditorStore; readonly assertionState: TestAssertionEditorState; constructor( editorStore: EditorStore, assertionState: TestAssertionEditorState, ) { makeObservable(this, { testResult: observable, setTestResult: action, statusState: observable, }); this.editorStore = editorStore; this.assertionState = assertionState; } setTestResult(val: TestResult | undefined): void { this.testResult = val; this.statusState = undefined; if (val instanceof TestFailed) { const status = val.assertStatuses.find( (_status) => _status.assertion === this.assertionState.assertion, ); this.statusState = this.buildStatus(status); } else if (val instanceof MultiExecutionServiceTestResult) { const statusMap = new Map<string, TestAssertionResultState>(); Array.from(val.keyIndexedTestResults.entries()).forEach((keyedResult) => { const resultState = new TestAssertionResultState( this.editorStore, this.assertionState, ); resultState.setTestResult(keyedResult[1]); statusMap.set(keyedResult[0], resultState); }); this.statusState = statusMap; } } buildStatus( val: AssertionStatus | undefined, ): TestAssertionStatusState | undefined { if (val) { if (val instanceof EqualToJsonAssertFail) { return new EqualToJsonAssertFailState(this, val); } if (val instanceof AssertFail) { return new AssertFailState(this, val); } return new UnsupportedAssertionStatusState(this, val); } return undefined; } get result(): TESTABLE_RESULT { if (this.assertionState.testState.runningTestAction.isInProgress) { return TESTABLE_RESULT.IN_PROGRESS; } if (this.testResult instanceof TestError) { return TESTABLE_RESULT.ERROR; } else if (this.testResult instanceof TestPassed) { return TESTABLE_RESULT.PASSED; } else if ( this.testResult instanceof TestFailed && this.statusState instanceof TestAssertionStatusState ) { return getTestableResultFromAssertionStatus(this.statusState.status); } else if (this.testResult instanceof MultiExecutionServiceTestResult) { const passed = Array.from( this.testResult.keyIndexedTestResults.entries(), ).every((keyResult) => { const result = keyResult[1]; if (result instanceof TestPassed) { return true; } if (result instanceof TestFailed) { const status = result.assertStatuses.find( (_status) => _status.assertion === this.assertionState.assertion, ); if (status instanceof AssertPass) { return true; } } return false; }); if (passed) { return TESTABLE_RESULT.PASSED; } const assertionErrors = Array.from( this.testResult.keyIndexedTestResults.values(), ).find((t) => t instanceof TestError); if (assertionErrors) { return TESTABLE_RESULT.ERROR; } return TESTABLE_RESULT.FAILED; } return TESTABLE_RESULT.DID_NOT_RUN; } } export abstract class TestAssertionState { readonly editorStore: EditorStore; assertion: TestAssertion; result: TestAssertionResultState; constructor( editorStore: EditorStore, assertionState: TestAssertionEditorState, ) { this.editorStore = editorStore; this.assertion = assertionState.assertion; this.result = new TestAssertionResultState(editorStore, assertionState); } abstract generateExpected(status: AssertFail): void; abstract generateBare(): TestAssertion; abstract label(): string; } export class EqualToJsonAssertionState extends TestAssertionState { declare assertion: EqualToJson; setExpectedValue(val: string): void { externalFormatData_setData(this.assertion.expected, val); } generateExpected(status: AssertFail): void { if (status instanceof EqualToJsonAssertFail) { const expected = status.actual; this.setExpectedValue(expected); } } generateBare(): TestAssertion { const bareAssertion = new EqualToJson(); bareAssertion.expected = new ExternalFormatData(); bareAssertion.expected.contentType = ContentType.APPLICATION_JSON; bareAssertion.expected.data = ''; return bareAssertion; } label(): string { return 'EqualToJSON'; } } export class UnsupportedAssertionState extends TestAssertionState { generateBare(): TestAssertion { throw new Error('Method not implemented.'); } generateExpected(status: AssertFail): void { return; } label(): string { return 'Unsupported'; } } export class TestAssertionEditorState { readonly editorStore: EditorStore; readonly testState: TestableTestEditorState; assertionState: TestAssertionState; assertionResultState: TestAssertionResultState; assertion: TestAssertion; selectedTab = TEST_ASSERTION_TAB.ASSERTION_SETUP; generatingExpectedAction = ActionState.create(); constructor( editorStore: EditorStore, assertion: TestAssertion, testState: TestableTestEditorState, ) { makeObservable(this, { selectedTab: observable, assertionResultState: observable, setSelectedTab: action, generateExpected: flow, }); this.editorStore = editorStore; this.assertion = assertion; this.testState = testState; this.assertionState = this.buildAssertionState(assertion); this.assertionResultState = new TestAssertionResultState(editorStore, this); } setSelectedTab(val: TEST_ASSERTION_TAB): void { this.selectedTab = val; } *generateExpected(): GeneratorFn<void> { try { this.generatingExpectedAction.inProgress(); const bare = this.assertionState.generateBare(); bare.parentTest = this.assertion.parentTest; const status = (yield this.editorStore.graphManagerState.graphManager.generateExpectedResult( this.testState.testable, this.testState.test, bare, this.editorStore.graphManagerState.graph, )) as AssertFail; this.assertionState.generateExpected(status); this.generatingExpectedAction.complete(); } catch (error) { assertErrorThrown(error); this.editorStore.applicationStore.notifyError( `Error generating expected result: ${error.message}`, ); this.generatingExpectedAction.fail(); } } buildAssertionState(assertion: TestAssertion): TestAssertionState { if (assertion instanceof EqualToJson) { return new EqualToJsonAssertionState(this.editorStore, this); } return new UnsupportedAssertionState(this.editorStore, this); } }