You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

125 lines
3.4 KiB
JavaScript

"use strict";
const expect = require("chai").expect;
const dm = require("../src");
describe("function guards", () => {
it("should accept a correctly-behaving function", () => {
let guardedFunction = dm.guard([dm.string(), dm.number()], dm.boolean(), function (str, num) {
expect(str).to.equal("hello world");
expect(num).to.equal(42);
return true;
});
guardedFunction("hello world", 42);
});
it("should throw on an invalid return value type", () => {
let guardedFunction = dm.guard([dm.string(), dm.number()], dm.boolean(), function (str, num) {
return "not a boolean";
});
expect(() => {
guardedFunction("hello world", 42);
}).to.throw("Expected a boolean, got a string instead");
});
it("should throw on an invalid argument type", () => {
let guardedFunction = dm.guard([dm.string(), dm.number()], dm.boolean(), function (str, num) {
return true;
});
expect(() => {
guardedFunction(false, 42);
}).to.throw("Expected a string, got a boolean instead");
});
it("should throw on a missing argument", () => {
let guardedFunction = dm.guard([dm.string(), dm.number()], dm.boolean(), function (str, num) {
return true;
});
expect(() => {
guardedFunction("hello world");
}).to.throw("Value is required for property '<unknown>'");
});
it(" ... but not when that argument is optional", () => {
let guardedFunction = dm.guard([dm.string(), dm.number().optional()], dm.boolean(), function (str, num) {
expect(str).to.equal("hello world");
expect(num).to.equal(null);
return true;
});
guardedFunction("hello world");
});
it("should correctly handle defaults", () => {
let guardedFunction = dm.guard([dm.string(), dm.number().default(42)], dm.boolean(), function (str, num) {
expect(str).to.equal("hello world");
expect(num).to.equal(42);
return true;
});
guardedFunction("hello world");
});
let SomeType = dm.createType("SomeType", {
value: dm.string()
});
let guardedTypeFunction = dm.guard([SomeType], dm.nothing(), function (instance) {
expect(instance.value).to.equal("foo");
});
it("should allow correct instances for a type rule", () => {
guardedTypeFunction(SomeType({
value: "foo"
}));
});
it("should reject other values for that rule", () => {
expect(() => {
guardedTypeFunction("hello world");
}).to.throw("Expected an instance of SomeType, got a string instead");
});
let SomeTraitType = dm.createType("SomeTraitType", {
value: dm.string()
});
let SomeTrait = dm.createTrait("SomeTrait", {
traitValue: dm.string()
});
SomeTraitType.implements(SomeTrait, {
traitValue: "SomeTraitType"
});
let guardedTraitFunction = dm.guard([SomeTrait], dm.nothing(), function (instance) {
expect(instance.value).to.equal("foo");
expect(instance.traitValue).to.equal("SomeTraitType");
});
it("should allow correct instances for a trait rule", () => {
guardedTraitFunction(SomeTraitType({
value: "foo"
}));
});
it ("should reject instances that do not have the trait", () => {
expect(() => {
guardedTraitFunction(SomeType({
value: "foo"
}));
}).to.throw("Expected object of a type with the SomeTrait trait, got an instance of SomeType instead");
});
it("should reject other values for that rule", () => {
expect(() => {
guardedTraitFunction("hello world");
}).to.throw("Expected object of a type with the SomeTrait trait, got a string instead");
});
});