1 jasmine.Env = function() {
  2   this.currentSpec = null;
  3   this.currentSuite = null;
  4   this.currentRunner = new jasmine.Runner(this);
  5   this.currentlyRunningTests = false;
  6 
  7   this.updateInterval = 0;
  8   this.lastUpdate = 0;
  9   this.specFilter = function() {
 10     return true;
 11   };
 12 
 13   this.nextSpecId_ = 0;
 14   this.equalityTesters_ = [];
 15 };
 16 
 17 
 18 jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
 19 jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
 20 jasmine.Env.prototype.setInterval = jasmine.setInterval;
 21 jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
 22 
 23 jasmine.Env.prototype.execute = function() {
 24   this.currentRunner.execute();
 25 };
 26 
 27 jasmine.Env.prototype.describe = function(description, specDefinitions) {
 28   var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
 29 
 30   var parentSuite = this.currentSuite;
 31   if (parentSuite) {
 32     parentSuite.specs.push(suite);
 33   } else {
 34     this.currentRunner.suites.push(suite);
 35   }
 36 
 37   this.currentSuite = suite;
 38 
 39   specDefinitions.call(suite);
 40 
 41   this.currentSuite = parentSuite;
 42 
 43   return suite;
 44 };
 45 
 46 jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
 47   this.currentSuite.beforeEach(beforeEachFunction);
 48 };
 49 
 50 jasmine.Env.prototype.afterEach = function(afterEachFunction) {
 51   this.currentSuite.afterEach(afterEachFunction);
 52 };
 53 
 54 jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
 55   return {
 56     execute: function() {
 57     }
 58   };
 59 };
 60 
 61 jasmine.Env.prototype.it = function(description, func) {
 62   var spec = new jasmine.Spec(this, this.currentSuite, description);
 63   this.currentSuite.specs.push(spec);
 64   this.currentSpec = spec;
 65 
 66   if (func) {
 67     spec.addToQueue(func);
 68   }
 69 
 70   return spec;
 71 };
 72 
 73 jasmine.Env.prototype.xit = function(desc, func) {
 74   return {
 75     id: this.nextSpecId_++,
 76     runs: function() {
 77     }
 78   };
 79 };
 80 
 81 jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
 82   if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
 83     return true;
 84   }
 85 
 86   a.__Jasmine_been_here_before__ = b;
 87   b.__Jasmine_been_here_before__ = a;
 88 
 89   var hasKey = function(obj, keyName) {
 90     return obj != null && obj[keyName] !== undefined;
 91   };
 92 
 93   for (var property in b) {
 94     if (!hasKey(a, property) && hasKey(b, property)) {
 95       mismatchKeys.push("expected has key '" + property + "', but missing from <b>actual</b>.");
 96     }
 97   }
 98   for (property in a) {
 99     if (!hasKey(b, property) && hasKey(a, property)) {
100       mismatchKeys.push("<b>expected</b> missing key '" + property + "', but present in actual.");
101     }
102   }
103   for (property in b) {
104     if (property == '__Jasmine_been_here_before__') continue;
105     if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
106       mismatchValues.push("'" + property + "' was<br /><br />'" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "'<br /><br />in expected, but was<br /><br />'" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "'<br /><br />in actual.<br />");
107     }
108   }
109 
110   if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
111     mismatchValues.push("arrays were not the same length");
112   }
113 
114   delete a.__Jasmine_been_here_before__;
115   delete b.__Jasmine_been_here_before__;
116   return (mismatchKeys.length == 0 && mismatchValues.length == 0);
117 };
118 
119 jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
120   mismatchKeys = mismatchKeys || [];
121   mismatchValues = mismatchValues || [];
122 
123   if (a === b) return true;
124 
125   if (a === undefined || a === null || b === undefined || b === null) {
126     return (a == undefined && b == undefined);
127   }
128 
129   if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
130     return a === b;
131   }
132 
133   if (a instanceof Date && b instanceof Date) {
134     return a.getTime() == b.getTime();
135   }
136 
137   if (a instanceof jasmine.Matchers.Any) {
138     return a.matches(b);
139   }
140 
141   if (b instanceof jasmine.Matchers.Any) {
142     return b.matches(a);
143   }
144 
145   if (typeof a === "object" && typeof b === "object") {
146     return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
147   }
148 
149   for (var i = 0; i < this.equalityTesters_.length; i++) {
150     var equalityTester = this.equalityTesters_[i];
151     var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
152     if (result !== undefined) return result;
153   }
154 
155   //Straight check
156   return (a === b);
157 };
158 
159 jasmine.Env.prototype.contains_ = function(haystack, needle) {
160   if (jasmine.isArray_(haystack)) {
161     for (var i = 0; i < haystack.length; i++) {
162       if (this.equals_(haystack[i], needle)) return true;
163     }
164     return false;
165   }
166   return haystack.indexOf(needle) >= 0;
167 };
168 
169 jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
170   this.equalityTesters_.push(equalityTester);
171 };
172