function getErrMessage(call) { const filename = call.getFileName(); const line = call.getLineNumber() - 1; const column = call.getColumnNumber() - 1; const identifier = `${filename}${line}${column}`; if (errorCache.has(identifier)) { return errorCache.get(identifier); } // Skip Node.js modules! if (filename.endsWith('.js') && NativeModule.exists(filename.slice(0, -3))) { errorCache.set(identifier, undefined); return; } let fd, message; try { fd = openSync(filename, 'r', 0o666); const buffers = getBuffer(fd, line); const code = Buffer.concat(buffers).toString('utf8'); // Lazy load acorn. const { parseExpressionAt } = require('internal/deps/acorn/dist/acorn'); const nodes = parseExpressionAt(code, column); // Node type should be "CallExpression" and some times // "SequenceExpression". const node = nodes.type === 'CallExpression' ? nodes : nodes.expressions[0]; const name = node.callee.name; // Calling `ok` with .apply or .call is uncommon but we use a simple // safeguard nevertheless. if (name !== 'apply' && name !== 'call') { // Only use `assert` and `assert.ok` to reference the "real API" and // not user defined function names. const ok = name === 'ok' ? '.ok' : ''; const args = node.arguments; message = code .slice(args[0].start, args[args.length - 1].end) .replace(escapeSequencesRegExp, escapeFn); if (EOL === '\r\n') { message = message.replace(/\r\n/g, '\n'); } message = 'The expression evaluated to a falsy value:' + `\n\n assert${ok}(${message})\n`; } // Make sure to always set the cache! No matter if the message is // undefined or not errorCache.set(identifier, message); return message; } catch (e) { // Invalidate cache to prevent trying to read this part again. errorCache.set(identifier, undefined); } finally { if (fd !== undefined) closeSync(fd); } }
// Do not try to check Node.js modules. { const e = new EventEmitter(); e.on('hello', assert); let threw = false; try { e.emit('hello', false); } catch (err) { const frames = err.stack.split('\n'); const [, filename, line, column] = frames[1].match(/\((.+):(\d+):(\d+)\)/); // Reset the cache to check again const size = errorCache.size; errorCache.delete(`${filename}${line - 1}${column - 1}`); assert.strictEqual(errorCache.size, size - 1); const data = `${'\n'.repeat(line - 1)}${' '.repeat(column - 1)}` + 'ok(failed(badly));'; try { writeFileSync(filename, data); assert.throws( () => e.emit('hello', false), { message: 'false == true' } ); threw = true; } finally { unlinkSync(filename); }