UNPKG

3.46 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('\n').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 deduped = withDuplicates.filter(function (line, ix) {
60 var hasPrior = line === stripped && withDuplicates[ix - 1] === stripped;
61 return !hasPrior;
62 });
63
64 return deduped.join('\n').replace(
65 // Handle stack trace variation in Node v0.8
66 /at(:?) Test\.(?:module\.exports|tap\.test\.err\.code)/g,
67 'at$1 Test.<anonymous>'
68 );
69};
70
71module.exports.runProgram = function (folderName, fileName, cb) {
72 var result = {
73 stdout: null,
74 stderr: null,
75 exitCode: 0
76 };
77 var ps = spawn(process.execPath, [
78 path.join(__dirname, folderName, fileName)
79 ]);
80
81 ps.stdout.pipe(concat(function (stdoutRows) {
82 result.stdout = stdoutRows;
83 }));
84 ps.stderr.pipe(concat(function (stderrRows) {
85 result.stderr = stderrRows;
86 }));
87
88 ps.on('exit', function (code) {
89 result.exitCode = code;
90 cb(result);
91 });
92};