"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 ''"); }); 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"); }); });