describe("jasmine.Env", function() {
  var env;
  beforeEach(function() {
    env = new jasmine.Env();
    env.updateInterval = 0;
  });

  describe('ids', function () {
    it('nextSpecId should return consecutive integers, starting at 0', function () {
      expect(env.nextSpecId()).toEqual(0);
      expect(env.nextSpecId()).toEqual(1);
      expect(env.nextSpecId()).toEqual(2);
    });
  });

  describe("reporting", function() {
    var fakeReporter;

    beforeEach(function() {
      fakeReporter = jasmine.createSpyObj("fakeReporter", ["log"]);
    });

    describe('version', function () {
      var oldVersion;

      beforeEach(function () {
        oldVersion = jasmine.version_;
      });

      afterEach(function () {
        jasmine.version_ = oldVersion;
      });

      it('should raise an error if version is not set', function () {
        jasmine.version_ = null;
        var exception;
        try {
          env.version();
        }
        catch (e) {
          exception = e;
        }
        expect(exception.message).toEqual('Version not set');
      });

      it("version should return the current version as an int", function() {
        jasmine.version_ = {
          "major": 1,
          "minor": 9,
          "build": 7,
          "revision": 8
        };
        expect(env.version()).toEqual({
          "major": 1,
          "minor": 9,
          "build": 7,
          "revision": 8
        });
      });

      describe("versionString", function() {
        it("should return a stringified version number", function() {
          jasmine.version_ = {
            "major": 1,
            "minor": 9,
            "build": 7,
            "revision": 8
          };
          expect(env.versionString()).toEqual("1.9.7 revision 8");
        });

        it("should return a nice string when version is unknown", function() {
          jasmine.version_ = null;
          expect(env.versionString()).toEqual("version unknown");
        });
      });
    });

    it("should allow reporters to be registered", function() {
      env.addReporter(fakeReporter);
      env.reporter.log("message");
      expect(fakeReporter.log).toHaveBeenCalledWith("message");
    });
  });

  describe("equality testing", function() {
    describe("with custom equality testers", function() {
      var aObj, bObj, isEqual;

      beforeEach(function() {
        env.addEqualityTester(function(a, b) {
          aObj = a;
          bObj = b;
          return isEqual;
        });
      });

      it("should call the custom equality tester with two objects for comparison", function() {
        env.equals_("1", "2");
        expect(aObj).toEqual("1");
        expect(bObj).toEqual("2");
      });

      describe("when the custom equality tester returns false", function() {
        beforeEach(function() {
          isEqual = false;
        });

        it("should give custom equality testers precedence", function() {
          expect(env.equals_('abc', 'abc')).toBeFalsy();
          var o = {};
          expect(env.equals_(o, o)).toBeFalsy();
        });
      });


      describe("when the custom equality tester returns true", function() {
        beforeEach(function() {
          isEqual = true;
        });

        it("should give custom equality testers precedence", function() {
          expect(env.equals_('abc', 'def')).toBeTruthy();
          expect(env.equals_(true, false)).toBeTruthy();
        });
      });

      describe("when the custom equality tester returns undefined", function() {
        beforeEach(function() {
          isEqual = jasmine.undefined;
        });

        it("should use normal equality rules", function() {
          expect(env.equals_('abc', 'abc')).toBeTruthy();
          expect(env.equals_('abc', 'def')).toBeFalsy();
        });

        describe("even if there are several", function() {
          beforeEach(function() {
            env.addEqualityTester(function(a, b) { return jasmine.undefined; });
            env.addEqualityTester(function(a, b) { return jasmine.undefined; });
          });

          it("should use normal equality rules", function() {
            expect(env.equals_('abc', 'abc')).toBeTruthy();
            expect(env.equals_('abc', 'def')).toBeFalsy();
          });
        });
      });

      it("should evaluate custom equality testers in the order they are declared", function() {
        isEqual = false;
        env.addEqualityTester(function(a, b) { return true; });
        expect(env.equals_('abc', 'abc')).toBeFalsy();
      });
    });
  });
});
