UNPKG

3.92 kBJavaScriptView Raw
1'use strict';
2
3var path = require('path');
4var spawn = require('child_process').spawn;
5var concat = require('concat-stream');
6var yaml = require('js-yaml');
7
8module.exports.getDiag = function (body) {
9 var yamlStart = body.indexOf(' ---');
10 var yamlEnd = body.indexOf(' ...\n');
11 var diag = body.slice(yamlStart, yamlEnd).split('\n').map(function (line) {
12 return line.slice(2);
13 }).join('\n');
14
15 // The stack trace and at variable will vary depending on where the code
16 // is run, so just strip it out.
17 var withStack = yaml.safeLoad(diag);
18 delete withStack.stack;
19 delete withStack.at;
20 return withStack;
21};
22
23// There are three challenges associated with checking the stack traces included
24// in errors:
25// 1) The base checkout directory of tape might change. Because stack traces
26// include absolute paths, the stack traces will change depending on the
27// checkout path. We handle this by replacing the base test directory with a
28// placeholder $TEST variable and the package root with a placeholder
29// $TAPE variable.
30// 2) Line positions within the file might change. We handle this by replacing
31// line and column markers with placeholder $LINE and $COL "variables"
32// a) node 0.8 does not provide nested eval line numbers, so we remove them
33// 3) Stacks themselves change frequently with refactoring. We've even run into
34// issues with node library refactorings "breaking" stack traces. Most of
35// these changes are irrelevant to the tests themselves. To counter this, we
36// strip out all stack frames that aren't directly under our test directory,
37// and replace them with placeholders.
38
39var stripChangingData = function (line) {
40 var withoutTestDir = line.replace(__dirname, '$TEST');
41 var withoutPackageDir = withoutTestDir.replace(path.dirname(__dirname), '$TAPE');
42 var withoutPathSep = withoutPackageDir.replace(new RegExp('\\' + path.sep, 'g'), '/');
43 var withoutLineNumbers = withoutPathSep.replace(/:\d+:\d+/g, ':$LINE:$COL');
44 var withoutNestedLineNumbers = withoutLineNumbers.replace(/, <anonymous>:\$LINE:\$COL\)$/, ')');
45 return withoutNestedLineNumbers;
46};
47
48module.exports.stripFullStack = function (output) {
49 var stripped = ' [... stack stripped ...]';
50 var withDuplicates = output.split(/\r?\n/g).map(stripChangingData).map(function (line) {
51 var m = line.match(/[ ]{8}at .*\((.*)\)/);
52
53 if (m && m[1].slice(0, 5) !== '$TEST') {
54 return stripped;
55 }
56 return line;
57 });
58
59 var withoutInternals = withDuplicates.filter(function (line) {
60 return !line.match(/ \(node:[^)]+\)$/);
61 });
62
63 var deduped = withoutInternals.filter(function (line, ix) {
64 var hasPrior = line === stripped && withDuplicates[ix - 1] === stripped;
65 return !hasPrior;
66 });
67
68 return deduped.join('\n').replace(
69 // Handle stack trace variation in Node v0.8
70 /at(:?) Test\.(?:module\.exports|tap\.test\.err\.code)/g,
71 'at$1 Test.<anonymous>'
72 ).replace(
73 // Handle stack trace variation in Node v0.8
74 /at(:?) (Test\.)?tap\.test\.test\.skip/g,
75 'at$1 $2<anonymous>'
76 ).replace(
77 // Handle stack trace variation in Node v0.8
78 /(\[\.\.\. stack stripped \.\.\.\]\r?\n *at) <anonymous> \(([^)]+)\)/g,
79 '$1 $2'
80 ).split(/\r?\n/g);
81};
82
83module.exports.runProgram = function (folderName, fileName, cb) {
84 var result = {
85 stdout: null,
86 stderr: null,
87 exitCode: 0
88 };
89 var ps = spawn(process.execPath, [
90 path.join(__dirname, folderName, fileName)
91 ]);
92
93 ps.stdout.pipe(concat(function (stdoutRows) {
94 result.stdout = stdoutRows;
95 }));
96 ps.stderr.pipe(concat(function (stderrRows) {
97 result.stderr = stderrRows;
98 }));
99
100 ps.on('exit', function (code) {
101 result.exitCode = code;
102 cb(result);
103 });
104};