406b5587 |
import * as uut from './genfuns';
|
636eaffe |
import { fail } from 'assert';
|
94944213 |
|
406b5587 |
describe('matches_specializer', () => {
|
94944213 |
test('works in expected cases', () => {
|
406b5587 |
function AThing() { }
const an_instance = new AThing();
|
94944213 |
|
406b5587 |
expect(uut.matches_specializer(an_instance, AThing)).toBeTruthy();
expect(uut.matches_specializer(an_instance, String)).toBeFalsy();
expect(uut.matches_specializer(an_instance, Object)).toBeTruthy();
|
94944213 |
|
406b5587 |
expect(uut.matches_specializer([], Array)).toBeTruthy();
expect(uut.matches_specializer([], Object)).toBeTruthy();
expect(uut.matches_specializer([], Number)).toBeFalsy();
|
94944213 |
|
5c93a70c |
function Foo() { }
|
94944213 |
Foo.prototype = Object.create(null);
const inst = new Foo();
|
406b5587 |
expect(uut.matches_specializer(inst, Foo)).toBeTruthy();
expect(uut.matches_specializer(inst, Object)).toBeFalsy();
|
5c93a70c |
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();
|
406b5587 |
|
5c93a70c |
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();
|
94944213 |
});
|
406b5587 |
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();
});
|
94944213 |
|
406b5587 |
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();
});
|
94944213 |
|
406b5587 |
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();
|
94944213 |
|
406b5587 |
expect(uut.matches_specializer(1, Number)).toBeTruthy();
expect(uut.matches_specializer(1, Object)).toBeTruthy();
expect(uut.matches_specializer(1, String)).toBeFalsy();
|
94944213 |
});
|
406b5587 |
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();
})
|
94944213 |
});
describe('defgeneric', () => {
test('methods get called appropriately', () => {
expect(
uut.defgeneric("testing1", "a", "b")
.primary([Object, Object], (_, __) => 1)
|
5c93a70c |
.fn(1, 2)
|
94944213 |
).toEqual(1);
|
636eaffe |
try {
|
406b5587 |
uut.defgeneric("foobar", "a")
|
636eaffe |
.primary([String], function (a) { })
.fn({});
fail();
} catch (err) {
expect(err).toBeInstanceOf(uut.NoApplicableMethodError);
}
|
406b5587 |
|
94944213 |
expect(
uut.defgeneric("testing1", "a", "b")
.primary([Number, Number], (_, __) => 1)
|
5c93a70c |
.fn(1, 2)
|
94944213 |
).toEqual(1);
expect(
uut.defgeneric("testing1", "a", "b")
.primary([Number, Number], (_, __) => 2)
.primary([String, String], (_, __) => 1)
|
5c93a70c |
.fn("1", "2")
|
94944213 |
).toEqual(1);
let firstCounts = 0;
expect(
uut.defgeneric("testing1", "a", "b")
.primary([Number, Number], (_, __) => firstCounts += 1)
.primary([String, String], (_, __) => firstCounts += 1)
|
5c93a70c |
.fn("1", "2")
|
94944213 |
).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)
|
5c93a70c |
.fn("1", "2")
|
94944213 |
).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)
|
5c93a70c |
.fn("1", "2")
|
94944213 |
).toEqual('hi');
expect(thirdCounts).toEqual(2);
|
406b5587 |
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', () => {
|
636eaffe |
try {
|
406b5587 |
uut.defgeneric("foobar", "a")
.primary([Object], function (a) {
this.call_next_method();
})
.primary([String], function (a) {
return 1;
})
|
636eaffe |
.fn({})
fail();
} catch (err) {
expect(err).toBeInstanceOf(uut.NoNextMethodError);
}
|
406b5587 |
expect(
uut.defgeneric("foobar", "a")
.primary([Object], function (a) {
return 1;
})
.primary([String], function (a) {
return this.call_next_method();
})
.fn("foobar")
).toEqual(1);
|
5c93a70c |
|
406b5587 |
expect(
uut.defgeneric("foobar", "a", "b")
|
5c93a70c |
.primary([String, String], function (a, b) {
|
406b5587 |
return `1${this.call_next_method()}`;
})
|
5c93a70c |
.primary([Object, String], function (a, b) {
|
406b5587 |
return `3${this.call_next_method()}`;
})
|
5c93a70c |
.primary([String, Object], function (a, b) {
|
406b5587 |
return `2${this.call_next_method()}`;
})
|
5c93a70c |
.primary([Object, Object], function (a, b) {
|
406b5587 |
return `4`;
}).fn("a", "b")
).toEqual("1234");
|
636eaffe |
try {
uut.defgeneric("foobar", "a")
.primary([Object], function (a) {
this.call_next_method();
})
.fn({});
fail();
} catch (err) {
expect(err).toBeInstanceOf(uut.NoNextMethodError);
}
|
406b5587 |
});
});
describe('custom specializers', () => {
test('Shape works', () => {
expect(uut.defgeneric("foobar", "a")
|
5c93a70c |
.primary([uut.Shape('a', 'b')], ({ a, b }) => a + b)
.primary([Object], _ => null)
.fn({ a: 1, b: 2 }))
|
406b5587 |
.toEqual(3);
expect(uut.defgeneric("foobar", "a")
|
5c93a70c |
.primary([uut.Shape('a', 'b')], ({ a, b }) => a + b)
.primary([Object], _ => null)
.fn({ a: 1, b: 2, c: 3 }))
|
406b5587 |
.toEqual(3);
expect(uut.defgeneric("foobar", "a")
|
5c93a70c |
.primary([uut.Shape('a', 'b')], ({ a, b }) => a + b)
.primary([Object], _ => null)
.fn({ a: 1 }))
|
406b5587 |
.toEqual(null);
|
a00b5a50 |
expect(uut.defgeneric("foobar", "a")
|
5c93a70c |
.primary([uut.Shape(['a', 1], 'b')], ({ a, b }) => a + b)
.primary([Object], _ => null)
.fn({ a: 1, b: 3 }))
|
a00b5a50 |
.toEqual(4);
expect(uut.defgeneric("foobar", "a")
|
5c93a70c |
.primary([uut.Shape(['a', null], 'b')], ({ a, b }) => b)
.primary([Object], _ => null)
.fn({ a: null, b: 3 }))
|
a00b5a50 |
.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")
|
5c93a70c |
.primary([uut.Shape(['a', 1], 'b')], ({ a, b }) => a + b)
.primary([Object], _ => null)
.fn({ a: 2, b: 3 }))
|
a00b5a50 |
.toEqual(null);
|
406b5587 |
});
test('Shape, prototype precedence', () => {
expect(uut.defgeneric("foobar4", "a")
|
5c93a70c |
.primary([uut.Shape('a')], ({ a }) => a)
.primary([uut.Shape('a', 'b')], ({ a, b }) => { return a + b })
.primary([Object], _ => null).fn({ a: 1, b: 3 }))
|
406b5587 |
.toEqual(4);
expect(uut.defgeneric("foobar", "a")
|
5c93a70c |
.primary([uut.Shape('a', 'b')], ({ a, b }) => a + b)
.primary([uut.Shape('b')], ({ b }) => b)
.primary([Object], _ => null)
.fn({ a: 1, b: 2 }))
|
406b5587 |
.toEqual(3);
|
5c93a70c |
const Foo = function () { }
Foo.prototype = { a: true, b: null };
|
406b5587 |
expect(uut.defgeneric("foobar", "a")
|
5c93a70c |
.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 })))
|
a00b5a50 |
.toEqual('cbad');
|
406b5587 |
});
});
|
94944213 |
|
406b5587 |
describe("Shape", () => {
test('super_of', () => {
expect(uut.Shape().super_of(uut.Shape("a", "b", "c"))).toBeTruthy();
expect(uut.Shape('a').super_of(uut.Shape('a', 'b'))).toBeTruthy();
expect(uut.Shape("a", "b").super_of(uut.Shape("a", "b", "c"))).toBeTruthy();
|
a00b5a50 |
expect(uut.Shape("a", "b").super_of(uut.Shape("a", "b", 3))).toBeTruthy();
|
406b5587 |
expect(uut.Shape("a", "b").super_of(uut.Shape("a", "b"))).toBeFalsy();
expect(uut.Shape("a", "b").super_of(uut.Shape("a"))).toBeFalsy();
|
94944213 |
});
|
636eaffe |
});
|