cc733b08 |
import * as uut from "./genfuns";
import { fail } from "assert";
describe("matches_specializer", () => {
test("works in expected cases", () => {
function AThing() {}
const an_instance = new AThing();
expect(uut.matches_specializer(an_instance, AThing)).toBeTruthy();
expect(uut.matches_specializer(an_instance, String)).toBeFalsy();
expect(uut.matches_specializer(an_instance, Object)).toBeTruthy();
expect(uut.matches_specializer([], Array)).toBeTruthy();
expect(uut.matches_specializer([], Object)).toBeTruthy();
expect(uut.matches_specializer([], Number)).toBeFalsy();
function Foo() {}
Foo.prototype = Object.create(null);
const inst = new Foo();
expect(uut.matches_specializer(inst, Foo)).toBeTruthy();
expect(uut.matches_specializer(inst, Object)).toBeFalsy();
expect(uut.matches_specializer({ a: 1 }, uut.Shape("a"))).toBeTruthy();
expect(
uut.matches_specializer({ a: 1, b: 2 }, uut.Shape("a"))
).toBeTruthy();
expect(uut.matches_specializer({ b: 2 }, uut.Shape("a"))).toBeFalsy();
expect(
uut.matches_specializer({ a: 1, b: 2, c: 3 }, uut.Shape("a", "b", "c"))
).toBeTruthy();
expect(
uut.matches_specializer(
{ a: 1, b: 2, c: 3, d: 4 },
uut.Shape("a", "b", "c")
)
).toBeTruthy();
expect(
uut.matches_specializer({ a: 1, c: 3 }, uut.Shape("a", "b", "c"))
).toBeFalsy();
expect(
uut.matches_specializer({ c: 3 }, uut.Shape("a", "b", "c"))
).toBeFalsy();
expect(
uut.matches_specializer({ d: 3 }, uut.Shape("a", "b", "c"))
).toBeFalsy();
});
test("null behavior", () => {
expect(uut.matches_specializer(null, null)).toBeTruthy();
expect(uut.matches_specializer(null, Number)).toBeFalsy();
expect(uut.matches_specializer(null, String)).toBeFalsy();
expect(uut.matches_specializer(null, Object)).toBeFalsy();
});
test("undefined (the value) behavior", () => {
expect(uut.matches_specializer(undefined, undefined)).toBeTruthy();
expect(uut.matches_specializer(undefined, Number)).toBeFalsy();
expect(uut.matches_specializer(undefined, String)).toBeFalsy();
expect(uut.matches_specializer(undefined, Object)).toBeFalsy();
});
test("works for numbers", () => {
expect(uut.matches_specializer(new Number(1), Number)).toBeTruthy();
expect(uut.matches_specializer(new Number(1), Object)).toBeTruthy();
expect(uut.matches_specializer(new Number(1), String)).toBeFalsy();
expect(uut.matches_specializer(1, Number)).toBeTruthy();
expect(uut.matches_specializer(1, Object)).toBeTruthy();
expect(uut.matches_specializer(1, String)).toBeFalsy();
});
test("handles strings", () => {
expect(uut.matches_specializer(new String("foobar"), String)).toBeTruthy();
expect(uut.matches_specializer(new String("foobar"), Object)).toBeTruthy();
expect(uut.matches_specializer("1", String)).toBeTruthy();
expect(uut.matches_specializer("1", Object)).toBeTruthy();
expect(uut.matches_specializer("1", Number)).toBeFalsy();
});
|
cc733b08 |
describe("defgeneric", () => {
test("methods get called appropriately", () => {
expect(
uut
.defgeneric("testing1", "a", "b")
.primary([Object, Object], (_, __) => 1)
.fn(1, 2)
).toEqual(1);
try {
uut
.defgeneric("foobar", "a")
.primary([String], function (a) {})
.fn({});
fail();
} catch (err) {
expect(err).toBeInstanceOf(uut.NoApplicableMethodError);
}
expect(
uut
.defgeneric("testing1", "a", "b")
.primary([Number, Number], (_, __) => 1)
.fn(1, 2)
).toEqual(1);
expect(
uut
.defgeneric("testing1", "a", "b")
.primary([Number, Number], (_, __) => 2)
.primary([String, String], (_, __) => 1)
.fn("1", "2")
).toEqual(1);
let firstCounts = 0;
expect(
uut
.defgeneric("testing1", "a", "b")
.primary([Number, Number], (_, __) => (firstCounts += 1))
.primary([String, String], (_, __) => (firstCounts += 1))
.fn("1", "2")
).toEqual(1);
expect(firstCounts).toEqual(1);
let secondCounts = 0;
expect(
uut
.defgeneric("testing1", "a", "b")
.primary([Object, Object], (_, __) => (secondCounts += 1))
.primary([String, String], (_, __) => (secondCounts += 1))
.fn("1", "2")
).toEqual(1);
expect(secondCounts).toEqual(1);
let thirdCounts = 0;
expect(
uut
.defgeneric("testing1", "a", "b")
.before([Object, Object], (_, __) => (thirdCounts += 1))
.primary([String, String], (_, __) => "hi")
.after([Object, String], (_, __) => (thirdCounts += 1))
.fn("1", "2")
).toEqual("hi");
expect(thirdCounts).toEqual(2);
expect(
uut
.defgeneric("foobar", "a")
.primary([Object], function (a) {
return 1;
})
.primary([String], function (a) {
return 2;
})
.fn("foobar")
).toEqual(2);
});
test("next-method-p works", () => {
expect.assertions(3);
uut
.defgeneric("foobar", "a")
.primary([Object], function (a) {
expect(this.next_method_p).toBe(false);
})
.fn({});
uut
.defgeneric("foobar", "a")
.primary([Object], function (a) {
expect(this.next_method_p).toBe(false);
})
.primary([String], function (a) {
expect(this.next_method_p).toBe(true);
})
.fn("foobar");
uut
.defgeneric("foobar", "a")
.primary([Object], function (a) {
expect(this.next_method_p).toBe(false);
})
.primary([String], function (a) {
expect(this.next_method_p).toBe(true);
})
.fn(1);
});
test("call-next-method works", () => {
try {
uut
.defgeneric("foobar", "a")
.primary([Object], function (a) {
this.call_next_method();
})
.primary([String], function (a) {
return 1;
})
.fn({});
fail();
} catch (err) {
expect(err).toBeInstanceOf(uut.NoNextMethodError);
}
expect(
uut
.defgeneric("foobar", "a")
.primary([Object], function (a) {
return 1;
})
.primary([String], function (a) {
return this.call_next_method();
})
.fn("foobar")
).toEqual(1);
expect(
uut
.defgeneric("foobar", "a", "b")
.primary([String, String], function (a, b) {
return `1${this.call_next_method()}`;
})
.primary([Object, String], function (a, b) {
return `3${this.call_next_method()}`;
})
.primary([String, Object], function (a, b) {
return `2${this.call_next_method()}`;
})
.primary([Object, Object], function (a, b) {
return `4`;
})
.fn("a", "b")
).toEqual("1234");
try {
uut
.defgeneric("foobar", "a")
.primary([Object], function (a) {
this.call_next_method();
})
.fn({});
fail();
} catch (err) {
expect(err).toBeInstanceOf(uut.NoNextMethodError);
}
});
|
cc733b08 |
describe("custom specializers", () => {
test("Shape works", () => {
expect(
uut
.defgeneric("foobar", "a")
.primary([uut.Shape("a", "b")], ({ a, b }) => a + b)
.primary([Object], _ => null)
.fn({ a: 1, b: 2 })
).toEqual(3);
expect(
uut
.defgeneric("foobar", "a")
.primary([uut.Shape("a", "b")], ({ a, b }) => a + b)
.primary([Object], _ => null)
.fn({ a: 1, b: 2, c: 3 })
).toEqual(3);
expect(
uut
.defgeneric("foobar", "a")
.primary([uut.Shape("a", "b")], ({ a, b }) => a + b)
.primary([Object], _ => null)
.fn({ a: 1 })
).toEqual(null);
expect(
uut
.defgeneric("foobar", "a")
.primary([uut.Shape(["a", 1], "b")], ({ a, b }) => a + b)
.primary([Object], _ => null)
.fn({ a: 1, b: 3 })
).toEqual(4);
expect(
uut
.defgeneric("foobar", "a")
.primary([uut.Shape(["a", null], "b")], ({ a, b }) => b)
.primary([Object], _ => null)
.fn({ a: null, b: 3 })
).toEqual(3);
expect(
uut
.defgeneric("foobar", "a")
.primary([uut.Shape(["a", undefined], "b")], ({ a, b }) => b)
.primary([Object], _ => null)
.fn({ b: 5 })
).toEqual(null); //undefined is not a permissible default: treated as if the key is missing
expect(
uut
.defgeneric("foobar", "a")
.primary([uut.Shape(["a", 1], "b")], ({ a, b }) => a + b)
.primary([Object], _ => null)
.fn({ a: 2, b: 3 })
).toEqual(null);
});
test("Shape, prototype precedence", () => {
expect(
uut
.defgeneric("foobar4", "a")
.primary([uut.Shape("a")], ({ a }) => a)
.primary([uut.Shape("a", "b")], ({ a, b }) => {
return a + b;
})
.primary([Object], _ => null)
.fn({ a: 1, b: 3 })
).toEqual(4);
expect(
uut
.defgeneric("foobar", "a")
.primary([uut.Shape("a", "b")], ({ a, b }) => a + b)
.primary([uut.Shape("b")], ({ b }) => b)
.primary([Object], _ => null)
.fn({ a: 1, b: 2 })
).toEqual(3);
const Foo = function () {};
Foo.prototype = { a: true, b: null };
expect(
uut
.defgeneric("foobar", "a")
.primary([uut.Shape("a")], function ({ a }) {
return `a${this.call_next_method()}`;
})
.primary([uut.Shape("a", "b", "c")], function ({ a, b, c }) {
return `c${this.call_next_method()}`;
})
.primary([uut.Shape("a", "b")], function ({ a, b }) {
return `b${this.call_next_method()}`;
})
.primary([Object], _ => "d")
.fn(Object.assign(new Foo(), { c: 3 }))
).toEqual("cbad");
});
|