This commit is contained in:
Yamozha
2021-04-02 02:24:13 +03:00
parent c23950b545
commit 7256d79e2c
31493 changed files with 3036630 additions and 0 deletions

View File

@ -0,0 +1,86 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails oncall+js_symbolication
* @format
*/
'use strict';
const SourceMetadataMapConsumer = require('../SourceMetadataMapConsumer.js');
describe('SourceMetadataMapConsumer', () => {
it('ignores metadata beyond the range of the sources array', () => {
const consumer = new SourceMetadataMapConsumer({
version: 3,
mappings: '',
sources: ['foo'],
names: [],
x_facebook_sources: [
null,
[
{
mappings: '',
names: [],
},
],
],
});
expect(consumer.toArray(['foo'])).toEqual([null]);
});
it('ignores metadata for a null source', () => {
const consumer = new SourceMetadataMapConsumer({
version: 3,
mappings: '',
sources: ['foo', null],
names: [],
x_facebook_sources: [
[
{
mappings: '',
names: [],
},
],
],
});
expect(consumer.toArray(['foo', null])).toEqual([
[
{
mappings: '',
names: [],
},
],
null,
]);
});
it('accepts metadata blob with null function map', () => {
const consumer = new SourceMetadataMapConsumer({
version: 3,
mappings: 'AAAA',
sources: ['foo'],
names: [],
x_facebook_sources: [[null]],
});
expect(consumer.functionNameFor({line: 1, column: 0, source: 'foo'})).toBe(
null,
);
});
it('accepts null metadata blob', () => {
const consumer = new SourceMetadataMapConsumer({
version: 3,
mappings: 'AAAA',
sources: ['foo'],
names: [],
x_facebook_sources: [null],
});
expect(consumer.functionNameFor({line: 1, column: 0, source: 'foo'})).toBe(
null,
);
});
});

View File

@ -0,0 +1,72 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails oncall+js_symbolication
* @format
*/
'use strict';
const Symbolication = require('../Symbolication.js');
const fs = require('fs');
const path = require('path');
const {SourceMapConsumer} = require('source-map');
const resolve = fileName => path.resolve(__dirname, '__fixtures__', fileName);
const read = fileName => fs.readFileSync(resolve(fileName), 'utf8');
const TESTFILE_MAP = resolve('testfile.js.map');
const UNKNOWN_MODULE_IDS = {
segmentId: 0,
localId: undefined,
};
test('symbolicating with context created from source map object', async () => {
const map = JSON.parse(read(TESTFILE_MAP));
const context = Symbolication.createContext(SourceMapConsumer, map);
expect(
Symbolication.getOriginalPositionFor(1, 161, UNKNOWN_MODULE_IDS, context),
).toMatchInlineSnapshot(`
Object {
"column": 20,
"line": 18,
"name": null,
"source": "thrower.js",
}
`);
});
test('symbolicating with context created from source map string', async () => {
const map = read(TESTFILE_MAP);
const context = Symbolication.createContext(SourceMapConsumer, map);
expect(
Symbolication.getOriginalPositionFor(1, 161, UNKNOWN_MODULE_IDS, context),
).toMatchInlineSnapshot(`
Object {
"column": 20,
"line": 18,
"name": null,
"source": "thrower.js",
}
`);
});
test('symbolicating without specifying module IDs', async () => {
const map = read(TESTFILE_MAP);
const context = Symbolication.createContext(SourceMapConsumer, map);
expect(Symbolication.getOriginalPositionFor(1, 161, null, context))
.toMatchInlineSnapshot(`
Object {
"column": 20,
"line": 18,
"name": null,
"source": "thrower.js",
}
`);
});

View File

@ -0,0 +1 @@
{"version":3,"sources":["/js/react-native-github/Libraries/BatchedBridge/BatchedBridge.js"],"names":["BatchedBridge","require","Object","defineProperty","global","configurable","value","module","exports"],"mappings":"AAUA;;AAIA,IAAMA,aAAa,GAAG,KAAAC,OAAA,mEAAA,GAAtB;AAQAC,MAAM,CAACC,cAAPD,CAAsBE,MAAtBF,EAA8B,mBAA9BA,EAAmD;AACjDG,EAAAA,YAAY,EAAE,IADmC;AAEjDC,EAAAA,KAAK,EAAEN;AAF0C,CAAnDE;AAKAK,MAAM,CAACC,OAAPD,GAAiBP,aAAjBO"}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,3 @@
someFunc@foo.js:4:0
someOtherFunc@subdir1/bar.js:255:6
fn@fileThatDoesntExist.js:10:20

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,39 @@
{
"callstack": [
{
"CJSModuleOffset": 0,
"FunctionID": 50,
"ByteCodeOffset": 58,
"SourceURL": "/a/b/c/main.jsbundle"
},
{
"CJSModuleOffset": 0,
"FunctionID": 290,
"ByteCodeOffset": 3,
"SourceURL": "/a/b/c/main.jsbundle"
},
{
"CJSModuleOffset": 0,
"FunctionID": 3,
"ByteCodeOffset": 4,
"SourceURL": "seg-1.js"
},
{
"CJSModuleOffset": 0,
"FunctionID": 3,
"ByteCodeOffset": 4,
"SourceURL": "seg-16.js"
},
{
"CJSModuleOffset": 0,
"FunctionID": 3,
"ByteCodeOffset": 4,
"SourceURL": "seg-1.js",
"StackFrameRegOffs": 1912,
"SourceLocation": "file.js:23:14"
},
{
"NativeCode": true
}
]
}

View File

@ -0,0 +1,33 @@
{
"callstack": [
{
"CJSModuleOffset": 0,
"FunctionID": 270,
"ByteCodeOffset": 12,
"SourceURL": "Fb4aBundle.js"
},
{
"CJSModuleOffset": 51,
"FunctionID": 3,
"ByteCodeOffset": 4,
"SourceURL": "Fb4aBundle.js"
},
{
"CJSModuleOffset": 51,
"FunctionID": 3,
"ByteCodeOffset": 4,
"SourceURL": "seg-5.js"
},
{
"CJSModuleOffset": 51,
"FunctionID": 3,
"ByteCodeOffset": 4,
"SourceURL": "Fb4aBundle.js",
"StackFrameRegOffs": 1219,
"SourceLocation": "file.js:12:11"
},
{
"NativeCode": true
}
]
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
{"functionId":1,"location":{"virtualOffset":22},"usage":[]}
{"functionId":2,"location":{"virtualOffset":99},"usage":[]}

View File

@ -0,0 +1,42 @@
{
"stackFrames": {
"1": {
"funcVirtAddr": "0",
"offset": "0",
"name": "global+0",
"category": "JavaScript"
},
"2": {
"funcVirtAddr": "0",
"offset": "55",
"name": "global+55",
"category": "JavaScript"
},
"3": {
"funcVirtAddr": "67",
"offset": "16",
"name": "entryPoint+16",
"category": "JavaScript",
"parent": 2
},
"4": {
"funcVirtAddr": "89",
"offset": "0",
"name": "helper+0",
"category": "JavaScript",
"parent": 3
},
"5": {
"funcVirtAddr": "89",
"offset": "146",
"name": "helper+146",
"category": "JavaScript",
"parent": 3
},
"6": {
"name": "[Native]4367295792",
"category": "Native",
"parent": 5
}
}
}

View File

@ -0,0 +1,15 @@
{
"version": 3,
"sources": [
"temp/bench.js"
],
"x_facebook_sources": [
[
{
"names": ["<global>","entryPoint","helper"],
"mappings": "AAA,uBCC,JCI,RFe"
}
]
],
"mappings": "AACC,uDAmBU,YAnBY,gBACd,MAGU,wFAKA,WACT,iBACC,IAAD,YACU,cAAA,YAHY,eAAb;"
}

View File

@ -0,0 +1,2 @@
{"version":3,"sources":["thrower.js"],"names":["notCalled","alsoNotCalled","throws6a","Error","throws6","throws6b","throws4","obj","throws5","apply","this","throws2","throws3","throws1","throws0","t","eval","o","forEach","call","arguments","arg","err","print","stack"],"mappings":"CAAA,WAGE,SAASA,YACP,SAASC,IACPA,IAEFA,IACAD,YAIF,SAASE,WACP,MAAM,IAAIC,MAAM,wBAGlB,SAASC,UACP,MAAM,IAAID,MAAM,wBAGlB,SAASE,WACP,MAAM,IAAIF,MAAM,wBAYlB,SAASG,UACPC,IAAIC,EAAQC,MAAMC,MAAON,QAASA,QAASA,UAG7C,SAASO,UACPJ,IAAIK,IAGN,SAASC,UAELF,UAIJ,SAASG,UACPD,UAxBF,IAAIN,KACFQ,EAAS,WACPC,KAAK,eAEPC,EAAS,cACJC,QAAQC,KAAKC,UAAW,SAASC,GAAOA,QAsB/C,IACEP,UACA,MAAOQ,GACPC,MAAMD,EAAIE,QAtDd"}

View File

@ -0,0 +1,13 @@
TypeError: undefined is not a function
at throws6 (/js/thrower.min.js:1:161)
at /js/thrower.min.js:1:488
at forEach ([native code])
at o (/js/thrower.min.js:1:464)
at throws4 (/js/thrower.min.js:1:276)
at eval (eval at /js/thrower.min.js:1:451)
at t (/js/thrower.min.js:1:420)
at throws2 (/js/thrower.min.js:1:333)
at throws1 (/js/thrower.min.js:1:362)
at throws0 (/js/thrower.min.js:1:391)
at /js/thrower.min.js:1:506
at global code (/js/thrower.min.js:1:534)

View File

@ -0,0 +1 @@
{"version":3,"sources":["foo.js"],"names":[],"mappings":"K,CACC,K,CACC,K"}

View File

@ -0,0 +1,4 @@
JS_0000_xxxxxxxxxxxxxxxxxxxxxx (unknown) 373
JS_0001_xxxxxxxxxxxxxxxxxxxxxx garbage 296
JS_0002_xxxxxxxxxxxxxxxxxxxxxx name 1234
JS_0003_xxxxxxxxxxxxxxxxxxxxxx (unknown) 5678

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,5 @@
Object.throwSmthInner@seg-1_2.js:6:13
Object.throwSmth@seg-1_1.js:8:18
makeItThrowInner@1.js:15:9
makeItThrow@1.js:11:5
1.js:6:7

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,13 @@
throws6@thrower.min.js:1:161
thrower.min.js:1:488
forEach@[native code]
o@thrower.min.js:1:464
throws4@thrower.min.js:1:276
eval code
eval@[native code]
t@thrower.min.js:1:420
throws2@thrower.min.js:1:333
throws1@thrower.min.js:1:362
throws0@thrower.min.js:1:391
thrower.min.js:1:506
global code@thrower.min.js:1:534

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,5 @@
Object.throwSmthInner@bundle.js:427:174
Object.throwSmth@bundle.js:426:200
makeItThrowInner@bundle.js:425:311
makeItThrow@bundle.js:425:253
unknown@bundle.js:425:206

View File

@ -0,0 +1,257 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`directory context symbolicating a stack trace 1`] = `
"/js/react-native-github/Libraries/BatchedBridge/BatchedBridge.js:23:Object
/js/react-native-github/Libraries/BatchedBridge/MessageQueue.js:89:null
fileThatDoesntExist.js:10:null
"
`;
exports[`symbolicating a hermes stack trace 1`] = `
Array [
Object {
"column": 21,
"functionName": "columns.forEach$argument_0",
"line": 480,
"name": "rows",
"source": "/js/node_modules/react-native/Libraries/polyfills/console.js",
},
Object {
"column": 8,
"functionName": "setEnabled",
"line": 101,
"name": "_enabled",
"source": "/js/react-native-github/Libraries/Performance/Systrace.js",
},
Object {
"column": 2,
"functionName": "getValue",
"line": 13,
"name": null,
"source": "/js/RKJSModules/Apps/HermesModulesTest/HMTLazyFetched.js",
},
Object {
"column": null,
"functionName": null,
"line": null,
"name": null,
"source": null,
},
Object {
"column": 2,
"functionName": "getValue",
"line": 13,
"name": null,
"source": "/js/RKJSModules/Apps/HermesModulesTest/HMTLazyFetched.js",
},
Object {
"NativeCode": true,
},
]
`;
exports[`symbolicating a hermes stack trace CJS 1`] = `
Array [
Object {
"column": 36,
"functionName": "result.clearExceptTimespans",
"line": 160,
"name": null,
"source": "/js/react-native-github/Libraries/Utilities/createPerformanceLogger.js",
},
Object {
"column": 2,
"functionName": "getValue",
"line": 13,
"name": null,
"source": "/js/RKJSModules/Apps/HermesModulesTest/HMTLazyFetched.js",
},
Object {
"column": 2,
"functionName": "getValue",
"line": 13,
"name": null,
"source": "/js/RKJSModules/Apps/HermesModulesTest/HMTLazyFetched.js",
},
Object {
"column": 2,
"functionName": "getValue",
"line": 13,
"name": null,
"source": "/js/RKJSModules/Apps/HermesModulesTest/HMTLazyFetched.js",
},
Object {
"NativeCode": true,
},
]
`;
exports[`symbolicating a profiler map 1`] = `
"JS_0000_xxxxxxxxxxxxxxxxxxxxxx throws0::thrower.js:48:11
JS_0001_xxxxxxxxxxxxxxxxxxxxxx throws6::thrower.js:35:38
JS_0002_xxxxxxxxxxxxxxxxxxxxxx name::thrower.js:1:0
JS_0003_xxxxxxxxxxxxxxxxxxxxxx (unknown)::thrower.js:1:0"
`;
exports[`symbolicating a stack trace 1`] = `
"thrower.js:18:null
thrower.js:30:arg
null:null:null
thrower.js:30:arguments
thrower.js:35:this
eval code
null:null:null
thrower.js:27:null
thrower.js:39:throws3
thrower.js:44:throws2
thrower.js:49:throws1
thrower.js:53:throws0
global thrower.js:1:null
"
`;
exports[`symbolicating a stack trace ignoring a function map 1`] = `
"/js/RKJSModules/segmented/biz.js:5:null
/js/RKJSModules/segmented/glo.js:7:throwSmthInner
/js/RKJSModules/bar.js:14:throwSmth
/js/RKJSModules/bar.js:10:makeItThrowInner
/js/RKJSModules/bar.js:5:makeItThrow
"
`;
exports[`symbolicating a stack trace in Node format 1`] = `
"TypeError: undefined is not a function
at throws6 (thrower.js:18:null)
at thrower.js:30:arg
at forEach (null:null:null)
at o (thrower.js:30:arguments)
at throws4 (thrower.js:35:this)
at eval (eval at thrower.js:30:forEach)
at t (thrower.js:27:null)
at throws2 (thrower.js:39:throws3)
at throws1 (thrower.js:44:throws2)
at throws0 (thrower.js:49:throws1)
at thrower.js:53:throws0
at global code (thrower.js:1:null)
"
`;
exports[`symbolicating a stack trace with a function map 1`] = `
"/js/RKJSModules/segmented/biz.js:5:module.exports.throwSmthInner
/js/RKJSModules/segmented/glo.js:7:module.exports.throwSmth
/js/RKJSModules/bar.js:14:makeItThrowInner
/js/RKJSModules/bar.js:10:makeItThrow
/js/RKJSModules/bar.js:5:import.then$argument_0
"
`;
exports[`symbolicating a stack trace with a segmented RAM bundle map 1`] = `
"/js/RKJSModules/segmented/biz.js:5:null
/js/RKJSModules/segmented/glo.js:7:throwSmthInner
/js/RKJSModules/bar.js:14:throwSmth
/js/RKJSModules/bar.js:10:makeItThrowInner
/js/RKJSModules/bar.js:5:makeItThrow
"
`;
exports[`symbolicating an attribution file 1`] = `
"{\\"functionId\\":1,\\"location\\":{\\"file\\":\\"thrower.js\\",\\"line\\":4,\\"column\\":11},\\"usage\\":[]}
{\\"functionId\\":2,\\"location\\":{\\"file\\":\\"thrower.js\\",\\"line\\":14,\\"column\\":14},\\"usage\\":[]}
"
`;
exports[`symbolicating an attribution file with 1-based column output 1`] = `
"{\\"functionId\\":1,\\"location\\":{\\"file\\":\\"thrower.js\\",\\"line\\":4,\\"column\\":12},\\"usage\\":[]}
{\\"functionId\\":2,\\"location\\":{\\"file\\":\\"thrower.js\\",\\"line\\":14,\\"column\\":15},\\"usage\\":[]}
"
`;
exports[`symbolicating with a cpuprofile 1`] = `
Object {
"stackFrames": Object {
"1": Object {
"category": "JavaScript",
"funcVirtAddr": "0",
"name": "<global>(temp/bench.js:2:1)",
"offset": "0",
},
"2": Object {
"category": "JavaScript",
"funcVirtAddr": "0",
"name": "<global>(temp/bench.js:21:11)",
"offset": "55",
},
"3": Object {
"category": "JavaScript",
"funcVirtAddr": "67",
"name": "entryPoint(temp/bench.js:3:9)",
"offset": "16",
"parent": 2,
},
"4": Object {
"category": "JavaScript",
"funcVirtAddr": "89",
"name": "helper(temp/bench.js:6:19)",
"offset": "0",
"parent": 3,
},
"5": Object {
"category": "JavaScript",
"funcVirtAddr": "89",
"name": "helper(temp/bench.js:14:20)",
"offset": "146",
"parent": 3,
},
"6": Object {
"category": "Native",
"name": "[Native]4367295792",
"parent": 5,
},
},
}
`;
exports[`symbolicating with a cpuprofile ignoring a function map 1`] = `
Object {
"stackFrames": Object {
"1": Object {
"category": "JavaScript",
"funcVirtAddr": "0",
"name": "global+0(temp/bench.js:2:1)",
"offset": "0",
},
"2": Object {
"category": "JavaScript",
"funcVirtAddr": "0",
"name": "global+55(temp/bench.js:21:11)",
"offset": "55",
},
"3": Object {
"category": "JavaScript",
"funcVirtAddr": "67",
"name": "entryPoint+16(temp/bench.js:3:9)",
"offset": "16",
"parent": 2,
},
"4": Object {
"category": "JavaScript",
"funcVirtAddr": "89",
"name": "helper+0(temp/bench.js:6:19)",
"offset": "0",
"parent": 3,
},
"5": Object {
"category": "JavaScript",
"funcVirtAddr": "89",
"name": "helper+146(temp/bench.js:14:20)",
"offset": "146",
"parent": 3,
},
"6": Object {
"category": "Native",
"name": "[Native]4367295792",
"parent": 5,
},
},
}
`;

View File

@ -0,0 +1,352 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails oncall+js_symbolication
* @format
*/
'use strict';
const fs = require('fs');
const path = require('path');
const symbolicate = require('../symbolicate');
const {PassThrough} = require('stream');
const resolve = fileName => path.resolve(__dirname, '__fixtures__', fileName);
const read = fileName => fs.readFileSync(resolve(fileName), 'utf8');
const execute = async (args: Array<string>, stdin: string): Promise<string> => {
const streams = {
stdin: new PassThrough(),
stdout: new PassThrough(),
stderr: new PassThrough(),
};
const stdout = [];
const output = ['Process failed with the following output:\n======\n'];
streams.stdout.on('data', data => {
output.push(data);
stdout.push(data);
});
streams.stderr.on('data', data => {
output.push(data);
});
if (stdin) {
streams.stdin.write(stdin);
streams.stdin.end();
}
const code = await symbolicate(args, streams);
if (code !== 0) {
output.push('======\n');
throw new Error(output.join(''));
}
return stdout.join('');
};
afterAll(() => {
try {
fs.unlinkSync(resolve('testfile.temp.cpuprofile'));
} catch (e) {}
});
const TESTFILE_MAP = resolve('testfile.js.map');
const WITH_FUNCTION_MAP_MAP = resolve('with-function-map.js.map');
const TESTFILE_RAM_MAP = resolve('testfile.ram.js.map');
const HERMES_MAP = resolve('hermes.js.hbc.map');
const HERMES_MAP_CJS = resolve('hermescjs.js.hbc.map');
test('symbolicating a hermes stack trace', async () => {
const output = JSON.parse(
await execute(
[HERMES_MAP, '--hermes-crash'],
read('hermesStackTrace.json'),
),
);
expect(output).toMatchSnapshot();
});
test('symbolicating a hermes stack trace with input-line-start and input-column-start', async () => {
const output0Based = JSON.parse(
await execute(
[
HERMES_MAP,
'--hermes-crash',
'--input-line-start',
'0',
'--input-column-start',
'0',
],
read('hermesStackTrace.json'),
),
);
const output1Based = JSON.parse(
await execute(
[
HERMES_MAP,
'--hermes-crash',
'--input-line-start',
'1',
'--input-column-start',
'1',
],
read('hermesStackTrace.json'),
),
);
const outputNoFlag = JSON.parse(
await execute(
[HERMES_MAP, '--hermes-crash'],
read('hermesStackTrace.json'),
),
);
expect(outputNoFlag).toMatchObject(output0Based);
expect(outputNoFlag).toMatchObject(output1Based);
});
test('symbolicating a hermes stack trace CJS', async () => {
const output = JSON.parse(
await execute(
[HERMES_MAP_CJS, '--hermes-crash'],
read('hermesStackTraceCJS.json'),
),
);
expect(output).toMatchSnapshot();
});
test('symbolicating a stack trace', async () =>
await expect(
execute([TESTFILE_MAP], read('testfile.stack')),
).resolves.toMatchSnapshot());
test('symbolicating a stack trace in Node format', async () =>
await expect(
execute([TESTFILE_MAP], read('testfile.node.stack')),
).resolves.toMatchSnapshot());
test('symbolicating a single entry', async () =>
await expect(execute([TESTFILE_MAP, '1', '161'])).resolves.toEqual(
'thrower.js:18:null\n',
));
test('symbolicating a single entry with 0-based line output', async () =>
await expect(
execute([TESTFILE_MAP, '1', '161', '--output-line-start', '0']),
).resolves.toEqual('thrower.js:17:null\n'));
test('symbolicating a single entry with 1-based column input', async () =>
await expect(
execute([TESTFILE_MAP, '1', '161', '--input-column-start', '1']),
).resolves.toEqual('thrower.js:18:Error\n'));
test('symbolicating a single entry with 0-based line input', async () =>
await expect(
execute([TESTFILE_MAP, '0', '161', '--input-line-start', '0']),
).resolves.toEqual('thrower.js:18:null\n'));
test('symbolicating a single entry with an out of range column', async () =>
await expect(execute([TESTFILE_MAP, '1', '1000000'])).resolves.toEqual(
'thrower.js:1:null\n',
));
test('symbolicating a single entry with out of range line', async () =>
await expect(execute([TESTFILE_MAP, '1000000', '161'])).resolves.toEqual(
'null:null:null\n',
));
test('symbolicating a sectioned source map', async () =>
await expect(
execute([resolve('testfile.sectioned.js.map'), '353.js', '1', '72']),
).resolves.toEqual('nested-thrower.js:6:start\n'));
test('symbolicating a profiler map', async () =>
await expect(
execute([TESTFILE_MAP, resolve('testfile.profmap')]),
).resolves.toMatchSnapshot());
test('symbolicating an attribution file', async () =>
await expect(
execute(
[TESTFILE_MAP, '--attribution'],
read('testfile.attribution.input'),
),
).resolves.toMatchSnapshot());
test('symbolicating an attribution file with 1-based column output', async () =>
await expect(
execute(
[TESTFILE_MAP, '--attribution', '--output-column-start', '1'],
read('testfile.attribution.input'),
),
).resolves.toMatchSnapshot());
describe('symbolicating an attribution file specifying unmapped offsets', () => {
const attribute = async obj =>
(await execute(
[resolve('testfile.partial.js.map'), '--attribution'],
JSON.stringify(obj) + '\n',
))
.split('\n')
.filter(Boolean)
.map(line => JSON.parse(line));
test('Lookup falls before all mappings with no non-null mapping in range', async () =>
await expect(
attribute({
functionId: 0,
location: {virtualOffset: 0, bytecodeSize: 5},
usage: [],
}),
).resolves.toMatchInlineSnapshot(`
Array [
Object {
"functionId": 0,
"location": Object {
"column": null,
"file": null,
"line": null,
},
"usage": Array [],
},
]
`));
test('Lookup finds a null mapping and falls back to a non-null mapping in range', async () =>
await expect(
attribute({
functionId: 1,
location: {virtualOffset: 5, bytecodeSize: 2},
usage: [],
}),
).resolves.toMatchInlineSnapshot(`
Array [
Object {
"functionId": 1,
"location": Object {
"column": 1,
"file": "foo.js",
"line": 2,
},
"usage": Array [],
},
]
`));
test('Lookup finds a null mapping with no bytecodeSize specified', async () =>
await expect(
attribute({
functionId: 1,
location: {virtualOffset: 5},
usage: [],
}),
).resolves.toMatchInlineSnapshot(`
Array [
Object {
"functionId": 1,
"location": Object {
"column": null,
"file": null,
"line": null,
},
"usage": Array [],
},
]
`));
test('Lookup finds a null mapping with no non-null mapping in range', async () =>
await expect(
attribute({
functionId: 2,
location: {virtualOffset: 11, bytecodeSize: 1},
usage: [],
}),
).resolves.toMatchInlineSnapshot(`
Array [
Object {
"functionId": 2,
"location": Object {
"column": null,
"file": null,
"line": null,
},
"usage": Array [],
},
]
`));
test('Lookup finds the last mapping and it is null', async () =>
await expect(
attribute({
functionId: 3,
location: {virtualOffset: 17, bytecodeSize: 1},
usage: [],
}),
).resolves.toMatchInlineSnapshot(`
Array [
Object {
"functionId": 3,
"location": Object {
"column": null,
"file": null,
"line": null,
},
"usage": Array [],
},
]
`));
});
test('symbolicating with a cpuprofile', async () => {
fs.copyFileSync(
resolve('testfile.cpuprofile'),
resolve('testfile.temp.cpuprofile'),
);
await execute([
resolve('testfile.cpuprofile.map'),
resolve('testfile.temp.cpuprofile'),
]);
expect(JSON.parse(read('testfile.temp.cpuprofile'))).toMatchSnapshot();
});
test('symbolicating with a cpuprofile ignoring a function map', async () => {
fs.copyFileSync(
resolve('testfile.cpuprofile'),
resolve('testfile.temp.cpuprofile'),
);
await execute([
'--no-function-names',
resolve('testfile.cpuprofile.map'),
resolve('testfile.temp.cpuprofile'),
]);
expect(JSON.parse(read('testfile.temp.cpuprofile'))).toMatchSnapshot();
});
test('symbolicating a stack trace with a function map', async () =>
await expect(
execute([WITH_FUNCTION_MAP_MAP], read('with-function-map.stack')),
).resolves.toMatchSnapshot());
test('symbolicating a stack trace with a segmented RAM bundle map', async () =>
await expect(
execute([TESTFILE_RAM_MAP], read('testfile.ram.stack')),
).resolves.toMatchSnapshot());
test('symbolicating a stack trace ignoring a function map', async () =>
await expect(
execute(
['--no-function-names', WITH_FUNCTION_MAP_MAP],
read('with-function-map.stack'),
),
).resolves.toMatchSnapshot());
describe('directory context', () => {
test('symbolicating a stack trace', async () =>
await expect(
execute([resolve('directory')], read('directory/test.stack')),
).resolves.toMatchSnapshot());
});