Skip to content

Commit

Permalink
convert operators tests to vitest (#252)
Browse files Browse the repository at this point in the history
  • Loading branch information
dqnykamp authored Nov 1, 2024
1 parent 50dc57b commit 605bb26
Show file tree
Hide file tree
Showing 9 changed files with 3,741 additions and 5,911 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class Xor extends BooleanBaseOperator {
static componentType = "xor";

static applyBooleanOperator(values) {
let numberTrues = values.reduce((acc, curr) => acc + curr, 0);
let numberTrues = values.reduce((acc, curr) => acc + (curr ? 1 : 0), 0);
return numberTrues === 1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ export class IsBetween extends BooleanBaseOperatorOfMath {
let lim1 = dependencyValues.limits[0];
let lim2 = dependencyValues.limits[1];

if (lim1 < lim2) {
let strict = dependencyValues.strict;

if (lim1 < lim2 || (!strict && lim1 === lim2)) {
lowerLimit = lim1;
upperLimit = lim2;
} else if (lim2 < lim1) {
Expand All @@ -122,8 +124,6 @@ export class IsBetween extends BooleanBaseOperatorOfMath {
return { setValue: { booleanOperator: () => false } };
}

let strict = dependencyValues.strict;

return {
setValue: {
booleanOperator: function (values) {
Expand Down
65 changes: 65 additions & 0 deletions packages/doenetml-worker/src/components/Function.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
returnNVariables,
roundForDisplay,
mergeListsWithOtherContainers,
superSubscriptsToUnicode,
} from "../utils/math";

export default class Function extends InlineComponent {
Expand Down Expand Up @@ -2772,6 +2773,70 @@ export default class Function extends InlineComponent {
},
};

stateVariableDefinitions.text = {
public: true,
shadowingInstructions: {
createComponentOfType: "text",
},
returnDependencies: () => ({
functionChild: {
dependencyType: "child",
childGroups: ["functions"],
variableNames: ["text"],
},
formula: {
dependencyType: "stateVariable",
variableName: "formula",
},
displayDigits: {
dependencyType: "stateVariable",
variableName: "displayDigits",
},
displayDecimals: {
dependencyType: "stateVariable",
variableName: "displayDecimals",
},
displaySmallAsZero: {
dependencyType: "stateVariable",
variableName: "displaySmallAsZero",
},
padZeros: {
dependencyType: "stateVariable",
variableName: "padZeros",
},
}),
definition: function ({ dependencyValues }) {
if (
dependencyValues.functionChild?.[0]?.componentType ===
"piecewiseFunction"
) {
// Note: A temporary solution until we can capture a piecewise function in formula (a math-expression).
// This solution is not perfect as it ignores any display attributes
// from the outer function.
return {
setValue: {
text: dependencyValues.functionChild[0].stateValues
.text,
},
};
}
let params = {};
if (dependencyValues.padZeros) {
if (Number.isFinite(dependencyValues.displayDecimals)) {
params.padToDecimals = dependencyValues.displayDecimals;
}
if (dependencyValues.displayDigits >= 1) {
params.padToDigits = dependencyValues.displayDigits;
}
}
let text = roundForDisplay({
value: dependencyValues.formula,
dependencyValues,
}).toString(params);
return { setValue: { text: superSubscriptsToUnicode(text) } };
},
};

stateVariableDefinitions.functionChildrenInfoToCalculateExtrema = {
returnDependencies: () => ({
functionChildren: {
Expand Down
264 changes: 264 additions & 0 deletions packages/doenetml-worker/src/test/tagSpecific/booleanoperators.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
import { describe, expect, it, vi } from "vitest";
import { createTestCore, returnAllStateVariables } from "../utils/test-core";
import {
updateBooleanInputValue,
updateMathInputValue,
} from "../utils/actions";

const Mock = vi.fn();
vi.stubGlobal("postMessage", Mock);

describe("Boolean Operator tag tests", async () => {
it("not", async () => {
let core = await createTestCore({
doenetML: `
<booleanInput name="bi" />
<not name="op1">$bi{name="bv"}</not>
<not name="op2">true</not>
<not name="op3">false</not>
`,
});

let stateVariables = await returnAllStateVariables(core);
expect(stateVariables["/bi"].stateValues.value).eq(false);
expect(stateVariables["/bv"].stateValues.value).eq(false);
expect(stateVariables["/op1"].stateValues.value).eq(true);
expect(stateVariables["/op2"].stateValues.value).eq(false);
expect(stateVariables["/op3"].stateValues.value).eq(true);

await updateBooleanInputValue({
boolean: true,
componentName: "/bi",
core,
});
stateVariables = await returnAllStateVariables(core);
expect(stateVariables["/bi"].stateValues.value).eq(true);
expect(stateVariables["/bv"].stateValues.value).eq(true);
expect(stateVariables["/op1"].stateValues.value).eq(false);
});

it("not when", async () => {
let core = await createTestCore({
doenetML: `
<mathInput name="mi" />
<not name="op"><when>$mi{name="mv"} > 1</when></not>
`,
});

let stateVariables = await returnAllStateVariables(core);
expect(stateVariables["/mi"].stateValues.value.tree).eq("\uff3f");
expect(stateVariables["/mv"].stateValues.value.tree).eq("\uff3f");
expect(stateVariables["/op"].stateValues.value).eq(true);

await updateMathInputValue({ latex: "2", componentName: "/mi", core });

stateVariables = await returnAllStateVariables(core);
expect(stateVariables["/mi"].stateValues.value.tree).eq(2);
expect(stateVariables["/mv"].stateValues.value.tree).eq(2);
expect(stateVariables["/op"].stateValues.value).eq(false);

await updateMathInputValue({ latex: "1", componentName: "/mi", core });
stateVariables = await returnAllStateVariables(core);
expect(stateVariables["/mi"].stateValues.value.tree).eq(1);
expect(stateVariables["/mv"].stateValues.value.tree).eq(1);
expect(stateVariables["/op"].stateValues.value).eq(true);
});

async function test_three_operators(
core: any,
operator: (args: boolean[]) => boolean,
) {
async function check_items(booleans: boolean[]) {
const stateVariables = await returnAllStateVariables(core);
expect(stateVariables["/bi1"].stateValues.value).eq(booleans[0]);
expect(stateVariables["/bi2"].stateValues.value).eq(booleans[1]);
expect(stateVariables["/bi3"].stateValues.value).eq(booleans[2]);
expect(stateVariables["/bv1"].stateValues.value).eq(booleans[0]);
expect(stateVariables["/bv2"].stateValues.value).eq(booleans[1]);
expect(stateVariables["/bv3"].stateValues.value).eq(booleans[2]);
expect(stateVariables["/op1"].stateValues.value).eq(
operator(booleans),
);
expect(stateVariables["/op2"].stateValues.value).eq(
operator([...booleans, true]),
);
expect(stateVariables["/op3"].stateValues.value).eq(
operator([...booleans, false]),
);
}

let booleans = [false, false, false];

await check_items(booleans);

booleans[0] = true;
await updateBooleanInputValue({
boolean: booleans[0],
componentName: "/bi1",
core,
});
await check_items(booleans);

booleans[1] = true;
await updateBooleanInputValue({
boolean: booleans[1],
componentName: "/bi2",
core,
});
await check_items(booleans);

booleans[2] = true;
await updateBooleanInputValue({
boolean: booleans[2],
componentName: "/bi3",
core,
});
await check_items(booleans);
}

it("and", async () => {
let core = await createTestCore({
doenetML: `
<booleanInput name="bi1" />
<booleanInput name="bi2" />
<booleanInput name="bi3" />
<and name="op1">
$bi1
$bi2
$bi3
</and>
<and name="op2">
$bi1
$bi2
$bi3
true
</and>
<and name="op3">
$bi1
$bi2
$bi3
false
</and>
<p>
$bi1{name="bv1"}
$bi2{name="bv2"}
$bi3{name="bv3"}
</p>
`,
});

let andOperator = function (booleans: boolean[]) {
return booleans.reduce((a, c) => a && c, true);
};

await test_three_operators(core, andOperator);
});

it("or", async () => {
let core = await createTestCore({
doenetML: `
<booleanInput name="bi1" />
<booleanInput name="bi2" />
<booleanInput name="bi3" />
<or name="op1">
$bi1
$bi2
$bi3
</or>
<or name="op2">
$bi1
$bi2
$bi3
true
</or>
<or name="op3">
$bi1
$bi2
$bi3
false
</or>
<p>
$bi1{name="bv1"}
$bi2{name="bv2"}
$bi3{name="bv3"}
</p>
`,
});

let orOperator = function (booleans: boolean[]) {
return booleans.reduce((a, c) => a || c, false);
};

await test_three_operators(core, orOperator);
});

it("xor", async () => {
let core = await createTestCore({
doenetML: `
<booleanInput name="bi1" />
<booleanInput name="bi2" />
<booleanInput name="bi3" />
<xor name="op1">
$bi1
$bi2
$bi3
</xor>
<xor name="op2">
$bi1
$bi2
$bi3
true
</xor>
<xor name="op3">
$bi1
$bi2
$bi3
false
</xor>
<p>
$bi1{name="bv1"}
$bi2{name="bv2"}
$bi3{name="bv3"}
</p>
`,
});

let xorOperator = function (booleans: boolean[]) {
let numberTrues = booleans.reduce(
(acc, curr) => acc + (curr ? 1 : 0),
0,
);
return numberTrues === 1;
};

await test_three_operators(core, xorOperator);
});

it("show point based on logic", async () => {
let core = await createTestCore({
doenetML: `
<booleanInput name="bi">
<label>show point</label>
</booleanInput>
<graph>
<point hide="not $bi" name="P">
(1,2)
</point>
</graph>
`,
});

let stateVariables = await returnAllStateVariables(core);
expect(stateVariables["/bi"].stateValues.value).eq(false);
expect(stateVariables["/P"].stateValues.hide).eq(true);

await updateBooleanInputValue({
boolean: true,
componentName: "/bi",
core,
});
stateVariables = await returnAllStateVariables(core);
expect(stateVariables["/bi"].stateValues.value).eq(true);
expect(stateVariables["/P"].stateValues.hide).eq(false);
});
});
Loading

0 comments on commit 605bb26

Please sign in to comment.