diff --git a/src/models/Chemistry.ts b/src/models/Chemistry.ts index 80e3cda..58c0d38 100644 --- a/src/models/Chemistry.ts +++ b/src/models/Chemistry.ts @@ -580,7 +580,7 @@ export function check(test: ChemAST, target: ChemAST, options: ChemistryOptions) response.expectedType = target.result.type; response.receivedType = test.result.type; - if (isEqual(test.result, target.result) && !options.keepAggregates) { + if (!options.keepAggregates && isEqual(test.result, target.result)) { return response; } diff --git a/src/models/Nuclear.ts b/src/models/Nuclear.ts index 1382070..2c9024b 100644 --- a/src/models/Nuclear.ts +++ b/src/models/Nuclear.ts @@ -309,12 +309,12 @@ function checkNodesEqual(test: ASTNode, target: ASTNode, response: CheckerRespon } } -export function check(test: NuclearAST, target: NuclearAST): CheckerResponse { - const response = STARTING_RESPONSE(); +export function check(test: NuclearAST, target: NuclearAST, options: ChemistryOptions): CheckerResponse { + const response = STARTING_RESPONSE(options); response.expectedType = target.result.type; response.receivedType = test.result.type; - if (isEqual(test.result, target.result)) { + if (!options.keepAggregates && isEqual(test.result, target.result)) { return response; } diff --git a/src/routes/Nuclear.ts b/src/routes/Nuclear.ts index c3f0397..fd164bf 100644 --- a/src/routes/Nuclear.ts +++ b/src/routes/Nuclear.ts @@ -25,7 +25,7 @@ router.post('/check', checkValidationRules, (req: Request, res: Response) => { const target: NuclearAST = augment(parseNuclearExpression(req.body.target)[0]); const test: NuclearAST = augment(parseNuclearExpression(req.body.test)[0]); - const result: CheckerResponse = check(test, target); + const result: CheckerResponse = check(test, target, {}); res.status(201).send(result); diff --git a/test/models/Chemistry.test.ts b/test/models/Chemistry.test.ts index d028193..73a44c7 100644 --- a/test/models/Chemistry.test.ts +++ b/test/models/Chemistry.test.ts @@ -1,4 +1,3 @@ -import exp from "constants"; import { Bracket, Compound, Element, exportedForTesting, Ion, Term, Expression, Statement, ParseError, check, ChemAST, augment, STARTING_COEFFICIENT, Result, ASTNode, isExpression } from "../../src/models/Chemistry"; import { CheckerResponse, listComparison, ChemistryOptions } from "../../src/models/common"; const { augmentNode } = exportedForTesting; @@ -139,7 +138,7 @@ function testCheck(target: T, test: T, options?: ChemistryOpt } function unaugmentedTestCheck(target: T, test: T, options?: ChemistryOptions): CheckerResponse { - return check({result: target as unknown as Result}, {result: test as unknown as Result}, options ?? {}); + return check(structuredClone({result: target as unknown as Result}), structuredClone({result: test as unknown as Result}), options ?? {}); } describe("listComparison", () => { @@ -277,7 +276,7 @@ describe("testCheck Compounds", () => { const compoundCopy: Compound = structuredClone(compound); // Act - const testResponse = testCheck(compoundCopy, structuredClone(compound), { keepAggregates: true }); + const testResponse = testCheck(compound, compoundCopy, { keepAggregates: true }); // Assert expect(testResponse.isEqual).toBeTruthy(); @@ -297,7 +296,7 @@ describe("testCheck Compounds", () => { const permutationsOptions = { allowPermutations: true }; // Act - const testResponse = testCheck(permutedCompound, structuredClone(compound), permutationsOptions); + const testResponse = testCheck(permutedCompound, compound, permutationsOptions); const hydrocarbonResponse = testCheck(hydrocarbonCompound, permutedHydrocarbonCompound, permutationsOptions); // Assert @@ -314,8 +313,8 @@ describe("testCheck Compounds", () => { lengthMismatch.elements?.push(structuredClone(element)); // Act - const typesIncorrect = unaugmentedTestCheck(typeMismatch, augmentNode(structuredClone(compound))); - const lengthIncorrect = unaugmentedTestCheck(lengthMismatch, augmentNode(structuredClone(compound))); + const typesIncorrect = unaugmentedTestCheck(typeMismatch, augmentedCompound); + const lengthIncorrect = unaugmentedTestCheck(lengthMismatch, augmentedCompound); // Assert expect(typesIncorrect.isEqual).toBeFalsy(); @@ -341,8 +340,8 @@ describe("testCheck Compounds", () => { elementMismatch.elements = [elementCoeffMismatch]; // Act - const bracketResponse: CheckerResponse = testCheck(bracketCoeffMismatch, structuredClone(bracket)); - const elementResponse: CheckerResponse = testCheck(elementCoeffMismatch, structuredClone(element)); + const bracketResponse: CheckerResponse = testCheck(bracketCoeffMismatch, bracket); + const elementResponse: CheckerResponse = testCheck(elementCoeffMismatch, element); // Assert expect(testCheck(bracketMismatch, minimalBracketCompound)).toEqual({...bracketResponse, expectedType: "compound", receivedType: "compound"}); @@ -352,7 +351,7 @@ describe("testCheck Compounds", () => { it("Returns an error if the AST is not augmented", () => { // Act - const testResponse = unaugmentedTestCheck(structuredClone(compound), augmentedCompound, { keepAggregates: true }); + const testResponse = unaugmentedTestCheck(compound, augmentedCompound, { keepAggregates: true }); // Assert expect(testResponse.containsError).toBeTruthy(); @@ -370,7 +369,7 @@ describe("testCheck Ions", () => { const ionClone: Ion = structuredClone(ion); // Act - const testResponse = testCheck(structuredClone(ion), ionClone, { keepAggregates: true }); + const testResponse = testCheck(ion, ionClone, { keepAggregates: true }); // Assert expect(testResponse.isEqual).toBeTruthy(); @@ -389,7 +388,7 @@ describe("testCheck Ions", () => { const permutationsOptions = { allowPermutations: true, keepAggregates: true }; // Act - const testResponse = testCheck(permutedIon, structuredClone(ion), permutationsOptions); + const testResponse = testCheck(permutedIon, ion, permutationsOptions); // Assert expect(testResponse.isEqual).toBeTruthy(); @@ -405,7 +404,7 @@ describe("testCheck Ions", () => { } // Act - const moleculeIncorrect = unaugmentedTestCheck(moleculeMismatch, structuredClone(augmentedIon), { keepAggregates: true }); + const moleculeIncorrect = unaugmentedTestCheck(moleculeMismatch, augmentedIon, { keepAggregates: true }); // Assert expect(moleculeIncorrect.isEqual).toBeFalsy(); @@ -422,7 +421,7 @@ describe("testCheck Ions", () => { } // Act - const chargeIncorrect = unaugmentedTestCheck(chargeMismatch, structuredClone(augmentedIon), { keepAggregates: true }); + const chargeIncorrect = unaugmentedTestCheck(chargeMismatch, augmentedIon, { keepAggregates: true }); // Assert expect(chargeIncorrect.isEqual).toBeFalsy(); @@ -436,7 +435,7 @@ describe("testCheck Ions", () => { lengthMismatch.molecules?.push([structuredClone(element), 1]); // Act - const lengthIncorrect = unaugmentedTestCheck(lengthMismatch, structuredClone(augmentedIon), { keepAggregates: true}); + const lengthIncorrect = unaugmentedTestCheck(lengthMismatch, augmentedIon, { keepAggregates: true}); // Assert expect(lengthIncorrect.isEqual).toBeFalsy(); @@ -445,7 +444,7 @@ describe("testCheck Ions", () => { it("Returns an error if the AST is not augmented", () => { // Act - const testResponse = unaugmentedTestCheck(structuredClone(ion), augmentedIon); + const testResponse = unaugmentedTestCheck(ion, augmentedIon); // Assert expect(testResponse.containsError).toBeTruthy(); @@ -511,7 +510,7 @@ describe("testCheck Term", () => { perturbedTerm.coeff = { numerator: 6, denominator: 4 }; // Act - const testResponse = testCheck(perturbedTerm, structuredClone(term), scaledOptions); + const testResponse = testCheck(perturbedTerm, term, scaledOptions); // Assert expect(testResponse.isEqual).toBeTruthy(); @@ -525,7 +524,7 @@ describe("testCheck Term", () => { mismatchTerm.coeff = { numerator: 1, denominator: 5 }; // Act - const testResponse = testCheck(mismatchTerm, structuredClone(term)); + const testResponse = testCheck(mismatchTerm, term); // Assert expect(testResponse.isEqual).toBeFalsy(); @@ -576,7 +575,7 @@ describe("testCheck Term", () => { mismatchTerm.value = { type: "electron" }; // Act - const testResponse = testCheck(mismatchTerm, structuredClone(term)); + const testResponse = testCheck(mismatchTerm, term); // Assert expect(testResponse.isEqual).toBeFalsy(); @@ -590,8 +589,8 @@ describe("testCheck Term", () => { complexTerm.value = structuredClone(compound); // Act - const testResponse = testCheck(complexTerm, structuredClone(term)); - const compoundResponse = testCheck(structuredClone(compound), minimalCompound); + const testResponse = testCheck(complexTerm, term); + const compoundResponse = testCheck(compound, minimalCompound); // Assert expect(testResponse).toEqual({...compoundResponse, expectedType: "term", receivedType: "term"}); @@ -627,7 +626,7 @@ describe("testCheck Expression", () => { } // Act - const testResponse = unaugmentedTestCheck(perturbedExpression, structuredClone(augmentedExpression), scaledOptions); + const testResponse = unaugmentedTestCheck(perturbedExpression, augmentedExpression, scaledOptions); // Assert expect(testResponse.isEqual).toBeTruthy(); @@ -673,7 +672,7 @@ describe("testCheck Expression", () => { it("Returns an error if the AST is not augmented", () => { // Act - const testResponse = unaugmentedTestCheck(structuredClone(expression), augmentedExpression); + const testResponse = unaugmentedTestCheck(expression, augmentedExpression); // Assert expect(testResponse.containsError).toBeTruthy(); @@ -698,13 +697,12 @@ describe("testCheck Statement", () => { // Arrange const copy: Statement = structuredClone(statement); - const copyResult: CheckerResponse = testCheck(copy, statement); - - copy.arrow = "DArr"; const doubleArrowCopy: Statement = structuredClone(copy); + doubleArrowCopy.arrow = "DArr"; // Act - const arrowResult = testCheck(copy, doubleArrowCopy); + const copyResult: CheckerResponse = testCheck(copy, statement, { keepAggregates: true }); + const arrowResult: CheckerResponse = testCheck(doubleArrowCopy, doubleArrowCopy, { keepAggregates: true }); // Assert expect(copyResult.isEqual).toBeTruthy(); @@ -728,7 +726,7 @@ describe("testCheck Statement", () => { } // Act - const testResponse = unaugmentedTestCheck(perturbedStatement, structuredClone(augmentedStatement), scaledOptions); + const testResponse = unaugmentedTestCheck(perturbedStatement, augmentedStatement, scaledOptions); // Assert expect(testResponse.isEqual).toBeTruthy(); @@ -787,7 +785,7 @@ describe("testCheck Statement", () => { it("Returns truthy CheckerResponse when statements charges are balanced", () => { // Arrange - const balancedCharges: Statement = augmentNode(structuredClone(statement)); + const balancedCharges: Statement = structuredClone(augmentedStatement); balancedCharges.left = structuredClone(chargedExpr); balancedCharges.right = structuredClone(chargedExpr); @@ -803,7 +801,7 @@ describe("testCheck Statement", () => { it("Returns falsy CheckerResponse when statements charges are unbalanced", () => { // Arrange - const unbalancedCharges: Statement = augmentNode(structuredClone(statement)); + const unbalancedCharges: Statement = structuredClone(augmentedStatement); unbalancedCharges.left = structuredClone(chargedExpr); // Act diff --git a/test/models/Nuclear.test.ts b/test/models/Nuclear.test.ts index 73907ec..74b5df7 100644 --- a/test/models/Nuclear.test.ts +++ b/test/models/Nuclear.test.ts @@ -1,5 +1,5 @@ import { Particle, Isotope, Term, Expression, Statement, ParseError, check, NuclearAST, exportedForTesting, Result, ASTNode, augmentNode } from "../../src/models/Nuclear"; -import { CheckerResponse } from "../../src/models/common"; +import { CheckerResponse, ChemistryOptions } from "../../src/models/common"; const original = console.error; @@ -67,22 +67,26 @@ const particleTerm: Term = { coeff: 2, isParticle: true }; + const expression: Expression = { type: "expr", term: structuredClone(term), - terms: [structuredClone(term), structuredClone(particleTerm)] + rest: structuredClone(particleTerm) } +const augmentedExpression: Expression = augmentNode(structuredClone(expression)); + const statement: Statement = { type: "statement", left: structuredClone(term), - right: structuredClone(particleTerm), + right: structuredClone(expression), } +const augmentedStatement: Statement = augmentNode(structuredClone(statement)); -function testCheck(target: T, test: T): CheckerResponse { - return check({result: augmentNode(target) as unknown as Result}, {result: augmentNode(test) as unknown as Result}); +function testCheck(target: T, test: T, options?: ChemistryOptions): CheckerResponse { + return check({result: augmentNode(structuredClone(target)) as unknown as Result}, {result: augmentNode(structuredClone(test)) as unknown as Result}, options ?? {}); } -function unaugmentedTestCheck(target: T, test: T): CheckerResponse { - return check({result: target as unknown as Result}, {result: test as unknown as Result}); +function unaugmentedTestCheck(target: T, test: T, options?: ChemistryOptions): CheckerResponse { + return check(structuredClone({result: target as unknown as Result}), structuredClone({result: test as unknown as Result}), options ?? {}); } describe("testCheck Particle", () => { @@ -240,11 +244,11 @@ describe("testCheck Expression", () => { it("Returns truthy CheckerResponse when expressions match", () => { // Arrange - const permutedExpression: Expression = structuredClone(expression); + const permutedExpression: Expression = structuredClone(augmentedExpression); permutedExpression.terms?.reverse; // Act - const testResponse: CheckerResponse = testCheck(permutedExpression, expression); + const testResponse: CheckerResponse = unaugmentedTestCheck(permutedExpression, augmentedExpression); // Assert expect(testResponse.isEqual).toBeTruthy(); @@ -253,15 +257,15 @@ describe("testCheck Expression", () => { it("Returns falsy CheckerResponse when expressions do not match", () => { // Arrange - const lengthMismatch: Expression = structuredClone(expression); - lengthMismatch.terms?.push(structuredClone(term)); + const lengthMismatch: Expression = structuredClone(augmentedExpression); + lengthMismatch.terms?.push(structuredClone(term)) - const termMismatch: Expression = structuredClone(expression); - if (termMismatch.terms) termMismatch.terms[1] = structuredClone(term); + const termMismatch: Expression = structuredClone(augmentedExpression); + if (termMismatch.terms) termMismatch.terms[1] = structuredClone(particleTerm); // Act - const lengthIncorrect = testCheck(lengthMismatch, expression); - const termIncorrect = testCheck(termMismatch, expression); + const lengthIncorrect = unaugmentedTestCheck(lengthMismatch, augmentedExpression); + const termIncorrect = unaugmentedTestCheck(termMismatch, augmentedExpression); // Assert expect(lengthIncorrect.isEqual).toBeFalsy(); @@ -270,16 +274,8 @@ describe("testCheck Expression", () => { ); it("Returns an error if the AST is not augmented", () => { - // Arrange - // This is the same as expression just unaugmented - const unaugmentedExpression: Expression = { - type: "expr", - term: structuredClone(term), - rest: structuredClone(particleTerm) - } - // Act - const testResponse = unaugmentedTestCheck(unaugmentedExpression, expression); + const testResponse = unaugmentedTestCheck(expression, expression, { keepAggregates: true }); // Assert expect(testResponse.containsError).toBeTruthy(); @@ -318,26 +314,48 @@ describe("testCheck Statement", () => { expect(swapResult.isEqual).toBeFalsy(); } ); - it("Correctly checks whether statements are balanced", + it("Returns truthy CheckerResponse when expressions are balanced", () => { // Arrange const balancedStatement: Statement = structuredClone(statement); balancedStatement.right = structuredClone(term); // Act - const balancedResponse = testCheck(balancedStatement, balancedStatement); - const unbalancedResponse = testCheck(statement, balancedStatement); + const balancedResponse = testCheck(balancedStatement, balancedStatement, { keepAggregates: true }); // Assert expect(balancedResponse.isBalanced).toBeTruthy(); expect(balancedResponse.balancedAtom).toBeTruthy(); expect(balancedResponse.balancedMass).toBeTruthy(); + } + ) + it("Returns falsy CheckerResponse when expressions are balanced", + () => { + // Arrange + const balancedStatement: Statement = structuredClone(statement); + balancedStatement.right = structuredClone(term); + + // Act + const unbalancedResponse = testCheck(statement, statement, { keepAggregates: true }); + // Assert expect(unbalancedResponse.isBalanced).toBeFalsy(); expect(unbalancedResponse.balancedAtom).toBeFalsy(); expect(unbalancedResponse.balancedMass).toBeFalsy(); } ); + it("Returns an error if the AST is not augmented", + () => { + // Act + const testResponse = unaugmentedTestCheck(statement, statement, { keepAggregates: true }); + + // Assert + expect(testResponse.containsError).toBeTruthy(); + expect(testResponse.error).toEqual("Received unaugmented AST during checking process."); + + expect(console.error).toHaveBeenCalled(); + } + ); }); describe("Check", () => { @@ -364,7 +382,7 @@ describe("Check", () => { } // Act - const response: CheckerResponse = check(errorAST, ast); + const response: CheckerResponse = check(errorAST, ast, {}); // Assert expect(response.containsError).toBeTruthy(); @@ -380,7 +398,7 @@ describe("Check", () => { } // Act - const response: CheckerResponse = check(ast, expressionAST); + const response: CheckerResponse = check(ast, expressionAST, {}); // Assert expect(response.typeMismatch).toBeTruthy(); @@ -390,7 +408,7 @@ describe("Check", () => { it("Returns truthy CheckerResponse when ASTs match", () => { // Act - const response: CheckerResponse = check(ast, ast); + const response: CheckerResponse = check(ast, ast, {}); // Assert expect(response).toEqual(trueResponse);