diff --git a/test/inspect-test.js b/test/inspect-test.js index 24374ef7..ec88f61a 100644 --- a/test/inspect-test.js +++ b/test/inspect-test.js @@ -4,368 +4,557 @@ const tape = require('tape'); const common = require('./common'); -tape('v8 inspect', (t) => { - t.timeoutAfter(15000); - - const sess = common.Session.create('inspect-scenario.js'); - - sess.waitBreak((err) => { - t.error(err); - sess.send('v8 bt'); - }); - - let that = null; - let fn = null; +// , + 'null': { + re: /\[0\]=(0x[0-9a-f]+):/, + desc: '[0] null element' + }, + // [4]=0x000039e38cc822d1:, + 'undefined': { + re: /\[4\]=(0x[0-9a-f]+):/, + desc: '[4] undefined element' + }, + // [23]=0x000003df9cbe83d9:, + 'regexp': { + re:/\[23\]=(0x[0-9a-f]+):<(?:Object: RegExp|JSRegExp source=\/regexp\/)>/, + desc: '[23] RegExp element', + validator(t, sess, addresses, name, cb) { + const address = addresses[name]; + sess.send(`v8 inspect ${address}`); + + sess.linesUntil(/}>/, (err, lines) => { + if (err) return cb(err); + lines = lines.join('\n'); + t.ok(/source=\/regexp\//.test(lines) || + /\.source=[^\n]*/.test(lines), + 'hashmap[23] should have the correct regexp.source'); + cb(null); + }); + } + }, + // [25]=0x000036eccf7c0b79:} + 'arrow': { + re: /\[25\]=(0x[0-9a-f]+):<(function: c.hashmap).*>/, + desc: '[25] Arrow Function element', + validator: (t, sess, addresses, name, cb) => { + const address = addresses[name]; + sess.send(`v8 inspect -s ${address}`); + + sess.linesUntil(/^>/, (err, lines) => { + if (err) return cb(err); + lines = lines.join('\n'); + // Include 'source:' and '>' to act as boundaries. (Avoid + // passing if the whole file it displayed instead of just + // the function we want.) + const arrowSource = 'source:\n' + + 'function c.hashmap.(anonymous function)(a,b)=>{a+b}\n' + + '>'; + + t.ok(lines.includes(arrowSource), + 'hashmap[25] should have the correct function source'); + cb(null); + }); + } + }, + // properties { + // .some-key=, + 'smi': { + re: /.some-key=/, + desc: '.some-key property' + }, + // .other-key=0x000036eccf7bd9c1:, + 'string': { + re: /.other-key=[^\n]*/, + desc: '.other-key property' + }, + // .cons-string=0x000003df9cbe7579:, + 'cons-string': { + re: /.cons-string=(0x[0-9a-f]+):/, + desc: '.cons-string ConsString property', + validators: [(t, sess, addresses, name, cb) => { + const address = addresses[name]; + sess.send(`v8 inspect -F ${address}`); + + sess.linesUntil(/">/, (err, lines) => { + if (err) return cb(err); + lines = lines.join('\n'); + const expected = 'this could be a bit smaller, but v8 wants big str.' + + 'this could be a bit smaller, but v8 wants big str.'; + t.ok(lines.includes(expected), + 'hashmap.cons-string should have the right content'); + cb(null); + }); + }, (t, sess, addresses, name, cb) => { + const address = addresses[name]; + sess.send(`v8 inspect --string-length 20 ${address}`); + + sess.linesUntil(/">/, (err, lines) => { + if (err) return cb(err); + lines = lines.join('\n'); + const expected = 'this could be a bit ...'; + t.ok(lines.includes(expected), + '--string-length should truncate the string'); + cb(null); + }); + }] + }, + // .internalized-string=0x000036eccf7bda89:, + 'internalized-string': { + re: /.internalized-string=(0x[0-9a-f]+):/, + desc: '.internalized-string Internalized String property' + }, + // .thin-string=0x000003df9cbe7621:, + 'thin-string': { + re: /.thin-string=(0x[0-9a-f]+):/, + desc: '.thin-string ThinString property', + validator(t, sess, addresses, name, cb) { + const address = addresses[name]; + sess.send(`v8 inspect ${address}`); + + sess.linesUntil(/">/, (err, lines) => { + if (err) return cb(err); + lines = lines.join('\n'); + t.ok( + /0x[0-9a-f]+:/.test(lines), + 'hashmap.thin-string should have the right content'); + cb(null); + }); + } + }, + // .externalized-string=0x000036eccf7bdb41:, + 'externalized-string': { + re: /.externalized-string=(0x[0-9a-f]+):/, + desc: '.externalized-string ExternalString property' + }, + // .sliced-externalized-string=0x000003df9cbe77e9:, + 'sliced-externalized-string': { + re: /.sliced-externalized-string=(0x[0-9a-f]+):/, + desc: '.sliced-externalized-string Sliced ExternalString property' + }, + // .array=0x000003df9cbe7919:, + 'array': { + re: /.array=(0x[0-9a-f]+):/, + desc: '.array JSArray property', + validator(t, sess, addresses, name, cb) { + const address = addresses[name]; + sess.send(`v8 inspect ${address}`); + + sess.linesUntil(/}>/, (err, lines) => { + if (err) return cb(err); + lines = lines.join('\n'); + t.ok(lines.includes(', + 'long-array': { + re: /.long-array=(0x[0-9a-f]+):/, + desc: '.long-array JSArray property', + validator(t, sess, addresses, name, cb) { + const address = addresses[name]; + sess.send(`v8 inspect --array-length 10 ${address}`); + + sess.linesUntil(/}>/, (err, lines) => { + if (err) return cb(err); + lines = lines.join('\n'); + t.ok(lines.includes('}>$/.test(lines), + 'hashmap.long-array should have the right content'); + cb(null); + }); + } + }, + // .array-buffer=0x000003df9cbe7df1:, + 'array-buffer': { + re: new RegExp('.array-buffer=(0x[0-9a-f]+):' + + ''), + desc: '.array-buffer JSArrayBuffer property', + validators: [(t, sess, addresses, name, cb) => { + const address = addresses[name]; + sess.send(`v8 inspect ${address}`); + + sess.linesUntil(/\]>/, (err, lines) => { + if (err) return cb(err); + lines = lines.join('\n'); + const re = new RegExp( + '0x[0-9a-f]+:' + + ''); + t.ok(re.test(lines), + 'hashmap.array-buffer should have the right content'); + cb(null); + }); + }, (t, sess, addresses, name, cb) => { + const address = addresses[name]; + sess.send(`v8 inspect --array-length 1 ${address}`); + + sess.linesUntil(/\]>/, (err, lines) => { + if (err) return cb(err); + lines = lines.join('\n'); + const re = new RegExp( + '0x[0-9a-f]+:' + + ''); + t.ok(re.test(lines), + 'hashmap.array-buffer should have the right content with ' + + '--array-length 1'); + cb(null); + }); + }] + }, + // .uint8-array=0x0000393071133e59:, + // OR + // .uint8-array=0x000003df9cbe7eb9:, + 'uint8-array': { + re: new RegExp('.uint8-array=(0x[0-9a-f]+):'), + desc: '.uint8-array JSArrayBufferView property', + optional: { + re: /.uint8-array=0x[0-9a-f]+:/, + reason: 'can be neutered' + }, + validators: [(t, sess, addresses, name, cb) => { + const address = addresses[name]; + sess.send(`v8 inspect ${address}`); + + sess.linesUntil(/\]>/, (err, lines) => { + if (err) return cb(err); + lines = lines.join('\n'); + const re = new RegExp( + '0x[0-9a-f]+:' + + ''); + t.ok(re.test(lines), + 'hashmap.uint8-array should have the right content'); + cb(null); + }); + }, (t, sess, addresses, name, cb) => { + const address = addresses[name]; + sess.send(`v8 inspect --array-length 1 ${address}`); + + sess.linesUntil(/\]>/, (err, lines) => { + if (err) return cb(err); + lines = lines.join('\n'); + const re = new RegExp( + '0x[0-9a-f]+:' + + ''); + t.ok(re.test(lines), + 'hashmap.uint8-array should have the right content with ' + + '--array-length 1'); + cb(null); + }); + }] + }, + // .buffer=0x000003df9cbe8231: + 'buffer': { + re: new RegExp('.buffer=(0x[0-9a-f]+):'), + desc: '.buffer JSArrayBufferView property', + validators: [(t, sess, addresses, name, cb) => { + const address = addresses[name]; + sess.send(`v8 inspect ${address}`); + + sess.linesUntil(/\]>/, (err, lines) => { + if (err) return cb(err); + lines = lines.join('\n'); + const re = new RegExp( + '0x[0-9a-f]+:' + + ''); + t.ok(re.test(lines), + 'hashmap.uint8-array should have the right content'); + cb(null); + }); + }, (t, sess, addresses, name, cb) => { + const address = addresses[name]; + sess.send(`v8 inspect --array-length 1 ${address}`); + + sess.linesUntil(/\]>/, (err, lines) => { + if (err) return cb(err); + lines = lines.join('\n'); + const re = new RegExp( + '0x[0-9a-f]+:' + + ''); + t.ok(re.test(lines), + 'hashmap.buffer should have the right content with ' + + '--array-length 1'); + cb(null); + }); + }] + } +}; + +const contextTests = { + 'previous': { + re: /\(previous\)/, + desc: '.(previous)' + }, + 'closure': { + re: /\(closure\)=(0x[0-9a-f]+)[^\n]+function: closure/i, + desc: '.(closure)', + validator(t, sess, addresses, name, cb) { + const address = addresses[name]; + sess.send(`v8 inspect ${address}`); + sess.linesUntil(/}>/, (err, lines) => { + if (err) return cb(err); + lines = lines.join('\n'); + t.ok(/outerVar[^\n]+"outer variable"/.test(lines), + 'method[[context]].closure.outerVar should exist'); + cb(null); + }); + } + }, + 'scoped-var': { + re: /scopedVar[^\n]+"scoped value"/i, + desc: '.scopedVar', + }, + 'scoped-api': { + re: /scopedAPI=(0x[0-9a-f]+)[^\n]+Zlib/i, + desc: '.scopedAPI', + validator(t, sess, addresses, name, cb) { + const address = addresses[name]; + sess.send(`v8 inspect ${address}`); + sess.linesUntil(/}>/, (err, lines) => { + if (err) return cb(err); + lines = lines.join('\n'); + t.ok(/internal fields/.test(lines), + 'method[[context]].closure.scopedAPI should have internal fields'); + cb(null); + }); + } + }, + 'scoped-array': { + re: /scopedArray=(0x[0-9a-f]+):/i, + desc: '.scopedArray', + validator(t, sess, addresses, name, cb) { + const address = addresses[name]; + sess.send(`v8 inspect ${address}`); + sess.linesUntil(/}>/, (err, lines) => { + if (err) return cb(err); + lines = lines.join('\n'); + t.ok(/\[0\]=/.test(lines), + 'method[[context]].scopedArray[0] should be ``'); + t.ok(/\[1\]=(0x[0-9a-f]+)[^\n]+Zlib>}>/i.test(lines), + 'method[[context]].scopedArray[1] should be a Zlib'); + cb(null); + }); + } + } +} +function verifyBacktrace(t, sess) { + sess.send('v8 bt'); sess.wait(/inspect-scenario.js/, (err, line) => { - t.error(err); + if (err) { + return teardown(t, sess, err); + } let match = line.match(/method\(this=(0x[0-9a-f]+)[^\n]+fn=(0x[0-9a-f]+)/i); - t.ok(match, 'method should have `this`'); - - that = match[1]; - fn = match[2]; - - sess.send(`v8 inspect ${that}`); - }); - - let hashmap = null; - - sess.wait(/Class/, (err, line) => { - t.error(err); - t.notEqual(line.indexOf(that), -1, 'addr of `Class` should match'); - }); - - sess.linesUntil(/}>/, (err, lines) => { - t.error(err); - lines = lines.join('\n'); - t.ok(/x=/.test(lines), '.x smi property'); - t.ok(/y=123.456/.test(lines), '.y heap number property'); - - const match = lines.match(/hashmap=(0x[0-9a-f]+):/i); - t.ok(match, '.hashmap object property'); - - hashmap = match[1]; - - sess.send(`v8 inspect ${hashmap}`); + t.ok(match, 'method should have `this` and `fn`'); + if (!match) { + return teardown(t, sess); + } + verifyMethod(t, sess, match[1], match[2]); }); +} + +function verifyMethod(t, sess, that, fn) { + const major = parseInt(process.version.match(/v(\d+)\./)[1]); + // No Context debugging for older node.js + // FIXME: this may not work if it's testing a prepared core generated by + // another version of Node.js + if (major >= 5) { + verifyMethod(t, sess, that, fn); + } else { + verifyMethodSource(t, sess, that, fn); + } +} - let regexp = null; - let cons = null; - let thin = null; - let ext = null; - let extSliced = null; - let arrowFunc = null; - let array = null; - let longArray = null; - let arrayBuffer = null; - let uint8Array = null; - let buffer = null; - - sess.wait(/Object/, (err, line) => { - t.error(err); - t.notEqual(line.indexOf(hashmap), -1, 'addr of `Object` should match'); - }); +function verifyMethodSource(t, sess, that, fn) { + sess.send(`v8 inspect -s ${fn}`); + sess.linesUntil(/^>/, (err, lines) => { + // We can still continue with this error reported + t.error(err, `v8 inspect -s should return output`); + if (err) { + verifyClass(t, sess, that); + return; + } + // Include 'source:' and '>' to act as boundaries. (Avoid + // passing if the whole file it displayed instead of just + // the function we want.) + const methodSource = ' source:\n' + + 'function method() {\n' + + ' throw new Error(\'Uncaught\');\n' + + ' }\n' + + '>'; - sess.linesUntil(/}>/, (err, lines) => { - t.error(err); lines = lines.join('\n'); - t.ok(/\[0\]=[^\n]*null/.test(lines), '[0] null element'); - t.ok(/\[4\]=[^\n]*undefined/.test(lines), '[4] undefined element'); - - const reMatch = lines.match( - /\[23\]=(0x[0-9a-f]+):<(?:Object: RegExp|JSRegExp source=\/regexp\/)>/); - t.ok(reMatch, '[23] RegExp element'); - regexp = reMatch[1]; - - const arrowMatch = lines.match( - /\[25\]=(0x[0-9a-f]+):<(function: c.hashmap).*>/); - t.ok(arrowMatch, '[25] Arrow Function element'); - arrowFunc = arrowMatch[1]; - - t.ok(/.some-key=/.test(lines), '.some-key property'); - t.ok(/.other-key=[^\n]*/.test(lines), - '.other-key property'); - - const arrayMatch = - lines.match(/.array=(0x[0-9a-f]+):/); - t.ok(arrayMatch, '.array JSArray property'); - array = arrayMatch[1]; - - const longArrayMatch = - lines.match(/.long-array=(0x[0-9a-f]+):/); - t.ok(longArrayMatch, '.array JSArray property'); - longArray = longArrayMatch[1]; - - const arrayBufferRe = new RegExp('.array-buffer=(0x[0-9a-f]+):' + - ''); - const arrayBufferMatch = lines.match(arrayBufferRe); - t.ok(arrayBufferMatch, '.array-buffer JSArrayBuffer property'); - arrayBuffer = arrayBufferMatch[1]; - - const uint8ArrayRe = new RegExp('.uint8-array=(0x[0-9a-f]+):' + - ''); - const uint8ArrayMatch = lines.match(uint8ArrayRe); - t.ok(uint8ArrayMatch, '.uint8-array JSArrayBufferView property'); - uint8Array = uint8ArrayMatch[1]; - - const bufferRe = new RegExp('.buffer=(0x[0-9a-f]+):' + - ''); - const bufferMatch = lines.match(bufferRe); - t.ok(bufferMatch, '.buffer JSArrayBufferView property'); - buffer = bufferMatch[1]; - - const consMatch = lines.match( - /.cons-string=(0x[0-9a-f]+):/); - t.ok(consMatch, '.cons-string ConsString property'); - cons = consMatch[1]; - - const thinMatch = lines.match( - /.thin-string=(0x[0-9a-f]+):/); - t.ok(thinMatch, '.thin-string ThinString property'); - thin = thinMatch[1]; - - const extMatch = lines.match( - /.externalized-string=(0x[0-9a-f]+):/); - t.ok(extMatch, '.externalized-string ExternalString property'); - ext = extMatch[1]; - - const extSlicedMatch = lines.match( - /.sliced-externalized-string=(0x[0-9a-f]+):/); - t.ok(extSlicedMatch, - '.sliced-externalized-string Sliced ExternalString property'); - extSliced = extSlicedMatch[1]; - - sess.send(`v8 inspect ${regexp}`); - sess.send(`v8 inspect -F ${cons}`); + t.ok(lines.includes(methodSource), 'method source should match'); + verifyClass(t, sess, that); }); +} +function verifyMethod(t, sess, that, fn) { + sess.send(`v8 inspect ${fn}`); sess.linesUntil(/}>/, (err, lines) => { - t.error(err); - lines = lines.join('\n'); - t.ok(/source=\/regexp\//.test(lines) || - /\.source=[^\n]*/.test(lines), - 'regexp.source'); - }); - - sess.linesUntil(/">/, (err, lines) => { - t.error(err); - lines = lines.join('\n'); - t.notEqual( - lines.indexOf('this could be a bit smaller, but v8 wants big str.' + - 'this could be a bit smaller, but v8 wants big str.'), - -1, - 'cons string content'); - - sess.send(`v8 inspect --string-length 20 ${cons}`); + if (err) { + return teardown(t, sess, err); + } + const parent = 'method[[context]]'; + const addresses = collectMembers( + t, lines.join('\n'), contextTests, parent + ); + verifyMembers(t, sess, addresses, contextTests, parent, (t, sess) => { + verifyMethodSource(t, sess, that, fn); + }); }); +} - sess.linesUntil(/">/, (err, lines) => { - t.error(err); - lines = lines.join('\n'); - t.notEqual( - lines.indexOf('this could be a bit ...'), - -1, - '--string-length truncates the string'); - - sess.send(`v8 inspect ${thin}`); +function verifyClass(t, sess, that) { + sess.send(`v8 inspect ${that}`); + sess.wait(/Class/, (err, line) => { + if (err) { + return teardown(t, sess, err); + } + t.ok(line.includes(that), + 'address in the detailed view of Class should match the address ' + + 'in the parent\'s view'); + sess.linesUntil(/}>/, (err, lines) => { + if (err) { + return teardown(t, sess, err); + } + lines = lines.join('\n'); + t.ok(/x=/.test(lines), + 'this.x should be '); + t.ok(/y=123.456/.test(lines), + 'this.y should be 123.456'); + const match = lines.match(/hashmap=(0x[0-9a-f]+):/i); + t.ok(match, 'this.hashmap should be an object'); + if (!match) { + return teardown(t, sess); + } + verifyObject(t, sess, match[1]); + }); }); +} - sess.linesUntil(/">/, (err, lines) => { - t.error(err); - lines = lines.join('\n'); - t.ok( - /0x[0-9a-f]+:/.test(lines), - 'thin string content'); - - sess.send(`v8 inspect ${array}`); - }); +function verifyObject(t, sess, hashmap) { + sess.send(`v8 inspect ${hashmap}`); + sess.wait(/Object/, (err, line) => { + if (err) { + return teardown(t, sess, err); + } - sess.linesUntil(/}>/, (err, lines) => { - t.error(err); - lines = lines.join('\n'); - t.notEqual( - lines.indexOf('}>$/), - 'array content'); - sess.send(`v8 inspect --array-length 10 ${longArray}`); + t.ok(line.includes(hashmap), + 'address in the detailed view of Object should match the address ' + + 'in the parent\'s view'); + verifyHashMap(t, sess, line, hashmap); }); +} +function verifyHashMap(t, sess) { sess.linesUntil(/}>/, (err, lines) => { - t.error(err); - lines = lines.join('\n'); - t.notEqual( - lines.indexOf('}>$/), 'long array content'); - sess.send(`v8 inspect ${arrayBuffer}`); - }); - - sess.linesUntil(/\]>/, (err, lines) => { - t.error(err); - lines = lines.join('\n'); - const re = new RegExp( - '0x[0-9a-f]+:' + - ''); - t.ok( - re.test(lines), - 'array buffer content'); - sess.send(`v8 inspect --array-length 1 ${arrayBuffer}`); - }); - - sess.linesUntil(/]>/, (err, lines) => { - t.error(err); - lines = lines.join('\n'); - const re = new RegExp( - '0x[0-9a-f]+:' + - ''); - t.ok( - re.test(lines), - 'array buffer content with maximum length 1'); - sess.send(`v8 inspect ${uint8Array}`); - }); - - sess.linesUntil(/]>/, (err, lines) => { - t.error(err); - lines = lines.join('\n'); - const re = new RegExp( - '0x[0-9a-f]+:' + - ''); - t.ok( - re.test(lines), - 'typed array content'); - sess.send(`v8 inspect --array-length 1 ${uint8Array}`); - }); - - sess.linesUntil(/]>/, (err, lines) => { - t.error(err); - lines = lines.join('\n'); - const re = new RegExp( - '0x[0-9a-f]+:' + - ''); - t.ok( - re.test(lines), - 'typed array content with maximum length 1'); - sess.send(`v8 inspect ${buffer}`); - }); - - sess.linesUntil(/]>/, (err, lines) => { - t.error(err); - lines = lines.join('\n'); - const re = new RegExp( - '0x[0-9a-f]+:' + - ''); - t.ok( - re.test(lines), - 'buffer content'); - sess.send(`v8 inspect --array-length 1 ${buffer}`); - }); - - sess.linesUntil(/]>/, (err, lines) => { - t.error(err); - lines = lines.join('\n'); - const re = new RegExp( - '0x[0-9a-f]+:' + - ''); - t.ok( - re.test(lines), - 'buffer content with maximum length 1'); - sess.send(`v8 inspect -s ${arrowFunc}`); - }); - - - sess.linesUntil(/^>/, (err, lines) => { - t.error(err); - lines = lines.join('\n'); - // Include 'source:' and '>' to act as boundaries. (Avoid - // passing if the whole file it displayed instead of just - // the function we want.) - const arrowSource = 'source:\n' + - 'function c.hashmap.(anonymous function)(a,b)=>{a+b}\n' + - '>'; - - t.ok(lines.includes( - arrowSource), - 'arrow method source'); - - sess.send(`v8 inspect -s ${fn}`); + if (err) { + return teardown(t, sess, err); + } + const parent = 'hashmap'; + const addresses = collectMembers( + t, lines.join('\n'), hashMapTests, parent); + verifyMembers(t, sess, addresses, hashMapTests, parent, teardown); }); +} + +function teardown(t, sess, err) { + t.end(err); + sess.quit(); +} + +function collectMembers(t, lines, tests, parent) { + const addresses = {}; + for (let name of Object.keys(tests)) { + const test = tests[name]; + const match = lines.match(test.re); + if (match) { + t.pass(`${parent}${test.desc} should exist `); + addresses[name] = match[1]; + } else { + if (test.optional && test.optional.re.test(lines)) { + t.skip(`${parent}${test.desc} ${test.optional.reason}`); + } else { + t.fail(`${parent}${test.desc} should exist `); + } + } + } + return addresses; +} - sess.linesUntil(/^>/, (err, lines) => { - t.error(err); - lines = lines.join('\n'); +// To avoid lldb output being mixed, we must do the validation one by one +function verifyMembers(t, sess, addresses, tests, parent, next) { + const arr = Object.keys(addresses); - // Include 'source:' and '>' to act as boundaries. (Avoid - // passing if the whole file it displayed instead of just - // the function we want.) - const methodSource = ' source:\n' + - 'function method() {\n' + - ' throw new Error(\'Uncaught\');\n' + - ' }\n' + - '>'; + function verifyProperty(t, sess, addresses, index, subIndex) { + if (index >= arr.length) { + return next(t, sess); + } - t.ok(lines.includes( - methodSource), - 'method source found'); + const name = arr[index]; + const test = tests[name]; + // We are in the middle of in test.validators + if (subIndex !== undefined) { + const validators = test.validators; + if (subIndex >= validators.length) { + return verifyProperty(t, sess, addresses, index + 1); + } + validators[subIndex](t, sess, addresses, name, (err) => { + t.error(err, `${parent}${test.desc} validator #${subIndex} should complete`); + verifyProperty(t, sess, addresses, index, subIndex + 1); + }); + return; + } - if (process.version < 'v5.0.0') { - sess.quit(); - t.end(); - } else { - // No Context debugging for older node.js - t.ok(/\(previous\)/.test(lines), 'method.previous'); - t.ok(/scopedVar[^\n]+"scoped value"/.test(lines), 'method.scopedValue'); + if (test.validator) { // Single validator + test.validator(t, sess, addresses, name, (err) => { + t.error(err, `${parent}${test.desc} validator should complete`); + verifyProperty(t, sess, addresses, index + 1); + }); + } else if (test.validators) { // Multiple validator + verifyProperty(t, sess, addresses, index, 0); + } else { // No validator + verifyProperty(t, sess, addresses, index + 1); + } + } - let match = lines.match( - /scopedAPI=(0x[0-9a-f]+)[^\n]+Zlib/i); - t.ok(match, '`method` should have `scopedAPI`'); + // Kickoff + verifyProperty(t, sess, addresses, 0); +} - sess.send(`v8 inspect ${match[1]}`); +tape('v8 inspect', (t) => { + t.timeoutAfter(15000); - match = lines.match( - /\(closure\)=(0x[0-9a-f]+)[^\n]+function: closure/i); - t.ok(match, '`method` should have `closure`'); + const sess = common.Session.create('inspect-scenario.js'); - sess.send(`v8 inspect ${match[1]}`); + sess.waitBreak((err) => { + if (err) { + return teardown(t, sess, err); } + verifyBacktrace(t, sess); }); - - if (process.version >= 'v5.0.0') { - sess.linesUntil(/}>/, (err, lines) => { - t.error(err); - lines = lines.join('\n'); - t.ok(/internal fields/.test(lines), 'method.scopedAPI.internalFields'); - }); - - sess.linesUntil(/}>/, (err, lines) => { - t.error(err); - lines = lines.join('\n'); - t.ok(/outerVar[^\n]+"outer variable"/.test(lines), - 'method.closure.outerVar'); - - sess.quit(); - t.end(); - }); - } });