|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 |
|
6 if (typeof assertThrowsInstanceOf === 'undefined') { |
|
7 var assertThrowsInstanceOf = function assertThrowsInstanceOf(f, ctor, msg) { |
|
8 var fullmsg; |
|
9 try { |
|
10 f(); |
|
11 } catch (exc) { |
|
12 if (exc instanceof ctor) |
|
13 return; |
|
14 fullmsg = "Assertion failed: expected exception " + ctor.name + ", got " + exc; |
|
15 } |
|
16 if (fullmsg === undefined) |
|
17 fullmsg = "Assertion failed: expected exception " + ctor.name + ", no exception thrown"; |
|
18 if (msg !== undefined) |
|
19 fullmsg += " - " + msg; |
|
20 throw new Error(fullmsg); |
|
21 }; |
|
22 } |
|
23 |
|
24 if (typeof assertThrowsValue === 'undefined') { |
|
25 var assertThrowsValue = function assertThrowsValue(f, val, msg) { |
|
26 var fullmsg; |
|
27 try { |
|
28 f(); |
|
29 } catch (exc) { |
|
30 if ((exc === val) === (val === val) && (val !== 0 || 1 / exc === 1 / val)) |
|
31 return; |
|
32 fullmsg = "Assertion failed: expected exception " + val + ", got " + exc; |
|
33 } |
|
34 if (fullmsg === undefined) |
|
35 fullmsg = "Assertion failed: expected exception " + val + ", no exception thrown"; |
|
36 if (msg !== undefined) |
|
37 fullmsg += " - " + msg; |
|
38 throw new Error(fullmsg); |
|
39 }; |
|
40 } |
|
41 |
|
42 if (typeof assertDeepEq === 'undefined') { |
|
43 var assertDeepEq = (function(){ |
|
44 var call = Function.prototype.call, |
|
45 Map_ = Map, |
|
46 Error_ = Error, |
|
47 Map_has = call.bind(Map.prototype.has), |
|
48 Map_get = call.bind(Map.prototype.get), |
|
49 Map_set = call.bind(Map.prototype.set), |
|
50 Object_toString = call.bind(Object.prototype.toString), |
|
51 Function_toString = call.bind(Function.prototype.toString), |
|
52 Object_getPrototypeOf = Object.getPrototypeOf, |
|
53 Object_hasOwnProperty = call.bind(Object.prototype.hasOwnProperty), |
|
54 Object_getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor, |
|
55 Object_isExtensible = Object.isExtensible, |
|
56 Object_getOwnPropertyNames = Object.getOwnPropertyNames, |
|
57 uneval_ = uneval; |
|
58 |
|
59 // Return true iff ES6 Type(v) isn't Object. |
|
60 // Note that `typeof document.all === "undefined"`. |
|
61 function isPrimitive(v) { |
|
62 return (v === null || |
|
63 v === undefined || |
|
64 typeof v === "boolean" || |
|
65 typeof v === "number" || |
|
66 typeof v === "string" || |
|
67 typeof v === "symbol"); |
|
68 } |
|
69 |
|
70 function assertSameValue(a, b, msg) { |
|
71 try { |
|
72 assertEq(a, b); |
|
73 } catch (exc) { |
|
74 throw new Error(exc.message + (msg ? " " + msg : "")); |
|
75 } |
|
76 } |
|
77 |
|
78 function assertSameClass(a, b, msg) { |
|
79 var ac = Object_toString(a), bc = Object_toString(b); |
|
80 assertSameValue(ac, bc, msg); |
|
81 switch (ac) { |
|
82 case "[object Function]": |
|
83 assertSameValue(Function_toString(a), Function_toString(b), msg); |
|
84 } |
|
85 } |
|
86 |
|
87 function at(prevmsg, segment) { |
|
88 return prevmsg ? prevmsg + segment : "at _" + segment; |
|
89 } |
|
90 |
|
91 // Assert that the arguments a and b are thoroughly structurally equivalent. |
|
92 // |
|
93 // For the sake of speed, we cut a corner: |
|
94 // var x = {}, y = {}, ax = [x]; |
|
95 // assertDeepEq([ax, x], [ax, y]); // passes (?!) |
|
96 // |
|
97 // Technically this should fail, since the two object graphs are different. |
|
98 // (The graph of [ax, y] contains one more object than the graph of [ax, x].) |
|
99 // |
|
100 // To get technically correct behavior, pass {strictEquivalence: true}. |
|
101 // This is slower because we have to walk the entire graph, and Object.prototype |
|
102 // is big. |
|
103 // |
|
104 return function assertDeepEq(a, b, options) { |
|
105 var strictEquivalence = options ? options.strictEquivalence : false; |
|
106 |
|
107 function assertSameProto(a, b, msg) { |
|
108 check(Object_getPrototypeOf(a), Object_getPrototypeOf(b), at(msg, ".__proto__")); |
|
109 } |
|
110 |
|
111 function failPropList(na, nb, msg) { |
|
112 throw Error_("got own properties " + uneval_(na) + ", expected " + uneval_(nb) + |
|
113 (msg ? " " + msg : "")); |
|
114 } |
|
115 |
|
116 function assertSameProps(a, b, msg) { |
|
117 var na = Object_getOwnPropertyNames(a), |
|
118 nb = Object_getOwnPropertyNames(b); |
|
119 if (na.length !== nb.length) |
|
120 failPropList(na, nb, msg); |
|
121 for (var i = 0; i < na.length; i++) { |
|
122 var name = na[i]; |
|
123 if (name !== nb[i]) |
|
124 failPropList(na, nb, msg); |
|
125 var da = Object_getOwnPropertyDescriptor(a, name), |
|
126 db = Object_getOwnPropertyDescriptor(b, name); |
|
127 var pmsg = at(msg, /^[_$A-Za-z0-9]+$/.test(name) |
|
128 ? /0|[1-9][0-9]*/.test(name) ? "[" + name + "]" : "." + name |
|
129 : "[" + uneval_(name) + "]"); |
|
130 assertSameValue(da.configurable, db.configurable, at(pmsg, ".[[Configurable]]")); |
|
131 assertSameValue(da.enumerable, db.enumerable, at(pmsg, ".[[Enumerable]]")); |
|
132 if (Object_hasOwnProperty(da, "value")) { |
|
133 if (!Object_hasOwnProperty(db, "value")) |
|
134 throw Error_("got data property, expected accessor property" + pmsg); |
|
135 check(da.value, db.value, pmsg); |
|
136 } else { |
|
137 if (Object_hasOwnProperty(db, "value")) |
|
138 throw Error_("got accessor property, expected data property" + pmsg); |
|
139 check(da.get, db.get, at(pmsg, ".[[Get]]")); |
|
140 check(da.set, db.set, at(pmsg, ".[[Set]]")); |
|
141 } |
|
142 } |
|
143 }; |
|
144 |
|
145 var ab = Map_(); |
|
146 var bpath = Map_(); |
|
147 |
|
148 function check(a, b, path) { |
|
149 if (isPrimitive(a)) { |
|
150 assertSameValue(a, b, path); |
|
151 } else if (isPrimitive(b)) { |
|
152 throw Error_("got " + Object_toString(a) + ", expected " + uneval_(b) + " " + path); |
|
153 } else if (Map_has(ab, a)) { |
|
154 assertSameValue(Map_get(ab, a), b, path); |
|
155 } else if (Map_has(bpath, b)) { |
|
156 var bPrevPath = Map_get(bpath, b) || "_"; |
|
157 throw Error_("got distinct objects " + at(path, "") + " and " + at(bPrevPath, "") + |
|
158 ", expected the same object both places"); |
|
159 } else { |
|
160 Map_set(ab, a, b); |
|
161 Map_set(bpath, b, path); |
|
162 if (a !== b || strictEquivalence) { |
|
163 assertSameClass(a, b, path); |
|
164 assertSameProto(a, b, path); |
|
165 assertSameProps(a, b, path); |
|
166 assertSameValue(Object_isExtensible(a), |
|
167 Object_isExtensible(b), |
|
168 at(path, ".[[Extensible]]")); |
|
169 } |
|
170 } |
|
171 } |
|
172 |
|
173 check(a, b, ""); |
|
174 }; |
|
175 })(); |
|
176 } |