-
Notifications
You must be signed in to change notification settings - Fork 6
/
test-node-vm.js
279 lines (214 loc) · 6.95 KB
/
test-node-vm.js
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
const fs = require('fs');
const path = require('path');
const { Session } = require('inspector');
const { promisify } = require('util');
const { fileURLToPath } = require('url');
const { Script, createContext } = require('vm');
const EC = require('eight-colors');
const MCR = require('../');
const checkSnapshot = require('./check-snapshot.js');
const coverageOptions = {
// logging: 'debug',
// watermarks: [60, 90],
reports: [
'v8',
'raw',
// 'text',
// ['html', {
// subdir: 'html'
// }],
// 'console-summary',
['console-details', {
// skipPercent: 80,
metrics: ['bytes', 'lines']
}]
],
name: 'My V8 Node VM Coverage Report',
assetsPath: '../assets',
// lcov: true,
// filter files if test with mcr CLI
entryFilter: (entry) => {
if (entry.url.includes('node_modules')) {
return false;
}
if (entry.url.includes('monocart-coverage-reports/lib')) {
return false;
}
return true;
},
outputDir: './docs/node-vm',
onEnd: function(coverageResults) {
checkSnapshot(coverageResults);
}
};
// ==================================================================
// start node.js coverage
const startV8Coverage = async () => {
const session = new Session();
session.connect();
const postSession = promisify(session.post.bind(session));
await postSession('Profiler.enable');
await postSession('Profiler.startPreciseCoverage', {
callCount: true,
detailed: true
});
return postSession;
};
const takeV8Coverage = async (postSession) => {
const { result } = await postSession('Profiler.takePreciseCoverage');
return result;
};
const stopV8Coverage = async (postSession) => {
await postSession('Profiler.stopPreciseCoverage');
await postSession('Profiler.disable');
};
// ==================================================================
const collectV8Coverage = async (postSession, files) => {
let coverageList = await takeV8Coverage(postSession);
if (!coverageList) {
return;
}
// console.log(coverageList.map((entry) => entry.url));
// filter node internal files
coverageList = coverageList.filter((entry) => entry.url && entry.url.startsWith('file:'));
coverageList = coverageList.filter((entry) => !entry.url.includes('test-node-vm.js'));
// attach source content
coverageList.forEach((item) => {
const filePath = fileURLToPath(item.url);
if (fs.existsSync(filePath)) {
item.source = fs.readFileSync(filePath).toString('utf8');
} else {
// vm source file
const vmFile = files[filePath];
if (vmFile) {
item.source = vmFile.source;
item.scriptOffset = vmFile.scriptOffset;
} else {
EC.logRed('not found file', filePath);
}
}
});
// console.log(coverageList.map((it) => it.url));
// add fake case
const appItem = coverageList.find((it) => it.url.endsWith('app.js'));
const fakeItem = {
... appItem,
fake: true,
source: appItem.source.replace(/\S/g, '*'),
url: `${appItem.url}.fake.js`
};
coverageList.push(fakeItem);
// const sItem = coverageList.find((it) => it.url.endsWith('typescript.js'));
// // sItem.source = sItem.source.replace(/\S/g, '*');
// sItem.sourceMap = JSON.parse(fs.readFileSync('./test/mock/istanbul/branches.typescript.js.map').toString('utf-8'));
// sItem.sourceMap.sourcesContent = [fs.readFileSync('./test/mock/istanbul/branches.typescript.ts').toString('utf-8')];
// fs.writeFileSync('./test/mock/istanbul/branches.typescript.js1.map', JSON.stringify(sItem.sourceMap));
// sItem.fake = true;
console.log('add node.js coverage ...');
await MCR(coverageOptions).add(coverageList);
};
const EVAL_RESULT_VARIABLE = 'Object.<anonymous>';
const wrapCodeInModuleWrapper = (scriptSource) => {
const args = [
'module',
'exports',
'require',
'__dirname',
'__filename'
];
const startStr = `({"${EVAL_RESULT_VARIABLE}":function(${args.join(',')}){`;
const scriptOffset = startStr.length;
const endStr = '\n}});';
return {
code: startStr + scriptSource + endStr,
scriptOffset
};
};
const createScriptFromCode = (scriptSource, filename) => {
const { code, scriptOffset } = wrapCodeInModuleWrapper(scriptSource);
const script = new Script(code, {
columnOffset: scriptOffset,
filename
});
return {
script,
scriptOffset
};
};
const generate = async () => {
// clean cache first
await MCR(coverageOptions).cleanCache();
// =====================================================
const postSession = await startV8Coverage();
// import lib after v8 coverage started
// test lib app
// var source1 = fs.readFileSync(path.res)
const sourceCode = `const {
foo, bar, app
} = require('./test/mock/node/lib/app.js');
// require('./test/mock/istanbul/branches.typescript.js');
if (require.a) {
console.log("uncovered block a");
}
if (require.s) console.log("statement")
const uncoveredFunction = () => {
const list = [1, 2, 3, 4, 5];
list.forEach((v) => {
console.log(v);
});
};
const uncoveredArrowFunction = () => require.v
const uncovered = () => {
// this is uncovered function in vm, test scriptOffset
console.log("uncovered");
}
foo();
bar();
app();
function fun(a) {
if (a) {console.log(a);}
}
if (require.b) {
console.log("uncovered block b");
}
fun();
function useless() {
console.log("useless");
}
/** the sourcemap url comments here ########################################################################################################### */
`;
const filename = path.resolve('my-vm-filename.js');
const { script, scriptOffset } = createScriptFromCode(sourceCode, filename);
const files = {};
files[filename] = {
source: sourceCode,
scriptOffset
};
const log = console.log;
console.log = () => {};
const context = createContext({});
const runScript = script.runInContext(context, {
});
const compiledFunction = runScript[EVAL_RESULT_VARIABLE];
compiledFunction.call(
module.exports,
// module object
module,
// module exports
module.exports,
// require implementation
module.require,
// __dirname
module.path,
// __filename
module.filename
);
// console.log(files);
console.log = log;
await collectV8Coverage(postSession, files);
await stopV8Coverage(postSession);
// =====================================================
const coverageResults = await MCR(coverageOptions).generate();
console.log('test-node-vm coverage reportPath', EC.magenta(coverageResults.reportPath));
};
generate();