GPU workaround to simulate Out of Memory errors with large textures
[chromium-blink-merge.git] / gin / test / expect.js
blob597b5b1d5e32bb456109f10cea141fb480451b93
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 define(function() {
6 // Equality function based on isEqual in
7 // Underscore.js 1.5.2
8 // http://underscorejs.org
9 // (c) 2009-2013 Jeremy Ashkenas,
10 // DocumentCloud,
11 // and Investigative Reporters & Editors
12 // Underscore may be freely distributed under the MIT license.
14 function has(obj, key) {
15 return obj.hasOwnProperty(key);
17 function isFunction(obj) {
18 return typeof obj === 'function';
20 function isArrayBufferClass(className) {
21 return className == '[object ArrayBuffer]' ||
22 className.match(/\[object \w+\d+(Clamped)?Array\]/);
24 // Internal recursive comparison function for `isEqual`.
25 function eq(a, b, aStack, bStack) {
26 // Identical objects are equal. `0 === -0`, but they aren't identical.
27 // See the Harmony `egal` proposal:
28 // http://wiki.ecmascript.org/doku.php?id=harmony:egal.
29 if (a === b)
30 return a !== 0 || 1 / a == 1 / b;
31 // A strict comparison is necessary because `null == undefined`.
32 if (a == null || b == null)
33 return a === b;
34 // Compare `[[Class]]` names.
35 var className = toString.call(a);
36 if (className != toString.call(b))
37 return false;
38 switch (className) {
39 // Strings, numbers, dates, and booleans are compared by value.
40 case '[object String]':
41 // Primitives and their corresponding object wrappers are equivalent;
42 // thus, `"5"` is equivalent to `new String("5")`.
43 return a == String(b);
44 case '[object Number]':
45 // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is
46 // performed for other numeric values.
47 return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
48 case '[object Date]':
49 case '[object Boolean]':
50 // Coerce dates and booleans to numeric primitive values. Dates are
51 // compared by their millisecond representations. Note that invalid
52 // dates with millisecond representations of `NaN` are not equivalent.
53 return +a == +b;
54 // RegExps are compared by their source patterns and flags.
55 case '[object RegExp]':
56 return a.source == b.source &&
57 a.global == b.global &&
58 a.multiline == b.multiline &&
59 a.ignoreCase == b.ignoreCase;
61 if (typeof a != 'object' || typeof b != 'object')
62 return false;
63 // Assume equality for cyclic structures. The algorithm for detecting
64 // cyclic structures is adapted from ES 5.1 section 15.12.3, abstract
65 // operation `JO`.
66 var length = aStack.length;
67 while (length--) {
68 // Linear search. Performance is inversely proportional to the number of
69 // unique nested structures.
70 if (aStack[length] == a)
71 return bStack[length] == b;
73 // Objects with different constructors are not equivalent, but `Object`s
74 // from different frames are.
75 var aCtor = a.constructor, bCtor = b.constructor;
76 if (aCtor !== bCtor && !(isFunction(aCtor) && (aCtor instanceof aCtor) &&
77 isFunction(bCtor) && (bCtor instanceof bCtor))
78 && ('constructor' in a && 'constructor' in b)) {
79 return false;
81 // Add the first object to the stack of traversed objects.
82 aStack.push(a);
83 bStack.push(b);
84 var size = 0, result = true;
85 // Recursively compare Maps, objects and arrays.
86 if (className == '[object Array]' || isArrayBufferClass(className)) {
87 // Compare array lengths to determine if a deep comparison is necessary.
88 size = a.length;
89 result = size == b.length;
90 if (result) {
91 // Deep compare the contents, ignoring non-numeric properties.
92 while (size--) {
93 if (!(result = eq(a[size], b[size], aStack, bStack)))
94 break;
97 } else if (className == '[object Map]') {
98 result = a.size == b.size;
99 if (result) {
100 var entries = a.entries();
101 for (var e = entries.next(); result && !e.done; e = entries.next()) {
102 var key = e.value[0];
103 var value = e.value[1];
104 result = b.has(key) && eq(value, b.get(key), aStack, bStack);
107 } else {
108 // Deep compare objects.
109 for (var key in a) {
110 if (has(a, key)) {
111 // Count the expected number of properties.
112 size++;
113 // Deep compare each member.
114 if (!(result = has(b, key) && eq(a[key], b[key], aStack, bStack)))
115 break;
118 // Ensure that both objects contain the same number of properties.
119 if (result) {
120 for (key in b) {
121 if (has(b, key) && !(size--))
122 break;
124 result = !size;
127 // Remove the first object from the stack of traversed objects.
128 aStack.pop();
129 bStack.pop();
130 return result;
133 function describe(subjects) {
134 var descriptions = [];
135 Object.getOwnPropertyNames(subjects).forEach(function(name) {
136 if (name === "Description")
137 descriptions.push(subjects[name]);
138 else
139 descriptions.push(name + ": " + JSON.stringify(subjects[name]));
141 return descriptions.join(" ");
144 var predicates = {};
146 predicates.toBe = function(actual, expected) {
147 return {
148 "result": actual === expected,
149 "message": describe({
150 "Actual": actual,
151 "Expected": expected,
156 predicates.toEqual = function(actual, expected) {
157 return {
158 "result": eq(actual, expected, [], []),
159 "message": describe({
160 "Actual": actual,
161 "Expected": expected,
166 predicates.toBeDefined = function(actual) {
167 return {
168 "result": typeof actual !== "undefined",
169 "message": describe({
170 "Actual": actual,
171 "Description": "Expected a defined value",
176 predicates.toBeUndefined = function(actual) {
177 // Recall: undefined is just a global variable. :)
178 return {
179 "result": typeof actual === "undefined",
180 "message": describe({
181 "Actual": actual,
182 "Description": "Expected an undefined value",
187 predicates.toBeNull = function(actual) {
188 // Recall: typeof null === "object".
189 return {
190 "result": actual === null,
191 "message": describe({
192 "Actual": actual,
193 "Expected": null,
198 predicates.toBeTruthy = function(actual) {
199 return {
200 "result": !!actual,
201 "message": describe({
202 "Actual": actual,
203 "Description": "Expected a truthy value",
208 predicates.toBeFalsy = function(actual) {
209 return {
210 "result": !!!actual,
211 "message": describe({
212 "Actual": actual,
213 "Description": "Expected a falsy value",
218 predicates.toContain = function(actual, element) {
219 return {
220 "result": (function () {
221 for (var i = 0; i < actual.length; ++i) {
222 if (eq(actual[i], element, [], []))
223 return true;
225 return false;
226 })(),
227 "message": describe({
228 "Actual": actual,
229 "Element": element,
234 predicates.toBeLessThan = function(actual, reference) {
235 return {
236 "result": actual < reference,
237 "message": describe({
238 "Actual": actual,
239 "Reference": reference,
244 predicates.toBeGreaterThan = function(actual, reference) {
245 return {
246 "result": actual > reference,
247 "message": describe({
248 "Actual": actual,
249 "Reference": reference,
254 predicates.toThrow = function(actual) {
255 return {
256 "result": (function () {
257 if (!isFunction(actual))
258 throw new TypeError;
259 try {
260 actual();
261 } catch (ex) {
262 return true;
264 return false;
265 })(),
266 "message": "Expected function to throw",
270 function negate(predicate) {
271 return function() {
272 var outcome = predicate.apply(null, arguments);
273 outcome.result = !outcome.result;
274 return outcome;
278 function check(predicate) {
279 return function() {
280 var outcome = predicate.apply(null, arguments);
281 if (outcome.result)
282 return;
283 throw outcome.message;
287 function Condition(actual) {
288 this.not = {};
289 Object.getOwnPropertyNames(predicates).forEach(function(name) {
290 var bound = predicates[name].bind(null, actual);
291 this[name] = check(bound);
292 this.not[name] = check(negate(bound));
293 }, this);
296 return function(actual) {
297 return new Condition(actual);