assert-offset-columns.js (3013B)
1 // Set breakpoints "everywhere" in a function, then call the function and check that 2 // the breakpoints were added are at the expected columns, and the breakpoints 3 // were executed in th expected order. 4 // 5 // `code` is a JS Script. The final line should define a function `f` to validate. 6 // `expectedBpts` is a string of spaces and carets ('^'). Throws if we don't hit 7 // breakpoints on exactly the columns indicated by the carets. 8 // `expectedOrdering` is a string of integer indices for the offsets that are 9 // executed, in the order that then are executed. Test code can also push 10 // additional items into this string using items.push("!"). 11 function assertOffsetColumns(code, expectedBpts, expectedOrdering = null) { 12 if (expectedOrdering === null) { 13 // The default ordering simply runs the breakpoints in order. 14 expectedOrdering = Array.from(expectedBpts.match(/\^/g), (_, i) => i).join(" "); 15 } 16 17 // Define the function `f` in a new global. 18 const global = newGlobal({newCompartment: true}); 19 20 const lines = code.split(/\r?\n|\r]/g); 21 const initCode = lines.slice(0, -1).join("\n"); 22 const execCode = lines[lines.length - 1]; 23 24 // Treat everything but the last line as initialization code. 25 global.eval(initCode); 26 27 // Run the test code itself. 28 global.eval(execCode); 29 30 // Allow some tests to append to a log that will show up in expected ordering. 31 const hits = global.hits = []; 32 const bpts = new Set(); 33 34 // Set breakpoints everywhere and call the function. 35 const dbg = new Debugger; 36 let debuggeeFn = dbg.addDebuggee(global).makeDebuggeeValue(global.f); 37 if (debuggeeFn.isBoundFunction) { 38 debuggeeFn = debuggeeFn.boundTargetFunction; 39 } 40 41 const { script } = debuggeeFn; 42 for (const offset of script.getAllColumnOffsets()) { 43 assertEq(offset.lineNumber, 1); 44 assertEq(offset.columnNumber <= execCode.length, true); 45 bpts.add(offset.columnNumber); 46 47 script.setBreakpoint(offset.offset, { 48 hit(frame) { 49 hits.push(offset.columnNumber); 50 }, 51 }); 52 } 53 global.f(3); 54 55 const actualBpts = Array.from(execCode, (_, i) => { 56 return bpts.has(i + 1) ? "^" : " "; 57 }).join(""); 58 59 if (actualBpts.trimEnd() !== expectedBpts.trimEnd()) { 60 throw new Error(`Assertion failed: 61 code: ${execCode} 62 expected bpts: ${expectedBpts} 63 actual bpts: ${actualBpts}\n`); 64 } 65 66 const indexLookup = new Map( 67 Array.from(bpts).sort().map((col, i) => [col, i])); 68 const actualOrdering = hits 69 .map(item => typeof item === "number" ? indexLookup.get(item) : item) 70 .join(" "); 71 72 if (actualOrdering.trimEnd() !== expectedOrdering.trimEnd()) { 73 throw new Error(`Assertion failed: 74 code: ${execCode} 75 bpts: ${expectedBpts} 76 expected order: ${expectedOrdering} 77 actual order: ${actualOrdering}\n`); 78 } 79 }