Name: js-handler/node_modules/nodeunit/node_modules/tap/lib/tap-assert.js
| 1: | // an assert module that returns tappable data for each assertion. |
| 2: | var difflet = require('difflet') |
| 3: | , deepEqual = require('deep-equal') |
| 4: | , bufferEqual = require('buffer-equal') |
| 5: | , Buffer = require('buffer').Buffer |
| 6: | |
| 7: | module.exports = assert |
| 8: | |
| 9: | var syns = {} |
| 10: | , id = 1 |
| 11: | |
| 12: | function assert (ok, message, extra) { |
| 13: | if (extra && extra.skip) return assert.skip(message, extra) |
| 14: | |
| 15: | //console.error("assert %j", [ok, message, extra]) |
| 16: | //if (extra && extra.skip) return assert.skip(message, extra) |
| 17: | //console.error("assert", [ok, message, extra]) |
| 18: | ok = !!ok |
| 19: | var res = { id : id ++, ok: ok } |
| 20: | |
| 21: | var caller = getCaller(extra && extra.error) |
| 22: | if (extra && extra.error) { |
| 23: | res.type = extra.error.name |
| 24: | res.message = extra.error.message |
| 25: | res.code = extra.error.code |
| 26: | || extra.error.type |
| 27: | res.errno = extra.error.errno |
| 28: | delete extra.error |
| 29: | } |
| 30: | if (caller.file) { |
| 31: | res.file = caller.file |
| 32: | res.line = +caller.line |
| 33: | res.column = +caller.column |
| 34: | } |
| 35: | res.stack = caller.stack |
| 36: | |
| 37: | res.name = message || "(unnamed assert)" |
| 38: | |
| 39: | if (extra) Object.keys(extra).forEach(function (k) { |
| 40: | if (!res.hasOwnProperty(k)) res[k] = extra[k] |
| 41: | }) |
| 42: | |
| 43: | // strings and objects are hard to diff by eye |
| 44: | if (!ok && |
| 45: | res.hasOwnProperty("found") && |
| 46: | res.hasOwnProperty("wanted") && |
| 47: | res.found !== res.wanted) { |
| 48: | if (typeof res.wanted !== typeof res.found || |
| 49: | typeof res.wanted === "object" && (!res.found || !res.wanted)) { |
| 50: | res.type = { found: typeof found |
| 51: | , wanted: typeof wanted } |
| 52: | } else if (typeof res.wanted === "string") { |
| 53: | res.diff = diffString(res.found, res.wanted) |
| 54: | } else if (typeof res.wanted === "object") { |
| 55: | res.diff = diffObject(res.found, res.wanted) |
| 56: | } |
| 57: | } |
| 58: | |
| 59: | //console.error("assert return", res) |
| 60: | |
| 61: | return res |
| 62: | } |
| 63: | assert.ok = assert |
| 64: | syns.ok = [ "true", "assert" ] |
| 65: | |
| 66: | |
| 67: | function notOk (ok, message, extra) { |
| 68: | return assert(!ok, message, extra) |
| 69: | } |
| 70: | assert.notOk = notOk |
| 71: | syns.notOk = [ "false", "notok" ] |
| 72: | |
| 73: | function error (er, message, extra) { |
| 74: | if (!er) { |
| 75: | // just like notOk(er) |
| 76: | return assert(!er, message, extra) |
| 77: | } |
| 78: | message = message || er.message |
| 79: | extra = extra || {} |
| 80: | extra.error = er |
| 81: | return assert.fail(message, extra) |
| 82: | } |
| 83: | assert.error = error |
| 84: | syns.error = [ "ifError", "ifErr", "iferror" ] |
| 85: | |
| 86: | |
| 87: | function pass (message, extra) { |
| 88: | return assert(true, message, extra) |
| 89: | } |
| 90: | assert.pass = pass |
| 91: | |
| 92: | function fail (message, extra) { |
| 93: | //console.error("assert.fail", [message, extra]) |
| 94: | //if (extra && extra.skip) return assert.skip(message, extra) |
| 95: | return assert(false, message, extra) |
| 96: | } |
| 97: | assert.fail = fail |
| 98: | |
| 99: | function skip (message, extra) { |
| 100: | //console.error("assert.skip", message, extra) |
| 101: | if (!extra) extra = {} |
| 102: | return { id: id ++, skip: true, name: message || "" } |
| 103: | } |
| 104: | assert.skip = skip |
| 105: | |
| 106: | function throws (fn, wanted, message, extra) { |
| 107: | if (typeof wanted === "string") { |
| 108: | extra = message |
| 109: | message = wanted |
| 110: | wanted = null |
| 111: | } |
| 112: | |
| 113: | if (extra && extra.skip) return assert.skip(message, extra) |
| 114: | |
| 115: | var found = null |
| 116: | try { |
| 117: | fn() |
| 118: | } catch (e) { |
| 119: | found = { name: e.name, message: e.message } |
| 120: | } |
| 121: | |
| 122: | extra = extra || {} |
| 123: | |
| 124: | extra.found = found |
| 125: | if (wanted) { |
| 126: | wanted = { name: wanted.name, message: wanted.message } |
| 127: | extra.wanted = wanted |
| 128: | } |
| 129: | |
| 130: | if (!message) { |
| 131: | message = "Expected to throw" |
| 132: | if (wanted) message += ": "+wanted.name + " " + wanted.message |
| 133: | } |
| 134: | |
| 135: | return (wanted) ? assert.similar(found, wanted, message, extra) |
| 136: | : assert.ok(found, message, extra) |
| 137: | } |
| 138: | assert.throws = throws |
| 139: | |
| 140: | |
| 141: | function doesNotThrow (fn, message, extra) { |
| 142: | if (extra && extra.skip) return assert.skip(message, extra) |
| 143: | var found = null |
| 144: | try { |
| 145: | fn() |
| 146: | } catch (e) { |
| 147: | found = {name: e.name, message: e.message} |
| 148: | } |
| 149: | message = message || "Should not throw" |
| 150: | |
| 151: | return assert.equal(found, null, message, extra) |
| 152: | } |
| 153: | assert.doesNotThrow = doesNotThrow |
| 154: | |
| 155: | |
| 156: | function equal (a, b, message, extra) { |
| 157: | if (extra && extra.skip) return assert.skip(message, extra) |
| 158: | extra = extra || {} |
| 159: | message = message || "should be equal" |
| 160: | extra.found = a |
| 161: | extra.wanted = b |
| 162: | return assert(a === b, message, extra) |
| 163: | } |
| 164: | assert.equal = equal |
| 165: | syns.equal = ["equals" |
| 166: | ,"isEqual" |
| 167: | ,"is" |
| 168: | ,"strictEqual" |
| 169: | ,"strictEquals"] |
| 170: | |
| 171: | |
| 172: | function equivalent (a, b, message, extra) { |
| 173: | if (extra && extra.skip) return assert.skip(message, extra) |
| 174: | var extra = extra || {} |
| 175: | message = message || "should be equivalent" |
| 176: | extra.found = a |
| 177: | extra.wanted = b |
| 178: | |
| 179: | if (Buffer.isBuffer(a) && Buffer.isBuffer(b)) { |
| 180: | return assert(bufferEqual(a, b), message, extra) |
| 181: | } else { |
| 182: | return assert(deepEqual(a, b), message, extra) |
| 183: | } |
| 184: | } |
| 185: | assert.equivalent = equivalent |
| 186: | syns.equivalent = ["isEquivalent" |
| 187: | ,"looseEqual" |
| 188: | ,"looseEquals" |
| 189: | ,"isDeeply" |
| 190: | ,"same" |
| 191: | ,"deepEqual" |
| 192: | ,"deepEquals"] |
| 193: | |
| 194: | |
| 195: | function inequal (a, b, message, extra) { |
| 196: | if (extra && extra.skip) return assert.skip(message, extra) |
| 197: | extra = extra || {} |
| 198: | message = message || "should not be equal" |
| 199: | extra.found = a |
| 200: | extra.doNotWant = b |
| 201: | return assert(a !== b, message, extra) |
| 202: | } |
| 203: | assert.inequal = inequal |
| 204: | syns.inequal = ["notEqual" |
| 205: | ,"notEquals" |
| 206: | ,"notStrictEqual" |
| 207: | ,"notStrictEquals" |
| 208: | ,"isNotEqual" |
| 209: | ,"isNot" |
| 210: | ,"not" |
| 211: | ,"doesNotEqual" |
| 212: | ,"isInequal"] |
| 213: | |
| 214: | |
| 215: | function inequivalent (a, b, message, extra) { |
| 216: | if (extra && extra.skip) return assert.skip(message, extra) |
| 217: | extra = extra || {} |
| 218: | message = message || "should not be equivalent" |
| 219: | extra.found = a |
| 220: | extra.doNotWant = b |
| 221: | |
| 222: | if (Buffer.isBuffer(a) && Buffer.isBuffer(b)) { |
| 223: | return assert(!bufferEqual(a, b), message, extra) |
| 224: | } else { |
| 225: | return assert(!deepEqual(a, b), message, extra) |
| 226: | } |
| 227: | } |
| 228: | assert.inequivalent = inequivalent |
| 229: | syns.inequivalent = ["notEquivalent" |
| 230: | ,"notDeepEqual" |
| 231: | ,"notDeeply" |
| 232: | ,"notSame" |
| 233: | ,"isNotDeepEqual" |
| 234: | ,"isNotDeeply" |
| 235: | ,"isNotEquivalent" |
| 236: | ,"isInequivalent"] |
| 237: | |
| 238: | function similar (a, b, message, extra, flip) { |
| 239: | if (extra && extra.skip) return assert.skip(message, extra) |
| 240: | // test that a has all the fields in b |
| 241: | message = message || "should be similar" |
| 242: | |
| 243: | if (typeof a === "string" && |
| 244: | (Object.prototype.toString.call(b) === "[object RegExp]")) { |
| 245: | extra = extra || {} |
| 246: | extra.pattern = b |
| 247: | extra.string = a |
| 248: | var ok = a.match(b) |
| 249: | extra.match = ok |
| 250: | if (flip) ok = !ok |
| 251: | return assert.ok(ok, message, extra) |
| 252: | } |
| 253: | |
| 254: | var isObj = assert(a && typeof a === "object", message, extra) |
| 255: | if (!isObj.ok) { |
| 256: | // not an object |
| 257: | if (a == b) isObj.ok = true |
| 258: | if (flip) isObj.ok = !isObj.ok |
| 259: | return isObj |
| 260: | } |
| 261: | |
| 262: | var eq = flip ? inequivalent : equivalent |
| 263: | return eq(selectFields(a, b), b, message, extra) |
| 264: | } |
| 265: | assert.similar = similar |
| 266: | syns.similar = ["isSimilar" |
| 267: | ,"has" |
| 268: | ,"hasFields" |
| 269: | ,"like" |
| 270: | ,"isLike"] |
| 271: | |
| 272: | function dissimilar (a, b, message, extra) { |
| 273: | if (extra && extra.skip) return assert.skip(message, extra) |
| 274: | message = message || "should be dissimilar" |
| 275: | return similar(a, b, message, extra, true) |
| 276: | } |
| 277: | assert.dissimilar = dissimilar |
| 278: | syns.dissimilar = ["unsimilar" |
| 279: | ,"notSimilar" |
| 280: | ,"unlike" |
| 281: | ,"isUnlike" |
| 282: | ,"notLike" |
| 283: | ,"isNotLike" |
| 284: | ,"doesNotHave" |
| 285: | ,"isNotSimilar" |
| 286: | ,"isDissimilar"] |
| 287: | |
| 288: | function type (thing, t, message, extra) { |
| 289: | if (extra && extra.skip) return assert.skip(message, extra) |
| 290: | var name = t |
| 291: | if (typeof name === "function") name = name.name || "(anonymous ctor)" |
| 292: | //console.error("name=%s", name) |
| 293: | message = message || "type is "+name |
| 294: | var type = typeof thing |
| 295: | //console.error("type=%s", type) |
| 296: | if (!thing && type === "object") type = "null" |
| 297: | if (type === "object" && t !== "object") { |
| 298: | if (typeof t === "function") { |
| 299: | //console.error("it is a function!") |
| 300: | extra = extra || {} |
| 301: | extra.found = Object.getPrototypeOf(thing).constructor.name |
| 302: | extra.wanted = name |
| 303: | //console.error(thing instanceof t, name) |
| 304: | return assert.ok(thing instanceof t, message, extra) |
| 305: | } |
| 306: | |
| 307: | //console.error("check prototype chain") |
| 308: | // check against classnames or objects in prototype chain, as well. |
| 309: | // type(new Error("asdf"), "Error") |
| 310: | // type(Object.create(foo), foo) |
| 311: | var p = thing |
| 312: | while (p = Object.getPrototypeOf(p)) { |
| 313: | if (p === t || p.constructor && p.constructor.name === t) { |
| 314: | type = name |
| 315: | break |
| 316: | } |
| 317: | } |
| 318: | } |
| 319: | //console.error(type, name, type === name) |
| 320: | return assert.equal(type, name, message, extra) |
| 321: | } |
| 322: | assert.type = type |
| 323: | syns.type = ["isa"] |
| 324: | |
| 325: | // synonyms are helpful. |
| 326: | Object.keys(syns).forEach(function (c) { |
| 327: | syns[c].forEach(function (s) { |
| 328: | Object.defineProperty(assert, s, { value: assert[c], enumerable: false }) |
| 329: | }) |
| 330: | }) |
| 331: | |
| 332: | // helpers below |
| 333: | |
| 334: | function selectFields (a, b) { |
| 335: | // get the values in A of the fields in B |
| 336: | var ret = Array.isArray(b) ? [] : {} |
| 337: | Object.keys(b).forEach(function (k) { |
| 338: | if (!a.hasOwnProperty(k)) return |
| 339: | var v = b[k] |
| 340: | , av = a[k] |
| 341: | if (v && av && typeof v === "object" && typeof av === "object" |
| 342: | && !(v instanceof Date) |
| 343: | && !(v instanceof RegExp) |
| 344: | && !(v instanceof String) |
| 345: | && !(v instanceof Boolean) |
| 346: | && !(v instanceof Number) |
| 347: | && !(Array.isArray(v))) { |
| 348: | ret[k] = selectFields(av, v) |
| 349: | } else ret[k] = av |
| 350: | }) |
| 351: | return ret |
| 352: | } |
| 353: | |
| 354: | function sortObject (obj) { |
| 355: | if (typeof obj !== 'object' || Array.isArray(obj) || obj === null) { |
| 356: | return obj |
| 357: | } |
| 358: | |
| 359: | return Object.keys(obj).sort().reduce(function (acc, key) { |
| 360: | acc[key] = sortObject(obj[key]) |
| 361: | return acc |
| 362: | }, {}) |
| 363: | } |
| 364: | |
| 365: | function stringify (a) { |
| 366: | return JSON.stringify(sortObject(a), (function () { |
| 367: | var seen = [] |
| 368: | , keys = [] |
| 369: | return function (key, val) { |
| 370: | var s = seen.indexOf(val) |
| 371: | if (s !== -1) { |
| 372: | return "[Circular: "+keys[s]+"]" |
| 373: | } |
| 374: | if (val && typeof val === "object" || typeof val === "function") { |
| 375: | seen.push(val) |
| 376: | keys.push(val["!"] || val.name || key || "<root>") |
| 377: | if (typeof val === "function") { |
| 378: | return val.toString().split(/\n/)[0] |
| 379: | } else if (typeof val.toUTCString === "function") { |
| 380: | return val.toUTCString() |
| 381: | } |
| 382: | } |
| 383: | return val |
| 384: | }})()) |
| 385: | } |
| 386: | |
| 387: | function diffString (f, w) { |
| 388: | if (w === f) return null |
| 389: | var p = 0 |
| 390: | , l = w.length |
| 391: | while (p < l && w.charAt(p) === f.charAt(p)) p ++ |
| 392: | w = stringify(w).substr(1).replace(/"$/, "") |
| 393: | f = stringify(f).substr(1).replace(/"$/, "") |
| 394: | return diff(f, w, p) |
| 395: | } |
| 396: | |
| 397: | function diffObject (f, w) { |
| 398: | return difflet({ indent : 2, comment : true }).compare(w, f) |
| 399: | } |
| 400: | |
| 401: | function diff (f, w, p) { |
| 402: | if (w === f) return null |
| 403: | var i = p || 0 // it's going to be at least p. JSON can only be bigger. |
| 404: | , l = w.length |
| 405: | while (i < l && w.charAt(i) === f.charAt(i)) i ++ |
| 406: | var pos = Math.max(0, i - 20) |
| 407: | w = w.substr(pos, 40) |
| 408: | f = f.substr(pos, 40) |
| 409: | var pointer = i - pos |
| 410: | return "FOUND: "+f+"\n" |
| 411: | + "WANTED: "+w+"\n" |
| 412: | + (new Array(pointer + 9).join(" ")) |
| 413: | + "^ (at position = "+p+")" |
| 414: | } |
| 415: | |
| 416: | function getCaller (er) { |
| 417: | // get the first file/line that isn't this file. |
| 418: | if (!er) er = new Error |
| 419: | var stack = er.stack || "" |
| 420: | stack = stack.split(/\n/) |
| 421: | for (var i = 1, l = stack.length; i < l; i ++) { |
| 422: | var s = stack[i].match(/\(([^):]+):([0-9]+):([0-9]+)\)$/) |
| 423: | if (!s) continue |
| 424: | var file = s[1] |
| 425: | , line = +s[2] |
| 426: | , col = +s[3] |
| 427: | if (file.indexOf(__dirname) === 0) continue |
| 428: | if (file.match(/tap-test\/test.js$/)) continue |
| 429: | else break |
| 430: | } |
| 431: | var res = {} |
| 432: | if (file && file !== __filename && !file.match(/tap-test\/test.js$/)) { |
| 433: | res.file = file |
| 434: | res.line = line |
| 435: | res.column = col |
| 436: | } |
| 437: | |
| 438: | res.stack = stack.slice(1).map(function (s) { |
| 439: | return s.replace(/^\s*at\s*/, "") |
| 440: | }) |
| 441: | |
| 442: | return res |
| 443: | } |
