UNPKG

11.7 kBJavaScriptView Raw
1
2
3
4// https://github.com/visionmedia/supertest
5// http://sinonjs.org/
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 // chrome --js-flags="--allow-natives-syntax" test.html
29 // node --allow-natives-syntax test.js
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 0 0 0 0 0 1 0 0 0 0 0 1
55 ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬ ┬
56 │ │ │ │ │ │ │ │ │ │ │ └─╸ is function
57 │ │ │ │ │ │ │ │ │ │ └───╸ is never optimized
58 │ │ │ │ │ │ │ │ │ └─────╸ is always optimized
59 │ │ │ │ │ │ │ │ └───────╸ is maybe deoptimized
60 │ │ │ │ │ │ │ └─────────╸ is optimized
61 │ │ │ │ │ │ └───────────╸ is optimized by TurboFan
62 │ │ │ │ │ └─────────────╸ is interpreted
63 │ │ │ │ └───────────────╸ is marked for optimization
64 │ │ │ └─────────────────╸ is marked for concurrent optimization
65 │ │ └───────────────────╸ is optimizing concurrently
66 │ └─────────────────────╸ is executing
67 └───────────────────────╸ topmost frame is turbo fanned */
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 // null == undefined
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 // Standard clearly states that NaN is a number
221 // but this is not useful for testing.
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 //else testCase.run(done)
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 * FAILED tests 1, 3, 6
453 * Failed 3/6 tests, 50.00% okay
454 * PASS 1 test executed in 0.023s, 1 passed, 0 failed, 0 dubious, 0 skipped.
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* http://sourceforge.net/projects/portableapps/files/
473*/
474