assert.js (5920B)
1 // // based on node assert, original notice: 2 // // NB: The URL to the CommonJS spec is kept just for tradition. 3 // // node-assert has evolved a lot since then, both in API and behavior. 4 // 5 // // http://wiki.commonjs.org/wiki/Unit_Testing/1.0 6 // // 7 // // THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! 8 // // 9 // // Originally from narwhal.js (http://narwhaljs.org) 10 // // Copyright (c) 2009 Thomas Robinson <280north.com> 11 // // 12 // // Permission is hereby granted, free of charge, to any person obtaining a copy 13 // // of this software and associated documentation files (the 'Software'), to 14 // // deal in the Software without restriction, including without limitation the 15 // // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 16 // // sell copies of the Software, and to permit persons to whom the Software is 17 // // furnished to do so, subject to the following conditions: 18 // // 19 // // The above copyright notice and this permission notice shall be included in 20 // // all copies or substantial portions of the Software. 21 // // 22 // // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 // // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 // // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 // // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 // // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 27 // // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 29 "use strict"; 30 31 var regex = /\s*function\s+([^\(\s]*)\s*/; 32 33 var functionsHaveNames = (function () { 34 return function foo() {}.name === "foo"; 35 }()); 36 37 function assert(value, message) { 38 if (!value) { 39 fail(value, true, message, "==", assert.ok); 40 } 41 } 42 43 assert.equal = function equal(actual, expected, message) { 44 if (actual != expected) { 45 fail(actual, expected, message, "==", assert.equal); 46 } 47 }; 48 49 assert.throws = function (block, error, message) { 50 _throws(true, block, error, message); 51 }; 52 53 function _throws(shouldThrow, block, expected, message) { 54 var actual; 55 56 if (typeof block !== "function") { 57 throw new TypeError(`"block" argument must be a function`); 58 } 59 60 if (typeof expected === "string") { 61 message = expected; 62 expected = null; 63 } 64 65 actual = _tryBlock(block); 66 67 message = (expected?.name ? " (" + expected.name + ")." : ".") + 68 (message ? " " + message : "."); 69 70 if (shouldThrow && !actual) { 71 fail(actual, expected, "Missing expected exception" + message); 72 } 73 74 var userProvidedMessage = typeof message === "string"; 75 var isUnwantedException = !shouldThrow && isError(actual); 76 var isUnexpectedException = !shouldThrow && actual && !expected; 77 78 if ((isUnwantedException && 79 userProvidedMessage && 80 expectedException(actual, expected)) || 81 isUnexpectedException) { 82 fail(actual, expected, "Got unwanted exception" + message); 83 } 84 85 if ((shouldThrow && actual && expected && 86 !expectedException(actual, expected)) || (!shouldThrow && actual)) { 87 throw actual; 88 } 89 } 90 91 function fail(actual, expected, message, operator, stackStartFunction) { 92 throw new assert.AssertionError({ 93 message: message, 94 actual: actual, 95 expected: expected, 96 operator: operator, 97 stackStartFunction: stackStartFunction 98 }); 99 } 100 101 assert.fail = fail; 102 103 assert.AssertionError = function AssertionError(options) { 104 this.name = "AssertionError"; 105 this.actual = options.actual; 106 this.expected = options.expected; 107 this.operator = options.operator; 108 if (options.message) { 109 this.message = options.message; 110 this.generatedMessage = false; 111 } else { 112 this.message = getMessage(this); 113 this.generatedMessage = true; 114 } 115 var stackStartFunction = options.stackStartFunction || fail; 116 if (Error.captureStackTrace) { 117 Error.captureStackTrace(this, stackStartFunction); 118 } else { 119 // non v8 browsers so we can have a stacktrace 120 var err = new Error(); 121 if (err.stack) { 122 var out = err.stack; 123 124 // try to strip useless frames 125 var fn_name = getName(stackStartFunction); 126 var idx = out.indexOf("\n" + fn_name); 127 if (idx >= 0) { 128 // once we have located the function frame 129 // we need to strip out everything before it (and its line) 130 var next_line = out.indexOf("\n", idx + 1); 131 out = out.substring(next_line + 1); 132 } 133 134 this.stack = out; 135 } 136 } 137 }; 138 139 function expectedException(actual, expected) { 140 if (!actual || !expected) { 141 return false; 142 } 143 144 if (Object.prototype.toString.call(expected) == "[object RegExp]") { 145 return expected.test(actual); 146 } 147 148 try { 149 if (actual instanceof expected) { 150 return true; 151 } 152 } catch (e) { 153 // Ignore. The instanceof check doesn"t work for arrow functions. 154 } 155 156 if (Error.isPrototypeOf(expected)) { 157 return false; 158 } 159 160 return expected.call({}, actual) === true; 161 } 162 163 function _tryBlock(block) { 164 var error; 165 try { 166 block(); 167 } catch (e) { 168 error = e; 169 } 170 return error; 171 } 172 173 function isError(obj) { 174 return obj instanceof Error; 175 } 176 177 function isFunction(value) { 178 return typeof value === "function"; 179 } 180 181 function getMessage(self) { 182 return truncate(inspect(self.actual), 128) + " " + 183 self.operator + " " + 184 truncate(inspect(self.expected), 128); 185 } 186 187 function getName(func) { 188 if (!isFunction(func)) { 189 return null; 190 } 191 if (functionsHaveNames) { 192 return func.name; 193 } 194 var str = func.toString(); 195 var match = str.match(regex); 196 return match?.[1]; 197 } 198 199 function truncate(s, n) { 200 if (typeof s === "string") { 201 return s.length < n ? s : s.slice(0, n); 202 } 203 return s; 204 } 205 206 function inspect(something) { 207 if (functionsHaveNames || !isFunction(something)) { 208 throw new Error(something); 209 } 210 var rawname = getName(something); 211 var name = rawname ? ": " + rawname : ""; 212 return "[Function" + name + "]"; 213 } 214 215 exports.assert = assert;