1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | !function(exports) {
|
8 |
|
9 | var testPoint
|
10 | , empty = {}
|
11 | , toStr = empty.toString
|
12 | , hasOwn = empty.hasOwnProperty
|
13 | , proc = typeof process == "undefined" ? { argv: [] } : process
|
14 | , color = (proc.stdout || empty).isTTY && proc.argv.indexOf("--no-color") == -1
|
15 | , v8 = assert.v8 = {
|
16 | statusTexts: [
|
17 | "Unknown",
|
18 | "Function is optimized",
|
19 | "Function is not optimized",
|
20 | "Function is always optimized",
|
21 | "Function is never optimized",
|
22 | "Function is maybe deoptimized",
|
23 | "Function is optimized by TurboFan"
|
24 | ]
|
25 | }
|
26 |
|
27 | try {
|
28 |
|
29 |
|
30 | ["GetOptimizationStatus", "HasFastProperties", "OptimizeFunctionOnNextCall"].map(function(name) {
|
31 | v8[name] = Function("fn", "return %" + name+ "(fn)")
|
32 | })
|
33 | v8.isNative = Function("%GetV8Version()")()
|
34 | } catch(e) {}
|
35 |
|
36 | function a() {}
|
37 | a.x1 = 1
|
38 | console.log("fast", assert.v8.HasFastProperties(a))
|
39 | a.x2=2
|
40 | delete a.x1
|
41 | console.log("fast", assert.v8.HasFastProperties(a))
|
42 |
|
43 | assert.isOptimized = function isOptimized(fn, args, scope) {
|
44 | if (!v8.isNative) {
|
45 | this.options.skip = "No access to v8 natives"
|
46 | return this
|
47 | }
|
48 | fn.apply(scope, args)
|
49 | fn.apply(scope, args)
|
50 | v8.OptimizeFunctionOnNextCall(fn)
|
51 | fn.apply(scope, args)
|
52 | var status = v8.GetOptimizationStatus(fn)
|
53 | |
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 | return this.ok(
|
70 | status == 1 || (status & 16 || status & 32),
|
71 | v8.statusTexts[status],
|
72 | isOptimized
|
73 | )
|
74 | }
|
75 |
|
76 | exports.assert = assert
|
77 | exports.describe = describe.describe = describe
|
78 | exports.test = function(name, next) {
|
79 | return testPoint = (testPoint || describe()).test(name, next)
|
80 | }
|
81 |
|
82 |
|
83 |
|
84 | function assert(value, message, _stackStart) {
|
85 | if (!value) {
|
86 | if (!message) {
|
87 | message = stringify(value) + " == true"
|
88 | } else if (Array.isArray(message)) {
|
89 | message = stringify(message[0]) + " " + message[1] + " " + stringify(message[2])
|
90 | }
|
91 | throw new AssertionError(message, _stackStart || assert)
|
92 | }
|
93 | }
|
94 | assert.ok = assert
|
95 |
|
96 | assert.notOk = function notOk(value, message) {
|
97 | return this.ok(
|
98 | !value,
|
99 | message || [actual, "==", expected],
|
100 | assertEqual
|
101 | )
|
102 | }
|
103 |
|
104 | assert.equal =
|
105 | assert.deepEqual = function assertEqual(actual, expected, message) {
|
106 | return this.ok(
|
107 | _deepEqual(actual, expected, []),
|
108 | message || [actual, "==", expected],
|
109 | assertEqual
|
110 | )
|
111 | }
|
112 |
|
113 |
|
114 | assert.notEqual =
|
115 | assert.notDeepEqual = function notEqual(actual, expected, message) {
|
116 | return this.ok(
|
117 | !_deepEqual(actual, expected, []),
|
118 | message || [actual, "!=", expected],
|
119 | notEqual
|
120 | )
|
121 | }
|
122 |
|
123 | assert.strictEqual = function strictEqual(actual, expected, message) {
|
124 | return this.ok(
|
125 | actual === expected,
|
126 | message || [actual, "===", expected],
|
127 | strictEqual
|
128 | )
|
129 | }
|
130 |
|
131 | assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
|
132 | return this.ok(
|
133 | actual !== expected,
|
134 | message || [actual, "!==", expected],
|
135 | notStrictEqual
|
136 | )
|
137 | }
|
138 |
|
139 | assert["throws"] = function assertThrows(fn, message) {
|
140 | var actual = false
|
141 | , expected = true
|
142 | try {
|
143 | fn()
|
144 | } catch(e) {
|
145 | actual = true
|
146 | }
|
147 | return this.ok(actual, message || "throws", assertThrows)
|
148 | }
|
149 |
|
150 | assert.type = function assertType(thing, expected) {
|
151 | var actual = type(thing)
|
152 | return this.ok(
|
153 | actual === expected,
|
154 | "type should be " + expected + ", got " + actual,
|
155 | assertType
|
156 | )
|
157 | }
|
158 |
|
159 | assert.anyOf = function anyOf(a, b) {
|
160 | return this.ok(
|
161 | Array.isArray(b) && b.indexOf(a) != -1,
|
162 | "should be one from " + stringify(b) + ", got " + a,
|
163 | anyOf
|
164 | )
|
165 | }
|
166 |
|
167 |
|
168 | function AssertionError(message, _stackStart) {
|
169 | this.name = "AssertionError"
|
170 | this.message = message
|
171 | if (Error.captureStackTrace) {
|
172 | Error.captureStackTrace(this, _stackStart || AssertionError)
|
173 | } else {
|
174 | this.stack = this.toString() + "\n" + (new Error()).stack
|
175 | }
|
176 | }
|
177 | AssertionError.prototype = Object.create(Error.prototype)
|
178 |
|
179 |
|
180 | function deepEqual(actual, expected) {
|
181 | return _deepEqual(actual, expected, [])
|
182 | }
|
183 |
|
184 | function _deepEqual(actual, expected, circ) {
|
185 |
|
186 | if (actual === expected || actual == null && actual == expected) return true
|
187 |
|
188 | var key, aKeys, eKeys, len
|
189 | , aType = type(actual)
|
190 |
|
191 | if (
|
192 | aType != type(expected) ||
|
193 | actual.constructor !== expected.constructor ||
|
194 | (aType == "date" && +actual !== +expected) ||
|
195 | typeof actual != "object"
|
196 | ) {
|
197 | return false
|
198 | }
|
199 |
|
200 | key = circ.indexOf(actual)
|
201 | if (key > -1) return circ[key + 1] === expected
|
202 | circ.push(actual, expected)
|
203 |
|
204 | aKeys = Object.keys(actual)
|
205 | len = aKeys.length
|
206 | if (aType == "array" || aType == "arguments") {
|
207 | if (actual.length !== expected.length) return false
|
208 | } else {
|
209 | eKeys = Object.keys(expected)
|
210 | if (len != eKeys.length || !_deepEqual(aKeys.sort(), eKeys.sort(), circ)) return false
|
211 | }
|
212 | for (; len--; ) {
|
213 | key = aKeys[len]
|
214 | if (!_deepEqual(actual[key], expected[key], circ)) return false
|
215 | }
|
216 | return true
|
217 | }
|
218 |
|
219 | function type(obj) {
|
220 |
|
221 |
|
222 | return obj !== obj ? "nan" : toStr.call(obj).slice(8, -1).toLowerCase()
|
223 | }
|
224 |
|
225 | function stringify(item, maxLen) {
|
226 | var max = maxLen > 9 ? maxLen : 70
|
227 | , str = _stringify(item, max, [])
|
228 | return str.length > max ? str.slice(0, max - 3) + ".." + str.slice(-1) : str
|
229 | }
|
230 |
|
231 | function _stringify(item, max, circ) {
|
232 | var i, tmp
|
233 | , left = max
|
234 | , t = type(item)
|
235 | , str =
|
236 | t === "string" ? JSON.stringify(item) :
|
237 | t === "function" ? ("" + item).split(/n | *\{/)[1] :
|
238 | (!item || t === "number" || t === "regexp" || item === true) ? "" + item :
|
239 | item.toJSON ? item.toJSON() :
|
240 | item
|
241 |
|
242 | if (typeof str == "object") {
|
243 | if (circ.indexOf(str) > -1) return "[Circular]"
|
244 | circ.push(str)
|
245 | tmp = []
|
246 | for (i in str) if (hasOwn.call(str, i)) {
|
247 | i = (t === "object" ? i + ":" : "") + _stringify(str[i], left, circ)
|
248 | tmp.push(i)
|
249 | left -= i.length
|
250 | if (left < 0) break
|
251 | }
|
252 | str =
|
253 | t === "array" ? "[" + tmp + "]" :
|
254 | t === "arguments" ? t + "[" + tmp + "]" :
|
255 | "{" + tmp + "}"
|
256 |
|
257 | if (t === "object" && item.constructor !== Object) {
|
258 | str = item.constructor.name + str
|
259 | }
|
260 | }
|
261 |
|
262 | return str
|
263 | }
|
264 |
|
265 |
|
266 |
|
267 |
|
268 |
|
269 |
|
270 |
|
271 | var doneTick, started
|
272 | , totalCases = 0
|
273 | , failedCases = 0
|
274 | , totalAsserts = 0
|
275 | , passedAsserts = 0
|
276 | , bold = "\x1b[1m"
|
277 | , italic = "\x1b[3m"
|
278 | , strike = "\x1b[9m"
|
279 | , underline = "\x1b[4m"
|
280 | , red = "\x1b[31m"
|
281 | , green = "\x1b[32m"
|
282 | , reset = "\x1b[0m"
|
283 |
|
284 | if (!color) {
|
285 | bold = italic = strike = underline = red = green = reset = ""
|
286 | }
|
287 |
|
288 | describe.result = ""
|
289 |
|
290 | describe.type = type
|
291 | describe.diff = diff
|
292 | describe.colorDiff = colorDiff
|
293 | describe.deepEqual = deepEqual
|
294 | describe.stringify = stringify
|
295 |
|
296 | function colorDiff(a, b) {
|
297 | var res = diff(a, b)
|
298 | console.log(
|
299 | a.slice(0, res[0]) +
|
300 | bold + red + strike + a.slice(res[0], res[0] + res[1]) +
|
301 | green + b.slice(res[0], res[0]+res[2]) +
|
302 | reset + a.slice(res[0] + res[1])
|
303 | )
|
304 | }
|
305 |
|
306 |
|
307 | function diff(a, b, re) {
|
308 | var c = 0, d = a.length, e = b.length
|
309 | for (; a.charAt(c) && a.charAt(c) == b.charAt(c); c++);
|
310 | for (; d > c && e > c && a.charAt(d - 1) == b.charAt(e - 1); d--) e--;
|
311 | return [c, d - c, e - c]
|
312 | }
|
313 |
|
314 | function describe(name) {
|
315 | return new TestSuite(name)
|
316 | }
|
317 |
|
318 |
|
319 |
|
320 |
|
321 | function TestSuite(name) {
|
322 | this.cases = []
|
323 |
|
324 | if (!started) {
|
325 | started = +new Date()
|
326 | print("TAP version 13")
|
327 | }
|
328 |
|
329 | print("# " + (name || "{unnamed test suite}"))
|
330 | }
|
331 |
|
332 | TestSuite.prototype = {
|
333 | _test: This,
|
334 | describe: describe,
|
335 | it: function(name, options) {
|
336 | return this.test("it " + name, null, options)
|
337 | },
|
338 | test: function(name, next, options) {
|
339 | var testSuite = this
|
340 | , testCase = new TestCase(name, options, testSuite)
|
341 |
|
342 | if (next) next(testCase)
|
343 |
|
344 | return testCase
|
345 | },
|
346 | }
|
347 |
|
348 | function TestCase(name, options, testSuite) {
|
349 | var testCase = this
|
350 | , opts = testCase.options = options || {}
|
351 | testCase.name = (++totalCases) + " - " + (name || "{unnamed test case}")
|
352 | testCase.suite = testSuite
|
353 | testCase.planned = 0
|
354 | testCase.failed = []
|
355 | testCase.passedAsserts = 0
|
356 | testCase.totalAsserts = 0
|
357 |
|
358 | testCase.plan = plan
|
359 | testCase.ok = ok
|
360 | testCase.end = end
|
361 |
|
362 | testSuite.cases.push( testCase )
|
363 |
|
364 | if (
|
365 | opts.skip ||
|
366 | (opts.skip = opts.v8Native && !v8.isNative && "No access to v8 natives") ) {
|
367 | testCase.ok = testCase.equal = testCase.type = testCase.run = This
|
368 | }
|
369 |
|
370 | ;["describe", "it", "test"].forEach(function(name) {
|
371 | testCase[name] = function() {
|
372 | testCase.end()
|
373 | return testSuite[name].apply(testSuite, arguments)
|
374 | }
|
375 | })
|
376 |
|
377 | clearTimeout(doneTick)
|
378 | doneTick = setTimeout(done, 50)
|
379 |
|
380 | function done() {
|
381 | if (testCase.ok == describe.it.ok) testSuite.done()
|
382 |
|
383 | }
|
384 |
|
385 | return testCase
|
386 | }
|
387 |
|
388 | TestCase.prototype = describe.it = describe.assert = assert
|
389 |
|
390 | function plan(num) {
|
391 | this.planned = num
|
392 | return this
|
393 | }
|
394 |
|
395 | function ok(value, message, _stackStart) {
|
396 | var testCase = this
|
397 | totalAsserts++
|
398 | testCase.totalAsserts++
|
399 | try {
|
400 | assert(value, message, _stackStart)
|
401 | passedAsserts++
|
402 | testCase.passedAsserts++
|
403 | } catch(e) {
|
404 | testCase.failed.push(testCase.options.noStack ? e.message : e.stack)
|
405 | }
|
406 | return testCase
|
407 | }
|
408 |
|
409 | function end() {
|
410 | var testCase = this
|
411 | , name = testCase.name
|
412 |
|
413 | if (testCase.ended) return
|
414 |
|
415 | testCase.ended = new Date()
|
416 |
|
417 | if (testCase.options.skip) {
|
418 | return print("ok " + name + " # skip - " + testCase.options.skip)
|
419 | }
|
420 |
|
421 | if (testCase.planned != void 0) {
|
422 | testCase.equal(testCase.planned, testCase.totalAsserts, null, "planned")
|
423 | }
|
424 |
|
425 | name += " [" + testCase.passedAsserts + "/" + testCase.totalAsserts + "]"
|
426 |
|
427 | if (testCase.failed.length) {
|
428 | failedCases++
|
429 | print("not ok " + name + "\n---\n" + testCase.failed.join("\n") + "\n---")
|
430 | } else {
|
431 | print("ok " + name)
|
432 | }
|
433 | }
|
434 |
|
435 | function done(next) {
|
436 | if (this.done_) return
|
437 | this.done_ = +new Date()
|
438 |
|
439 | print("1.." + totalCases)
|
440 | print("#" + (failedCases ? "" : green + bold) + " pass " + (totalCases - failedCases)
|
441 | + "/" + totalCases
|
442 | + " [" + passedAsserts + "/" + totalAsserts + "]"
|
443 | + " in " + (this.done_ - started) + " ms"
|
444 | + reset)
|
445 |
|
446 | failedCases && print("#" + red + bold + " fail " + failedCases
|
447 | + " [" + (totalAsserts - passedAsserts) + "]"
|
448 | + reset)
|
449 |
|
450 | if (typeof next == "function") next()
|
451 | |
452 |
|
453 |
|
454 |
|
455 |
|
456 | }
|
457 |
|
458 | function print(str) {
|
459 | describe.result += str + "\n"
|
460 | console.log(str)
|
461 | }
|
462 |
|
463 | function This() {
|
464 | return this
|
465 | }
|
466 |
|
467 |
|
468 | }(this)
|
469 |
|
470 |
|
471 |
|
472 |
|
473 |
|
474 |
|