Skip to content

Commit

Permalink
Remove Interpreter.case() unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bartblast committed Nov 7, 2024
1 parent 6f76c24 commit c904662
Show file tree
Hide file tree
Showing 2 changed files with 3 additions and 308 deletions.
4 changes: 3 additions & 1 deletion assets/js/interpreter.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,9 @@ export default class Interpreter {

return moduleRef[functionArityStr](...args.data);
}

// case() has no unit tests in interpreter_test.mjs, only feature tests in test/features/test/special_forms/case_test.exs
// Unit test maintenance in interpreter_test.mjs would be problematic because tests would need to be updated
// each time Hologram.Compiler.Encoder's implementation changes.
static case(condition, clauses, context) {
let conditionContext;

Expand Down
307 changes: 0 additions & 307 deletions test/javascript/interpreter_test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -659,313 +659,6 @@ describe("Interpreter", () => {
});
});

describe("case()", () => {
let context;

beforeEach(() => {
context = contextFixture({
vars: {a: Type.integer(5), b: Type.integer(6), x: Type.integer(9)},
});
});

it("returns the result of the first matching clause's block (and ignores non-matching clauses)", () => {
// case 2 do
// 1 -> :expr_1
// 2 -> :expr_2
// 3 -> :expr_3
// end

const clause1 = {
match: Type.integer(1),
guards: [],
body: (_context) => {
return Type.atom("expr_1");
},
};

const clause2 = {
match: Type.integer(2),
guards: [],
body: (_context) => {
return Type.atom("expr_2");
},
};

const clause3 = {
match: Type.integer(3),
guards: [],
body: (_context) => {
return Type.atom("expr_3");
},
};

const result = Interpreter.case(
Type.integer(2),
[clause1, clause2, clause3],
context,
);

assert.deepStrictEqual(result, Type.atom("expr_2"));
});

it("runs guards for each tried clause", () => {
// case 2 do
// x when x == 1 -> :expr_1
// y when y == 2 -> :expr_2
// z when z == 3 -> :expr_3
// end
//
// case 2 do
// x when :erlang.==(x, 1) -> :expr_1
// y when :erlang.==(y, 2) -> :expr_2
// z when :erlang.==(z, 3) -> :expr_3
// end

const clause1 = {
match: Type.variablePattern("x"),
guards: [(context) => Erlang["==/2"](context.vars.x, Type.integer(1))],
body: (_context) => {
return Type.atom("expr_1");
},
};

const clause2 = {
match: Type.variablePattern("y"),
guards: [(context) => Erlang["==/2"](context.vars.y, Type.integer(2))],
body: (_context) => {
return Type.atom("expr_2");
},
};

const clause3 = {
match: Type.variablePattern("z"),
guards: [(context) => Erlang["==/2"](context.vars.z, Type.integer(3))],
body: (_context) => {
return Type.atom("expr_3");
},
};

const result = Interpreter.case(
Type.integer(2),
[clause1, clause2, clause3],
context,
);

assert.deepStrictEqual(result, Type.atom("expr_2"));
});

it("clause with multiple guards", () => {
// case my_var do
// x when x == 1 when x == 11 -> :expr_1
// y when y == 2 when y == 22 -> :expr_2
// z when z == 3 when z == 33 -> :expr_3
// end
//
// case my_var do
// x when :erlang.==(x, 1) when :erlang.==(x, 11) -> :expr_1
// y when :erlang.==(y, 2) when :erlang.==(y, 22) -> :expr_2
// z when :erlang.==(z, 3) when :erlang.==(z, 33) -> :expr_3
// end

const clause1 = {
match: Type.variablePattern("x"),
guards: [
(context) => Erlang["==/2"](context.vars.x, Type.integer(1)),
(context) => Erlang["==/2"](context.vars.x, Type.integer(11)),
],
body: (_context) => {
return Type.atom("expr_1");
},
};

const clause2 = {
match: Type.variablePattern("y"),
guards: [
(context) => Erlang["==/2"](context.vars.y, Type.integer(2)),
(context) => Erlang["==/2"](context.vars.y, Type.integer(22)),
],
body: (_context) => {
return Type.atom("expr_2");
},
};

const clause3 = {
match: Type.variablePattern("z"),
guards: [
(context) => Erlang["==/2"](context.vars.z, Type.integer(3)),
(context) => Erlang["==/2"](context.vars.z, Type.integer(33)),
],
body: (_context) => {
return Type.atom("expr_3");
},
};

const context = contextFixture({vars: {my_var: Type.integer(22)}});

const result = Interpreter.case(
context.vars.my_var,
[clause1, clause2, clause3],
context,
);

assert.deepStrictEqual(result, Type.atom("expr_2"));
});

it("clones vars for each clause and has access to vars from closure", () => {
// x = 9
//
// case 2 do
// x when x == 1 -> :expr_1
// y -> x
// end

const clause1 = {
match: Type.variablePattern("x"),
guards: [(context) => Erlang["==/2"](context.vars.x, Type.integer(1))],
body: (_context) => {
return Type.atom("expr_1");
},
};

const clause2 = {
match: Type.variablePattern("y"),
guards: [],
body: (context) => {
return context.vars.x;
},
};

const result = Interpreter.case(
Type.integer(2),
[clause1, clause2],
context,
);

assert.deepStrictEqual(result, Type.integer(9));
});

it("raises CaseClauseError error if none of the clauses is matched", () => {
// case 3 do
// 1 -> :expr_1
// 2 -> :expr_2
// end

const clause1 = {
match: Type.integer(1),
guards: [],
body: (_context) => {
return Type.atom("expr_1");
},
};

const clause2 = {
match: Type.integer(2),
guards: [],
body: (_context) => {
return Type.atom("expr_2");
},
};

assertBoxedError(
() => Interpreter.case(Type.integer(3), [clause1, clause2], context),
"CaseClauseError",
"no case clause matching: 3",
);
});

it("errors raised inside case clause are not caught", () => {
const clause = {
match: Type.integer(1),
guards: [],
body: (_context) => Interpreter.raiseArgumentError("my message"),
};

assertBoxedError(
() => Interpreter.case(Type.integer(1), [clause], context),
"ArgumentError",
"my message",
);
});

it("mutliple-expression condition that is matched by one of the clauses", () => {
// case (1; 2) do
// 2 -> :ok
// end
const result = Interpreter.case(
(_context) => {
Type.integer(1);
return Type.integer(2);
},
[
{
match: Type.integer(2),
guards: [],
body: (_context) => {
return Type.atom("ok");
},
},
],
context,
);

assert.deepStrictEqual(result, Type.atom("ok"));
});

it("mutliple-expression condition that is not matched by any of the clauses", () => {
const condition = (_context) => {
Type.integer(1);
return Type.integer(2);
};

const clauses = [
{
match: Type.integer(1),
guards: [],
body: (_context) => {
return Type.atom("ok");
},
},
];

assertBoxedError(
// case (1; 2) do
// 1 -> :ok
// end
() => Interpreter.case(condition, clauses, context),
"CaseClauseError",
"no case clause matching: 2",
);
});

it("clauses have access to vars from condition", () => {
// (case x = 1; 2) do
// 2 -> x
// end
const result = Interpreter.case(
(context) => {
Interpreter.matchOperator(
Type.integer(1),
Type.variablePattern("x"),
context,
);
return Type.integer(2);
},
[
{
match: Type.integer(2),
guards: [],
body: (context) => {
return context.vars.x;
},
},
],
context,
);

assert.deepStrictEqual(result, Type.integer(1));
});
});

it("cloneContext()", () => {
const context = {
module: Type.atom("MyModule1"),
Expand Down

0 comments on commit c904662

Please sign in to comment.