"use strict"; const expect = require("chai").expect; const dm = require("../src"); /* FIXME: Slot rule testing */ /* FIXME: Function guard signature matching */ let GitSource = dm.createTrait("GitSource", { stringify: dm.function([], dm.string()) }); let GithubSource, CrytoGitSource, ExternalGitSource, sourceOne, sourceTwo, randomGitSource; describe("traits", () => { it("should allow valid trait implementations", () => { GithubSource = dm.createType("GithubSource", { username: dm.string(), repository: dm.string() }).implements(GitSource, { stringify: dm.guard([], dm.string(), function () { return `https://github.com/${this.username}/${this.repository}.git`; }) }); CrytoGitSource = dm.createType("CrytoGitSource", { username: dm.string(), repository: dm.string() }).implements(GitSource, { stringify: dm.guard([], dm.string(), function () { return `http://git.cryto.net/${this.username}/${this.repository}.git`; }) }); }); it("should produce working trait functionality", () => { sourceOne = GithubSource({ username: "joepie91", repository: "node-bhttp" }); expect(sourceOne.stringify()).to.equal("https://github.com/joepie91/node-bhttp.git"); sourceTwo = CrytoGitSource({ username: "joepie91", repository: "node-bhttp" }); expect(sourceTwo.stringify()).to.equal("http://git.cryto.net/joepie91/node-bhttp.git"); }); let guardedFunc = dm.guard([GitSource], dm.nothing(), function (source) { expect(source.stringify()).to.be.a("string"); }); it("should allow an instance of any type with the correct trait to be passed into a trait-guarded function", () => { guardedFunc(sourceOne); guardedFunc(sourceTwo); }); it("should reject an instance of a type that does not have the correct trait", () => { let SomeType = dm.createType("SomeType", { value: dm.string() }); let instance = SomeType({ value: "foo" }); expect(() => { guardedFunc(instance); }).to.throw("Expected object of a type with the GitSource trait, got an instance of SomeType instead"); }); it(" ... even if that type has an otherwise compatible-looking method", () => { let SomeOtherType = dm.createType("SomeOtherType", { value: dm.string(), stringify: dm.function([], dm.string()) }); let instance = SomeOtherType({ value: "foo", stringify: dm.guard([], dm.string(), function () { return "this is not a URL at all"; }) }); expect(() => { guardedFunc(instance); }).to.throw("Expected object of a type with the GitSource trait, got an instance of SomeOtherType instead"); }); it("should reject a trait implementation that does not meet the trait definition", () => { expect(() => { let InvalidType = dm.createType("InvalidType", { value: dm.string() }).implements(GitSource, { stringify: "this is not a function" }); }).to.throw("Expected a guarded function () → string, got a string instead"); }); it("should reject an empty trait implementation when the trait definition does not allow that", () => { expect(() => { let InvalidType = dm.createType("InvalidType", { value: dm.string() }).implements(GitSource, { }); }).to.throw("Value is required for property 'stringify'"); }); it("should allow for specifying slot rules", () => { ExternalGitSource = dm.createType("ExternalGitSource", { sourceName: dm.string() }).implements(GitSource, { stringify: dm.slot() }); }); it("should allow specifying a value for that slot", () => { randomGitSource = ExternalGitSource({ sourceName: "randomGit", stringify: dm.guard([], dm.string(), function () { return "https://randomgit.example.com/repo.git" }) }); }); it("should have produced a working slot value", () => { expect(randomGitSource.stringify()).to.equal("https://randomgit.example.com/repo.git"); }); it("should reject an invalid slot value in the instance", () => { expect(() => { ExternalGitSource({ sourceName: "randomGit", stringify: "foo" }); }).to.throw("Expected a guarded function () → string, got a string instead"); }); });