101938e6278b1c7db3cfb784990b29d10a0e10e8.svn-base
3.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
'use strict'
const path = require('path')
const Module = require('module')
const fs = require('fs')
const binpath = path.resolve(__dirname, '../bin')
const stack = require('./stack.js')
const diff = require('diff')
const yaml = require('tap-yaml')
const {format, strict} = require('tcompare')
const hasOwn = (obj, key) =>
Object.prototype.hasOwnProperty.call(obj, key)
const tapDir = path.resolve(__dirname, '..')
const cleanDiag = object => {
const res = { ...object }
if (hasOwn(res, 'stack') && !hasOwn(res, 'at'))
res.at = stack.parseLine(res.stack.split('\n')[0])
// don't print locations in tap itself, that's almost never useful
const file = res.at && res.at.file && path.resolve(res.at.file)
if (file &&
(file.indexOf(__dirname) === 0 || file.indexOf(binpath) === 0) &&
(process.cwd() !== tapDir || process.env.TAP_DEV_SHORTSTACK === '1') &&
process.env.TAP_DEV_LONGSTACK !== '1') {
delete res.at
}
if (file && res.at && res.at.file && res.at.line && !res.source) {
const content = (() => {
try {
return fs.readFileSync(file, 'utf8')
} catch (er) {
}
})()
if (content) {
const lines = content.split('\n')
if (res.at.line <= lines.length) {
const startLine = Math.max(res.at.line - 2, 0)
const endLine = Math.min(res.at.line + 2, lines.length)
const caret = res.at.column &&
res.at.column <= lines[res.at.line - 1].length
? [new Array(res.at.column).join('-') + '^'] : []
const context = lines.slice(startLine, res.at.line).concat(caret)
.concat(lines.slice(res.at.line, endLine))
const csplit = context.join('\n').trimRight()
if (csplit)
res.source = csplit + '\n'
}
}
}
// show a line by line string diff
// diff the yaml, to make it more humane, especially
// when strings or buffers are very large or multi-line
if (res.found && res.wanted && res.found !== res.wanted && !res.diff) {
const f = res.found
const w = res.wanted
if (typeof f === 'string' && typeof w === 'string')
res.diff = diff.createTwoFilesPatch('expected', 'actual', w + '\n', f + '\n')
.replace(/^=+\n/, '')
else if (f && w && typeof f === 'object' && typeof w === 'object') {
const s = strict(f, w)
if (!s.match)
res.diff = s.diff
else
res.note = 'object identities differ'
} else {
// some mixed stringly bits
// XXX tcompare needs better string diffs
const ff = format(f)
const fw = format(w)
const fs = (typeof f === 'string' ? f : ff) + '\n'
const ws = (typeof w === 'string' ? w : fw) + '\n'
/* istanbul ignore else - impossible without bug in tcompare */
if (fw !== ff)
res.diff = diff.createTwoFilesPatch('expected', 'actual', ws, fs)
.replace(/^=+\n/, '')
else
res.note = 'object identities differ'
}
if (res.diff === '--- expected\n+++ actual\n')
delete res.diff
if (res.diff) {
delete res.found
delete res.wanted
}
}
for (const [key, value] of Object.entries(res)) {
if (key === 'todo' ||
key === 'time' ||
/^_?tapChild/.test(key) ||
key === 'childId' ||
/^tapStream/.test(key) ||
/^tapMochaTest/.test(key) ||
key === 'cb' ||
key === 'name' ||
key === 'indent' ||
key === 'skip' ||
key === 'bail' ||
key === 'grep' ||
key === 'grepInvert' ||
key === 'only' ||
key === 'diagnostic' ||
key === 'buffered' ||
key === 'parent' ||
key === 'domainEmitter' ||
key === 'domainThrew' ||
key === 'domain' ||
key === 'at' && !value ||
key === 'stack' && !value)
delete res[key]
}
return res
}
module.exports = cleanDiag