1 /**
  2  * Environment for Jasmine
  3  *
  4  * @constructor
  5  */
  6 jasmine.Env = function() {
  7   this.currentSpec = null;
  8   this.currentSuite = null;
  9   this.currentRunner_ = new jasmine.Runner(this);
 10 
 11   this.reporter = new jasmine.MultiReporter();
 12 
 13   this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL
 14   this.lastUpdate = 0;
 15   this.specFilter = function() {
 16     return true;
 17   };
 18 
 19   this.nextSpecId_ = 0;
 20   this.nextSuiteId_ = 0;
 21   this.equalityTesters_ = [];
 22 };
 23 
 24 
 25 jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
 26 jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
 27 jasmine.Env.prototype.setInterval = jasmine.setInterval;
 28 jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
 29 
 30 /**
 31  * @returns an object containing jasmine version build info, if set.
 32  */
 33 jasmine.Env.prototype.version = function () {
 34   if (jasmine.version_) {
 35     return jasmine.version_;
 36   } else {
 37     throw new Error('Version not set');
 38   }
 39 };
 40 
 41 /**
 42  * @returns a sequential integer starting at 0
 43  */
 44 jasmine.Env.prototype.nextSpecId = function () {
 45   return this.nextSpecId_++;
 46 };
 47 
 48 /**
 49  * @returns a sequential integer starting at 0
 50  */
 51 jasmine.Env.prototype.nextSuiteId = function () {
 52   return this.nextSuiteId_++;
 53 };
 54 
 55 /**
 56  * Register a reporter to receive status updates from Jasmine.
 57  * @param {jasmine.Reporter} reporter An object which will receive status updates.
 58  */
 59 jasmine.Env.prototype.addReporter = function(reporter) {
 60   this.reporter.addReporter(reporter);
 61 };
 62 
 63 jasmine.Env.prototype.execute = function() {
 64   this.currentRunner_.execute();
 65 };
 66 
 67 jasmine.Env.prototype.describe = function(description, specDefinitions) {
 68   var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
 69 
 70   var parentSuite = this.currentSuite;
 71   if (parentSuite) {
 72     parentSuite.add(suite);
 73   } else {
 74     this.currentRunner_.add(suite);
 75   }
 76 
 77   this.currentSuite = suite;
 78 
 79   specDefinitions.call(suite);
 80 
 81   this.currentSuite = parentSuite;
 82 
 83   return suite;
 84 };
 85 
 86 jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
 87   if (this.currentSuite) {
 88     this.currentSuite.beforeEach(beforeEachFunction);
 89   } else {
 90     this.currentRunner_.beforeEach(beforeEachFunction);
 91   }
 92 };
 93 
 94 jasmine.Env.prototype.currentRunner = function () {
 95   return this.currentRunner_;
 96 };
 97 
 98 jasmine.Env.prototype.afterEach = function(afterEachFunction) {
 99   if (this.currentSuite) {
100     this.currentSuite.afterEach(afterEachFunction);
101   } else {
102     this.currentRunner_.afterEach(afterEachFunction);
103   }
104 
105 };
106 
107 jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
108   return {
109     execute: function() {
110     }
111   };
112 };
113 
114 jasmine.Env.prototype.it = function(description, func) {
115   var spec = new jasmine.Spec(this, this.currentSuite, description);
116   this.currentSuite.add(spec);
117   this.currentSpec = spec;
118   spec.pending = false;
119 
120   if (func) {
121     spec.runs(func);
122   } else {
123     spec.pending = true;
124   }
125 
126   return spec;
127 };
128 
129 jasmine.Env.prototype.xit = function(description, func) {
130   var spec = this.it(description, func);
131   spec.pending = true;
132   return spec;
133 };
134 
135 jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
136   if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
137     return true;
138   }
139 
140   a.__Jasmine_been_here_before__ = b;
141   b.__Jasmine_been_here_before__ = a;
142 
143   var hasKey = function(obj, keyName) {
144     return obj != null && obj[keyName] !== undefined;
145   };
146 
147   for (var property in b) {
148     if (!hasKey(a, property) && hasKey(b, property)) {
149       mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
150     }
151   }
152   for (property in a) {
153     if (!hasKey(b, property) && hasKey(a, property)) {
154       mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
155     }
156   }
157   for (property in b) {
158     if (property == '__Jasmine_been_here_before__') continue;
159     if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
160       mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
161     }
162   }
163 
164   if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
165     mismatchValues.push("arrays were not the same length");
166   }
167 
168   delete a.__Jasmine_been_here_before__;
169   delete b.__Jasmine_been_here_before__;
170   return (mismatchKeys.length == 0 && mismatchValues.length == 0);
171 };
172 
173 jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
174   mismatchKeys = mismatchKeys || [];
175   mismatchValues = mismatchValues || [];
176 
177   if (a === b) return true;
178 
179   if (a === undefined || a === null || b === undefined || b === null) {
180     return (a == undefined && b == undefined);
181   }
182 
183   if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
184     return a === b;
185   }
186 
187   if (a instanceof Date && b instanceof Date) {
188     return a.getTime() == b.getTime();
189   }
190 
191   if (a instanceof jasmine.Matchers.Any) {
192     return a.matches(b);
193   }
194 
195   if (b instanceof jasmine.Matchers.Any) {
196     return b.matches(a);
197   }
198 
199   if (typeof a === "object" && typeof b === "object") {
200     return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
201   }
202 
203   for (var i = 0; i < this.equalityTesters_.length; i++) {
204     var equalityTester = this.equalityTesters_[i];
205     var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
206     if (result !== undefined) return result;
207   }
208 
209   //Straight check
210   return (a === b);
211 };
212 
213 jasmine.Env.prototype.contains_ = function(haystack, needle) {
214   if (jasmine.isArray_(haystack)) {
215     for (var i = 0; i < haystack.length; i++) {
216       if (this.equals_(haystack[i], needle)) return true;
217     }
218     return false;
219   }
220   return haystack.indexOf(needle) >= 0;
221 };
222 
223 jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
224   this.equalityTesters_.push(equalityTester);
225 };
226