blob: 4667a71d6b717f35f1615d9bb4503f0b4cd0caef [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2012 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
29
30// Get the Debug object exposed from the debug context global object.
31var Debug = debug.Debug;
32
33// Accepts a function/closure 'fun' that must have a debugger statement inside.
34// A variable 'variable_name' must be initialized before debugger statement
35// and returned after the statement. The test will alter variable value when
36// on debugger statement and check that returned value reflects the change.
37function RunPauseTest(scope_number, expected_old_result, variable_name,
38 new_value, expected_new_result, fun) {
39 var actual_old_result = fun();
40 assertEquals(expected_old_result, actual_old_result);
41
42 var listener_delegate;
43 var listener_called = false;
44 var exception = null;
45
46 function listener_delegate(exec_state) {
47 var scope = exec_state.frame(0).scope(scope_number);
48 scope.setVariableValue(variable_name, new_value);
49 }
50
51 function listener(event, exec_state, event_data, data) {
52 try {
53 if (event == Debug.DebugEvent.Break) {
54 listener_called = true;
55 listener_delegate(exec_state);
56 }
57 } catch (e) {
58 exception = e;
59 }
60 }
61
62 // Add the debug event listener.
63 Debug.setListener(listener);
64
65 var actual_new_value;
66 try {
67 actual_new_result = fun();
68 } finally {
69 Debug.setListener(null);
70 }
71
72 if (exception != null) {
73 assertUnreachable("Exception in listener\n" + exception.stack);
74 }
75 assertTrue(listener_called);
76
77 assertEquals(expected_new_result, actual_new_result);
78}
79
80// Accepts a closure 'fun' that returns a variable from it's outer scope.
81// The test changes the value of variable via the handle to function and checks
82// that the return value changed accordingly.
83function RunClosureTest(scope_number, expected_old_result, variable_name,
84 new_value, expected_new_result, fun) {
85 var actual_old_result = fun();
86 assertEquals(expected_old_result, actual_old_result);
87
88 var fun_mirror = Debug.MakeMirror(fun);
89
90 var scope = fun_mirror.scope(scope_number);
91 scope.setVariableValue(variable_name, new_value);
92
93 var actual_new_result = fun();
94
95 assertEquals(expected_new_result, actual_new_result);
96}
97
98
99function ClosureTestCase(scope_index, old_result, variable_name, new_value,
100 new_result, success_expected, factory) {
101 this.scope_index_ = scope_index;
102 this.old_result_ = old_result;
103 this.variable_name_ = variable_name;
104 this.new_value_ = new_value;
105 this.new_result_ = new_result;
106 this.success_expected_ = success_expected;
107 this.factory_ = factory;
108}
109
110ClosureTestCase.prototype.run_pause_test = function() {
111 var th = this;
112 var fun = this.factory_(true);
113 this.run_and_catch_(function() {
114 RunPauseTest(th.scope_index_ + 1, th.old_result_, th.variable_name_,
115 th.new_value_, th.new_result_, fun);
116 });
117}
118
119ClosureTestCase.prototype.run_closure_test = function() {
120 var th = this;
121 var fun = this.factory_(false);
122 this.run_and_catch_(function() {
123 RunClosureTest(th.scope_index_, th.old_result_, th.variable_name_,
124 th.new_value_, th.new_result_, fun);
125 });
126}
127
128ClosureTestCase.prototype.run_and_catch_ = function(runnable) {
129 if (this.success_expected_) {
130 runnable();
131 } else {
132 assertThrows(runnable);
133 }
134}
135
136
137// Test scopes visible from closures.
138
139var closure_test_cases = [
140 new ClosureTestCase(0, 'cat', 'v1', 5, 5, true,
141 function Factory(debug_stop) {
142 var v1 = 'cat';
143 return function() {
144 if (debug_stop) debugger;
145 return v1;
146 }
147 }),
148
149 new ClosureTestCase(0, 4, 't', 7, 9, true, function Factory(debug_stop) {
150 var t = 2;
151 var r = eval("t");
152 return function() {
153 if (debug_stop) debugger;
154 return r + t;
155 }
156 }),
157
158 new ClosureTestCase(0, 6, 't', 10, 13, true, function Factory(debug_stop) {
159 var t = 2;
160 var r = eval("t = 3");
161 return function() {
162 if (debug_stop) debugger;
163 return r + t;
164 }
165 }),
166
167 new ClosureTestCase(0, 17, 's', 'Bird', 'Bird', true,
168 function Factory(debug_stop) {
169 eval("var s = 17");
170 return function() {
171 if (debug_stop) debugger;
172 return s;
173 }
174 }),
175
176 new ClosureTestCase(2, 'capybara', 'foo', 77, 77, true,
177 function Factory(debug_stop) {
178 var foo = "capybara";
179 return (function() {
180 var bar = "fish";
181 try {
182 throw {name: "test exception"};
183 } catch (e) {
184 return function() {
185 if (debug_stop) debugger;
186 bar = "beast";
187 return foo;
188 }
189 }
190 })();
191 }),
192
193 new ClosureTestCase(0, 'AlphaBeta', 'eee', 5, '5Beta', true,
194 function Factory(debug_stop) {
195 var foo = "Beta";
196 return (function() {
197 var bar = "fish";
198 try {
199 throw "Alpha";
200 } catch (eee) {
201 return function() {
202 if (debug_stop) debugger;
203 return eee + foo;
204 }
205 }
206 })();
207 })
208];
209
210for (var i = 0; i < closure_test_cases.length; i++) {
211 closure_test_cases[i].run_pause_test();
212}
213
214for (var i = 0; i < closure_test_cases.length; i++) {
215 closure_test_cases[i].run_closure_test();
216}
217
218
219// Test local scope.
220
221RunPauseTest(0, 'HelloYou', 'u', 'We', 'HelloWe', (function Factory() {
222 return function() {
223 var u = "You";
224 var v = "Hello";
225 debugger;
226 return v + u;
227 }
228})());
229
230RunPauseTest(0, 'Helloworld', 'p', 'GoodBye', 'HelloGoodBye',
231 (function Factory() {
232 function H(p) {
233 var v = "Hello";
234 debugger;
235 return v + p;
236 }
237 return function() {
238 return H("world");
239 }
240})());
241
242RunPauseTest(0, 'mouse', 'v1', 'dog', 'dog', (function Factory() {
243 return function() {
244 var v1 = 'cat';
245 eval("v1 = 'mouse'");
246 debugger;
247 return v1;
248 }
249})());
250
251RunPauseTest(0, 'mouse', 'v1', 'dog', 'dog', (function Factory() {
252 return function() {
253 eval("var v1 = 'mouse'");
254 debugger;
255 return v1;
256 }
257})());
258
259
260// Check that we correctly update local variable that
261// is referenced from an inner closure.
262RunPauseTest(0, 'Blue', 'v', 'Green', 'Green', (function Factory() {
263 return function() {
264 function A() {
265 var v = "Blue";
266 function Inner() {
267 return void v;
268 }
269 debugger;
270 return v;
271 }
272 return A();
273 }
274})());
275
276// Check that we correctly update parameter, that is known to be stored
277// both on stack and in heap.
278RunPauseTest(0, 5, 'p', 2012, 2012, (function Factory() {
279 return function() {
280 function A(p) {
281 function Inner() {
282 return void p;
283 }
284 debugger;
285 return p;
286 }
287 return A(5);
288 }
289})());
290
291
292// Test value description protocol JSON
293
294assertEquals(true, Debug.TestApi.CommandProcessorResolveValue({value: true}));
295
296assertSame(null, Debug.TestApi.CommandProcessorResolveValue({type: "null"}));
297assertSame(undefined,
298 Debug.TestApi.CommandProcessorResolveValue({type: "undefined"}));
299
300assertSame("123", Debug.TestApi.CommandProcessorResolveValue(
301 {type: "string", stringDescription: "123"}));
302assertSame(123, Debug.TestApi.CommandProcessorResolveValue(
303 {type: "number", stringDescription: "123"}));
304
305assertSame(Number, Debug.TestApi.CommandProcessorResolveValue(
306 {handle: Debug.MakeMirror(Number).handle()}));
307assertSame(RunClosureTest, Debug.TestApi.CommandProcessorResolveValue(
308 {handle: Debug.MakeMirror(RunClosureTest).handle()}));