"use strict";

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

describe("verifier", function() {
    var verify;

    beforeEach(function() {
        verify = referee.verifier();
    });

    it("should increment verify.count on pass", function() {
        var numberOfAssertions = 100;

        for (var i = 0; i < numberOfAssertions; i++) {
            referee.assert(true);
        }
        assert.equal(verify.count, numberOfAssertions);

        verify(numberOfAssertions);
    });

    it("should increment verify.count on failure", function() {
        var numberOfAssertions = 100;

        for (var i = 0; i < numberOfAssertions; i++) {
            try {
                referee.refute(true);
            } catch (ignore) {
                // Ignore exception
            }
        }
        assert.equal(verify.count, numberOfAssertions);

        verify(numberOfAssertions);
    });

    context("after call", function() {
        it("should not increment verify.count on assert", function() {
            referee.assert(true);

            verify();
            referee.assert(true);

            assert.equal(verify.count, 1);
        });

        it("should not increment verify.count on refute", function() {
            try {
                referee.refute(true);
            } catch (ignore) {
                // Ignore exception
            }

            verify();
            try {
                referee.refute(true);
            } catch (ignore) {
                // Ignore exception
            }

            assert.equal(verify.count, 1);
        });
    });

    context("when called with zero expected argument", function() {
        it("should throw an error", function() {
            var error;
            try {
                verify(0);
            } catch (err) {
                error = err;
            }

            assert.equal(
                error.message,
                "expected argument must be a number >= 1"
            );
        });
    });

    context("when called with non-number expected argument", function() {
        it("should throw an error", function() {
            var error;
            try {
                verify("12");
            } catch (err) {
                error = err;
            }

            assert.equal(
                error.message,
                "expected argument must be a number >= 1"
            );
        });
    });

    context("when no assertions have been made", function() {
        it("should throw an Error", function() {
            var error;
            try {
                verify();
            } catch (err) {
                error = err;
            }

            assert.equal(
                error.message,
                "Expected assertion count to be at least 1, but was 0"
            );
        });
    });

    context("when called without an expected value", function() {
        it("should not throw", function() {
            for (var i = 0; i < 1000; i++) {
                referee.assert(true);
                verify();
            }
        });
    });

    context("when called with an expected value", function() {
        context("when expected === verify.count", function() {
            it("should not throw", function() {
                var limit = 1000;
                for (var i = 0; i < limit; i++) {
                    referee.assert(true);
                }

                verify(limit);
            });
        });

        context("when expected !== verify.count", function() {
            it("should throw an error", function() {
                var limit = 10;
                var expectedCount = 2;
                var expectedMessage =
                    "Expected assertion count to be " +
                    expectedCount +
                    " but was " +
                    limit;
                var error;

                for (var i = 0; i < limit; i++) {
                    referee.assert(true);
                }

                try {
                    verify(expectedCount);
                } catch (err) {
                    error = err;
                }

                assert.equal(error.message, expectedMessage);
            });
        });
    });
});
