"use strict";

var assert = require("assert");
var referee = require("../referee");

function MyThing() {}
var myThing = new MyThing();
var otherThing = {};
function F() {}
F.prototype = myThing;
var specializedThing = new F();

describe("assert.hasPrototype", function() {
    it("should fail when object does not inherit from prototype", function() {
        assert.throws(
            function() {
                referee.assert.hasPrototype(otherThing, MyThing.prototype);
            },
            function(error) {
                assert.equal(error.code, "ERR_ASSERTION");
                assert.equal(
                    error.message,
                    "[assert.hasPrototype] Expected {  } to have [MyThing] {  } on its prototype chain"
                );
                assert.equal(error.name, "AssertionError");
                assert.equal(error.operator, "assert.hasPrototype");
                return true;
            }
        );
    });

    it("should fail when primitive does not inherit from prototype", function() {
        assert.throws(
            function() {
                referee.assert.hasPrototype(3, MyThing.prototype);
            },
            function(error) {
                assert.equal(error.code, "ERR_ASSERTION");
                assert.equal(
                    error.message,
                    "[assert.hasPrototype] Expected 3 to have [MyThing] {  } on its prototype chain"
                );
                assert.equal(error.name, "AssertionError");
                assert.equal(error.operator, "assert.hasPrototype");
                return true;
            }
        );
    });

    it("should fail with no arguments", function() {
        assert.throws(
            function() {
                referee.assert.hasPrototype();
            },
            function(error) {
                assert.equal(error.code, "ERR_ASSERTION");
                assert.equal(
                    error.message,
                    "[assert.hasPrototype] Expected to receive at least 2 argument(s)"
                );
                assert.equal(error.name, "AssertionError");
                return true;
            }
        );
    });

    it("should fail with only one object", function() {
        assert.throws(
            function() {
                referee.assert.hasPrototype({});
            },
            function(error) {
                assert.equal(error.code, "ERR_ASSERTION");
                assert.equal(
                    error.message,
                    "[assert.hasPrototype] Expected to receive at least 2 argument(s)"
                );
                assert.equal(error.name, "AssertionError");
                return true;
            }
        );
    });

    it("should pass when object has other object on prototype chain", function() {
        referee.assert.hasPrototype(myThing, MyThing.prototype);
    });

    it("should pass when object has other object as ancestor", function() {
        referee.assert.hasPrototype(specializedThing, MyThing.prototype);
    });

    it("should fail with custom message", function() {
        var message = "272bbe5f-e863-490b-9ed0-6af2e95b4b0e";

        assert.throws(
            function() {
                referee.assert.hasPrototype(
                    otherThing,
                    MyThing.prototype,
                    message
                );
            },
            function(error) {
                assert.equal(error.code, "ERR_ASSERTION");
                assert.equal(
                    error.message,
                    "[assert.hasPrototype] " +
                        message +
                        ": Expected {  } to have [MyThing] {  } on its prototype chain"
                );
                assert.equal(error.name, "AssertionError");
                assert.equal(error.operator, "assert.hasPrototype");
                return true;
            }
        );
    });
});

describe("refute.hasPrototype", function() {
    it("should fail with no arguments", function() {
        assert.throws(
            function() {
                referee.refute.hasPrototype();
            },
            function(error) {
                assert.equal(error.code, "ERR_ASSERTION");
                assert.equal(
                    error.message,
                    "[refute.hasPrototype] Expected to receive at least 2 argument(s)"
                );
                assert.equal(error.name, "AssertionError");
                return true;
            }
        );
    });

    it("should fail with only one object", function() {
        assert.throws(
            function() {
                referee.refute.hasPrototype({});
            },
            function(error) {
                assert.equal(error.code, "ERR_ASSERTION");
                assert.equal(
                    error.message,
                    "[refute.hasPrototype] Expected to receive at least 2 argument(s)"
                );
                assert.equal(error.name, "AssertionError");
                return true;
            }
        );
    });

    it("should fail when object inherits from prototype", function() {
        assert.throws(
            function() {
                referee.refute.hasPrototype(myThing, MyThing.prototype);
            },
            function(error) {
                assert.equal(error.code, "ERR_ASSERTION");
                assert.equal(
                    error.message,
                    "[refute.hasPrototype] Expected [MyThing] {  } not to have [MyThing] {  } on its prototype chain"
                );
                assert.equal(error.name, "AssertionError");
                assert.equal(error.operator, "refute.hasPrototype");
                return true;
            }
        );
    });

    it("should fail when object has prototype as ancestor", function() {
        assert.throws(
            function() {
                referee.refute.hasPrototype(
                    specializedThing,
                    MyThing.prototype
                );
            },
            function(error) {
                assert.equal(error.code, "ERR_ASSERTION");
                assert.equal(
                    error.message,
                    "[refute.hasPrototype] Expected [MyThing] {  } not to have [MyThing] {  } on its prototype chain"
                );
                assert.equal(error.name, "AssertionError");
                assert.equal(error.operator, "refute.hasPrototype");
                return true;
            }
        );
    });

    it("should pass when primitive does not inherit from prototype", function() {
        referee.refute.hasPrototype(3, MyThing);
    });

    it("should pass when object does not inherit", function() {
        referee.refute.hasPrototype(otherThing, MyThing);
    });

    it("should fail with custom message", function() {
        var message = "d4aea902-44f2-4ba1-a33e-503132f82eca";

        assert.throws(
            function() {
                referee.refute.hasPrototype(
                    specializedThing,
                    MyThing.prototype,
                    message
                );
            },
            function(error) {
                assert.equal(error.code, "ERR_ASSERTION");
                assert.equal(
                    error.message,
                    "[refute.hasPrototype] " +
                        message +
                        ": Expected [MyThing] {  } not to have [MyThing] {  } on its prototype chain"
                );
                assert.equal(error.name, "AssertionError");
                assert.equal(error.operator, "refute.hasPrototype");
                return true;
            }
        );
    });
});
