1// Copyright 2008 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28// Flags: --expose-debug-as debug --nocrankshaft 29// Get the Debug object exposed from the debug context global object. 30Debug = debug.Debug 31 32function DebuggerStatement() { 33 debugger; /*pause*/ 34} 35 36function TestCase(fun, frame_number) { 37 var exception = false; 38 var codeSnippet = undefined; 39 var resultPositions = undefined; 40 41 function listener(event, exec_state, event_data, data) { 42 try { 43 if (event == Debug.DebugEvent.Break || 44 event == Debug.DebugEvent.Exception) { 45 Debug.setListener(null); 46 assertHasLineMark(/pause/, exec_state.frame(0)); 47 assertHasLineMark(/positions/, exec_state.frame(frame_number)); 48 var frame = exec_state.frame(frame_number); 49 codeSnippet = frame.sourceLineText(); 50 resultPositions = frame.stepInPositions(); 51 } 52 } catch (e) { 53 exception = e 54 } 55 56 function assertHasLineMark(mark, frame) { 57 var line = frame.sourceLineText(); 58 if (!mark.exec(frame.sourceLineText())) { 59 throw new Error("Line " + line + " should contain mark " + mark); 60 } 61 } 62 } 63 64 Debug.setListener(listener); 65 66 fun(); 67 68 Debug.setListener(null); 69 70 assertTrue(!exception, exception); 71 72 var expectedPositions = {}; 73 var markPattern = new RegExp("/\\*#\\*/", "g"); 74 75 var matchResult; 76 while ( (matchResult = markPattern.exec(codeSnippet)) ) { 77 expectedPositions[matchResult.index] = true; 78 } 79 80 print(codeSnippet); 81 82 var decoratedResult = codeSnippet; 83 84 function replaceStringRange(s, pos, substitute) { 85 return s.substring(0, pos) + substitute + 86 s.substring(pos + substitute.length); 87 } 88 89 var markLength = 5; 90 var unexpectedPositionFound = false; 91 92 for (var i = 0; i < resultPositions.length; i++) { 93 var col = resultPositions[i].position.column - markLength; 94 if (expectedPositions[col]) { 95 delete expectedPositions[col]; 96 decoratedResult = replaceStringRange(decoratedResult, col, "*YES*"); 97 } else { 98 decoratedResult = replaceStringRange(decoratedResult, col, "!BAD!"); 99 unexpectedPositionFound = true; 100 } 101 } 102 103 print(decoratedResult); 104 105 for (var n in expectedPositions) { 106 assertTrue(false, "Some positions are not reported: " + decoratedResult); 107 break; 108 } 109 assertFalse(unexpectedPositionFound, "Found unexpected position: " + 110 decoratedResult); 111} 112 113function TestCaseWithDebugger(fun) { 114 TestCase(fun, 1); 115} 116 117function TestCaseWithBreakpoint(fun, line_number, frame_number) { 118 var breakpointId = Debug.setBreakPoint(fun, line_number); 119 TestCase(fun, frame_number); 120 Debug.clearBreakPoint(breakpointId); 121} 122 123function TestCaseWithException(fun, frame_number) { 124 Debug.setBreakOnException(); 125 TestCase(fun, frame_number); 126 Debug.clearBreakOnException(); 127} 128 129 130// Test cases. 131 132// Step in position, when the function call that we are standing at is already 133// being executed. 134var fun = function() { 135 function g(p) { 136 throw String(p); /*pause*/ 137 } 138 try { 139 var res = [ g(1), /*#*/g(2) ]; /*positions*/ 140 } catch (e) { 141 } 142}; 143TestCaseWithBreakpoint(fun, 2, 1); 144TestCaseWithException(fun, 1); 145 146 147// Step in position, when the function call that we are standing at is raising 148// an exception. 149var fun = function() { 150 var o = { 151 g: function(p) { 152 throw p; 153 } 154 }; 155 try { 156 var res = [ /*#*/f(1), /*#*/g(2) ]; /*pause, positions*/ 157 } catch (e) { 158 } 159}; 160TestCaseWithException(fun, 0); 161 162 163// Step-in position, when already paused almost on the first call site. 164var fun = function() { 165 function g(p) { 166 throw p; 167 } 168 try { 169 var res = [ /*#*/g(Math.rand), /*#*/g(2) ]; /*pause, positions*/ 170 } catch (e) { 171 } 172}; 173TestCaseWithBreakpoint(fun, 5, 0); 174 175// Step-in position, when already paused on the first call site. 176var fun = function() { 177 function g() { 178 throw "Debug"; 179 } 180 try { 181 var res = [ /*#*/g(), /*#*/g() ]; /*pause, positions*/ 182 } catch (e) { 183 } 184}; 185TestCaseWithBreakpoint(fun, 5, 0); 186 187 188// Method calls. 189var fun = function() { 190 var data = { 191 a: function() {} 192 }; 193 var res = [ DebuggerStatement(), data./*#*/a(), data[/*#*/String("a")]/*#*/(), data["a"]/*#*/(), data.a, data["a"] ]; /*positions*/ 194}; 195TestCaseWithDebugger(fun); 196 197// Function call on a value. 198var fun = function() { 199 function g(p) { 200 return g; 201 } 202 var res = [ DebuggerStatement(), /*#*/g(2), /*#*/g(2)/*#*/(3), /*#*/g(0)/*#*/(0)/*#*/(g) ]; /*positions*/ 203}; 204TestCaseWithDebugger(fun); 205 206// Local function call, closure function call, 207// local function construction call. 208var fun = (function(p) { 209 return function() { 210 function f(a, b) { 211 } 212 var res = /*#*/f(DebuggerStatement(), /*#*/p(/*#*/new f())); /*positions*/ 213 }; 214})(Object); 215TestCaseWithDebugger(fun); 216 217// Global function, global object construction, calls before pause point. 218var fun = (function(p) { 219 return function() { 220 var res = [ Math.abs(new Object()), DebuggerStatement(), Math./*#*/abs(4), /*#*/new Object()./*#*/toString() ]; /*positions*/ 221 }; 222})(Object); 223TestCaseWithDebugger(fun); 224