Skip to content

Commit

Permalink
Merge pull request #387 from fongandrew/master
Browse files Browse the repository at this point in the history
Check added stack trace parts for filename match
  • Loading branch information
ljharb committed Sep 13, 2017
2 parents 0bb42ee + bf5a750 commit cc69501
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 26 deletions.
74 changes: 51 additions & 23 deletions lib/test.js
Expand Up @@ -217,37 +217,65 @@ Test.prototype._assert = function assert (ok, opts) {
var e = new Error('exception');
var err = (e.stack || '').split('\n');
var dir = __dirname + path.sep;

for (var i = 0; i < err.length; i++) {
var m = /^[^\s]*\s*\bat\s+(.+)/.exec(err[i]);
/*
Stack trace lines may resemble one of the following. We need
to should correctly extract a function name (if any) and
path / line no. for each line.
at myFunction (/path/to/file.js:123:45)
at myFunction (/path/to/file.other-ext:123:45)
at myFunction (/path to/file.js:123:45)
at myFunction (C:\path\to\file.js:123:45)
at myFunction (/path/to/file.js:123)
at Test.<anonymous> (/path/to/file.js:123:45)
at Test.bound [as run] (/path/to/file.js:123:45)
at /path/to/file.js:123:45
Regex has three parts. First is non-capturing group for 'at '
(plus anything preceding it).
/^(?:[^\s]*\s*\bat\s+)/
Second captures function call description (optional). This is
not necessarily a valid JS function name, but just what the
stack trace is using to represent a function call. It may look
like `<anonymous>` or 'Test.bound [as run]'.
For our purposes, we assume that, if there is a function
name, it's everything leading up to the first open
parentheses (trimmed) before our pathname.
/(?:(.*)\s+\()?/
Last part captures file path plus line no (and optional
column no).
/((?:\/|[A-Z]:\\)[^:\)]+:(\d+)(?::(\d+))?)/
*/
var re = /^(?:[^\s]*\s*\bat\s+)(?:(.*)\s+\()?((?:\/|[A-Z]:\\)[^:\)]+:(\d+)(?::(\d+))?)/
var m = re.exec(err[i]);

if (!m) {
continue;
}

var callDescription = m[1] || '<anonymous>';
var filePath = m[2];

var s = m[1].split(/\s+/);
var filem = /((?:\/|[A-Z]:\\)[^:\s]+:(\d+)(?::(\d+))?)/.exec(s[1]);
if (!filem) {
filem = /((?:\/|[A-Z]:\\)[^:\s]+:(\d+)(?::(\d+))?)/.exec(s[2]);

if (!filem) {
filem = /((?:\/|[A-Z]:\\)[^:\s]+:(\d+)(?::(\d+))?)/.exec(s[3]);

if (!filem) {
continue;
}
}
}

if (filem[1].slice(0, dir.length) === dir) {
if (filePath.slice(0, dir.length) === dir) {
continue;
}

// Function call description may not (just) be a function name.
// Try to extract function name by looking at first "word" only.
res.functionName = callDescription.split(/s+/)[0]
res.file = filePath;
res.line = Number(m[3]);
if (m[4]) res.column = Number(m[4]);

res.functionName = s[0];
res.file = filem[1];
res.line = Number(filem[2]);
if (filem[3]) res.column = filem[3];

res.at = m[1];
res.at = callDescription + ' (' + filePath + ')';
break;
}
}
Expand Down
49 changes: 49 additions & 0 deletions test/anonymous-fn.js
@@ -0,0 +1,49 @@
var tape = require('../');
var tap = require('tap');
var concat = require('concat-stream');

var stripFullStack = require('./common').stripFullStack;
var testWrapper = require('./anonymous-fn/test-wrapper');

tap.test('inside anonymous functions', function (tt) {
tt.plan(1);

var test = tape.createHarness();
var tc = function (rows) {
var body = stripFullStack(rows.toString('utf8'));

// Handle stack trace variation in Node v0.8
body = body.replace(
'at Test.module.exports',
'at Test.<anonymous>'
);

tt.same(body, [
'TAP version 13',
'# wrapped test failure',
'not ok 1 fail',
' ---',
' operator: fail',
' at: <anonymous> ($TEST/anonymous-fn.js:$LINE:$COL)',
' stack: |-',
' Error: fail',
' [... stack stripped ...]',
' at $TEST/anonymous-fn.js:$LINE:$COL',
' at Test.<anonymous> ($TEST/anonymous-fn/test-wrapper.js:$LINE:$COL)',
' [... stack stripped ...]',
' ...',
'',
'1..1',
'# tests 1',
'# pass 0',
'# fail 1'
].join('\n') + '\n');
};

test.createStream().pipe(concat(tc));

test('wrapped test failure', testWrapper(function (t) {
t.fail('fail');
t.end();
}));
});
16 changes: 16 additions & 0 deletions test/anonymous-fn/test-wrapper.js
@@ -0,0 +1,16 @@
// Example of wrapper function that would invoke tape
module.exports = function (testCase) {
return function(t) {
setUp();
testCase(t);
tearDown();
};
}

function setUp() {
// ... example ...
}

function tearDown() {
// ... example ...
}
2 changes: 1 addition & 1 deletion test/exit.js
Expand Up @@ -52,7 +52,7 @@ tap.test('exit fail', function (t) {
' operator: deepEqual',
' expected: [ [ 1, 2, [ 3, 4444 ] ], [ 5, 6 ] ]',
' actual: [ [ 1, 2, [ 3, 4 ] ], [ 5, 6 ] ]',
' at: Test.<anonymous> ($TEST/exit/fail.js:$LINE:$COL)',
' at: <anonymous> ($TEST/exit/fail.js:$LINE:$COL)',
' stack: |-',
' Error: should be equivalent',
' [... stack stripped ...]',
Expand Down
2 changes: 1 addition & 1 deletion test/fail.js
Expand Up @@ -22,7 +22,7 @@ tap.test('array test', function (tt) {
' operator: deepEqual',
' expected: [ [ 1, 2, [ 3, 4444 ] ], [ 5, 6 ] ]',
' actual: [ [ 1, 2, [ 3, 4 ] ], [ 5, 6 ] ]',
' at: Test.<anonymous> ($TEST/fail.js:$LINE:$COL)',
' at: <anonymous> ($TEST/fail.js:$LINE:$COL)',
' stack: |-',
' Error: should be equivalent',
' [... stack stripped ...]',
Expand Down
40 changes: 40 additions & 0 deletions test/has spaces.js
@@ -0,0 +1,40 @@
var tape = require('../');
var tap = require('tap');
var concat = require('concat-stream');

var stripFullStack = require('./common').stripFullStack;

tap.test('array test', function (tt) {
tt.plan(1);

var test = tape.createHarness({ exit : false });
var tc = function (rows) {
tt.same(stripFullStack(rows.toString('utf8')), [
'TAP version 13',
'# fail',
'not ok 1 this should fail',
' ---',
' operator: fail',
' at: Test.<anonymous> ($TEST/has spaces.js:$LINE:$COL)',
' stack: |-',
' Error: this should fail',
' [... stack stripped ...]',
' at Test.<anonymous> ($TEST/has spaces.js:$LINE:$COL)',
' [... stack stripped ...]',
' ...',
'',
'1..1',
'# tests 1',
'# pass 0',
'# fail 1',
''
].join('\n'));
};

test.createStream().pipe(concat(tc));

test('fail', function (t) {
t.fail('this should fail');
t.end();
});
});
2 changes: 1 addition & 1 deletion test/too_many.js
Expand Up @@ -22,7 +22,7 @@ tap.test('array test', function (tt) {
' operator: fail',
' expected: 3',
' actual: 4',
' at: Test.<anonymous> ($TEST/too_many.js:$LINE:$COL)',
' at: <anonymous> ($TEST/too_many.js:$LINE:$COL)',
' stack: |-',
' Error: plan != count',
' [... stack stripped ...]',
Expand Down

0 comments on commit cc69501

Please sign in to comment.