1b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// Copyright 2011 the V8 project authors. All rights reserved.
2b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// Redistribution and use in source and binary forms, with or without
3b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// modification, are permitted provided that the following conditions are
4b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// met:
5b645116853c677aca8a316381b87441ba6004f67danno@chromium.org//
6b645116853c677aca8a316381b87441ba6004f67danno@chromium.org//     * Redistributions of source code must retain the above copyright
7b645116853c677aca8a316381b87441ba6004f67danno@chromium.org//       notice, this list of conditions and the following disclaimer.
8b645116853c677aca8a316381b87441ba6004f67danno@chromium.org//     * Redistributions in binary form must reproduce the above
9b645116853c677aca8a316381b87441ba6004f67danno@chromium.org//       copyright notice, this list of conditions and the following
10b645116853c677aca8a316381b87441ba6004f67danno@chromium.org//       disclaimer in the documentation and/or other materials provided
11b645116853c677aca8a316381b87441ba6004f67danno@chromium.org//       with the distribution.
12b645116853c677aca8a316381b87441ba6004f67danno@chromium.org//     * Neither the name of Google Inc. nor the names of its
13b645116853c677aca8a316381b87441ba6004f67danno@chromium.org//       contributors may be used to endorse or promote products derived
14b645116853c677aca8a316381b87441ba6004f67danno@chromium.org//       from this software without specific prior written permission.
15b645116853c677aca8a316381b87441ba6004f67danno@chromium.org//
16b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
28b4b2aa69a9f12525fca190287f47a66d7bdcb3aerossberg@chromium.org// Flags: --expose-debug-as debug --harmony-scoping
29b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// The functions used for testing backtraces. They are at the top to make the
30b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// testing of source line/column easier.
31b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
32b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
33b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// Get the Debug object exposed from the debug context global object.
34b645116853c677aca8a316381b87441ba6004f67danno@chromium.orgDebug = debug.Debug;
35b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
36b645116853c677aca8a316381b87441ba6004f67danno@chromium.orgvar test_name;
37b645116853c677aca8a316381b87441ba6004f67danno@chromium.orgvar listener_delegate;
38b645116853c677aca8a316381b87441ba6004f67danno@chromium.orgvar listener_called;
39b645116853c677aca8a316381b87441ba6004f67danno@chromium.orgvar exception;
40b645116853c677aca8a316381b87441ba6004f67danno@chromium.orgvar begin_test_count = 0;
41b645116853c677aca8a316381b87441ba6004f67danno@chromium.orgvar end_test_count = 0;
42b645116853c677aca8a316381b87441ba6004f67danno@chromium.orgvar break_count = 0;
43b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
44b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
45b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// Debug event listener which delegates.
46b645116853c677aca8a316381b87441ba6004f67danno@chromium.orgfunction listener(event, exec_state, event_data, data) {
47b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  try {
48b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    if (event == Debug.DebugEvent.Break) {
49b645116853c677aca8a316381b87441ba6004f67danno@chromium.org      break_count++;
50b645116853c677aca8a316381b87441ba6004f67danno@chromium.org      listener_called = true;
51b645116853c677aca8a316381b87441ba6004f67danno@chromium.org      listener_delegate(exec_state);
52b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    }
53b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  } catch (e) {
54b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    exception = e;
55b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  }
56b645116853c677aca8a316381b87441ba6004f67danno@chromium.org}
57b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
58b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// Add the debug event listener.
59b645116853c677aca8a316381b87441ba6004f67danno@chromium.orgDebug.setListener(listener);
60b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
61b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
62b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// Initialize for a new test.
63b645116853c677aca8a316381b87441ba6004f67danno@chromium.orgfunction BeginTest(name) {
64b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  test_name = name;
65b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  listener_delegate = null;
66b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  listener_called = false;
67b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  exception = null;
68b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  begin_test_count++;
69b645116853c677aca8a316381b87441ba6004f67danno@chromium.org}
70b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
71b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
72b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// Check result of a test.
73b645116853c677aca8a316381b87441ba6004f67danno@chromium.orgfunction EndTest() {
74b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  assertTrue(listener_called, "listerner not called for " + test_name);
75b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  assertNull(exception, test_name);
76b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  end_test_count++;
77b645116853c677aca8a316381b87441ba6004f67danno@chromium.org}
78b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
79b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
80b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// Check that the scope chain contains the expected types of scopes.
81b645116853c677aca8a316381b87441ba6004f67danno@chromium.orgfunction CheckScopeChain(scopes, exec_state) {
82b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  assertEquals(scopes.length, exec_state.frame().scopeCount());
83b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  for (var i = 0; i < scopes.length; i++) {
84b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    var scope = exec_state.frame().scope(i);
85b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    assertTrue(scope.isScope());
86b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    assertEquals(scopes[i], scope.scopeType());
87b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
88b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    // Check the global object when hitting the global scope.
89b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    if (scopes[i] == debug.ScopeType.Global) {
90b645116853c677aca8a316381b87441ba6004f67danno@chromium.org      // Objects don't have same class (one is "global", other is "Object",
91b645116853c677aca8a316381b87441ba6004f67danno@chromium.org      // so just check the properties directly.
92b645116853c677aca8a316381b87441ba6004f67danno@chromium.org      assertPropertiesEqual(this, scope.scopeObject().value());
93b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    }
94b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  }
95b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
96b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  // Get the debug command processor.
97b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
98b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
99b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  // Send a scopes request and check the result.
100b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  var json;
101b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  var request_json = '{"seq":0,"type":"request","command":"scopes"}';
102b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  var response_json = dcp.processDebugJSONRequest(request_json);
103b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  var response = JSON.parse(response_json);
104b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  assertEquals(scopes.length, response.body.scopes.length);
105b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  for (var i = 0; i < scopes.length; i++) {
106b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    assertEquals(i, response.body.scopes[i].index);
107b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    assertEquals(scopes[i], response.body.scopes[i].type);
108b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    if (scopes[i] == debug.ScopeType.Local ||
109b645116853c677aca8a316381b87441ba6004f67danno@chromium.org        scopes[i] == debug.ScopeType.Closure) {
110b645116853c677aca8a316381b87441ba6004f67danno@chromium.org      assertTrue(response.body.scopes[i].object.ref < 0);
111b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    } else {
112b645116853c677aca8a316381b87441ba6004f67danno@chromium.org      assertTrue(response.body.scopes[i].object.ref >= 0);
113b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    }
114b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    var found = false;
115b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    for (var j = 0; j < response.refs.length && !found; j++) {
116b645116853c677aca8a316381b87441ba6004f67danno@chromium.org      found = response.refs[j].handle == response.body.scopes[i].object.ref;
117b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    }
118b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    assertTrue(found, "Scope object " + response.body.scopes[i].object.ref + " not found");
119b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  }
120b645116853c677aca8a316381b87441ba6004f67danno@chromium.org}
121b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
122b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// Check that the content of the scope is as expected. For functions just check
123b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// that there is a function.
124b645116853c677aca8a316381b87441ba6004f67danno@chromium.orgfunction CheckScopeContent(content, number, exec_state) {
125b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  var scope = exec_state.frame().scope(number);
126b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  var count = 0;
127b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  for (var p in content) {
128b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    var property_mirror = scope.scopeObject().property(p);
129b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    if (property_mirror.isUndefined()) {
130b645116853c677aca8a316381b87441ba6004f67danno@chromium.org      print('property ' + p + ' not found in scope');
131b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    }
132b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    assertFalse(property_mirror.isUndefined(), 'property ' + p + ' not found in scope');
133b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    if (typeof(content[p]) === 'function') {
134b645116853c677aca8a316381b87441ba6004f67danno@chromium.org      assertTrue(property_mirror.value().isFunction());
135b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    } else {
136b645116853c677aca8a316381b87441ba6004f67danno@chromium.org      assertEquals(content[p], property_mirror.value().value(), 'property ' + p + ' has unexpected value');
137b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    }
138b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    count++;
139b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  }
140b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
141b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  // 'arguments' and might be exposed in the local and closure scope. Just
142b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  // ignore this.
143b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  var scope_size = scope.scopeObject().properties().length;
144b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  if (!scope.scopeObject().property('arguments').isUndefined()) {
145b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    scope_size--;
146b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  }
147b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  // Skip property with empty name.
148b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  if (!scope.scopeObject().property('').isUndefined()) {
149b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    scope_size--;
150b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  }
151b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
152b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  if (count != scope_size) {
153b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    print('Names found in scope:');
154b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    var names = scope.scopeObject().propertyNames();
155b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    for (var i = 0; i < names.length; i++) {
156b645116853c677aca8a316381b87441ba6004f67danno@chromium.org      print(names[i]);
157b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    }
158b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  }
159b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  assertEquals(count, scope_size);
160b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
161b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  // Get the debug command processor.
162b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  var dcp = exec_state.debugCommandProcessor("unspecified_running_state");
163b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
164b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  // Send a scope request for information on a single scope and check the
165b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  // result.
166b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  var request_json = '{"seq":0,"type":"request","command":"scope","arguments":{"number":';
167b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  request_json += scope.scopeIndex();
168b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  request_json += '}}';
169b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  var response_json = dcp.processDebugJSONRequest(request_json);
170b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  var response = JSON.parse(response_json);
171b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  assertEquals(scope.scopeType(), response.body.type);
172b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  assertEquals(number, response.body.index);
173b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  if (scope.scopeType() == debug.ScopeType.Local ||
174b645116853c677aca8a316381b87441ba6004f67danno@chromium.org      scope.scopeType() == debug.ScopeType.Closure) {
175b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    assertTrue(response.body.object.ref < 0);
176b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  } else {
177b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    assertTrue(response.body.object.ref >= 0);
178b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  }
179b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  var found = false;
180b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  for (var i = 0; i < response.refs.length && !found; i++) {
181b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    found = response.refs[i].handle == response.body.object.ref;
182b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  }
183b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  assertTrue(found, "Scope object " + response.body.object.ref + " not found");
184b645116853c677aca8a316381b87441ba6004f67danno@chromium.org}
185b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
186b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
187b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// Simple closure formed by returning an inner function referering to an outer
188b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// block local variable and an outer function's parameter. Due to VM
189b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// optimizations parts of the actual closure is missing from the debugger
190b645116853c677aca8a316381b87441ba6004f67danno@chromium.org// information.
191b645116853c677aca8a316381b87441ba6004f67danno@chromium.orgBeginTest("Closure 1");
192b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
193b645116853c677aca8a316381b87441ba6004f67danno@chromium.orgfunction closure_1(a) {
194b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  var x = 2;
195b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  let y = 3;
196b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  if (true) {
197b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    let z = 4;
198b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    function f() {
199b645116853c677aca8a316381b87441ba6004f67danno@chromium.org      debugger;
200b645116853c677aca8a316381b87441ba6004f67danno@chromium.org      return a + x + y + z;
201b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    };
202b645116853c677aca8a316381b87441ba6004f67danno@chromium.org    return f;
203b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  }
204b645116853c677aca8a316381b87441ba6004f67danno@chromium.org}
205b645116853c677aca8a316381b87441ba6004f67danno@chromium.org
206b645116853c677aca8a316381b87441ba6004f67danno@chromium.orglistener_delegate = function(exec_state) {
207b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  CheckScopeChain([debug.ScopeType.Local,
208b645116853c677aca8a316381b87441ba6004f67danno@chromium.org                   debug.ScopeType.Block,
209b645116853c677aca8a316381b87441ba6004f67danno@chromium.org                   debug.ScopeType.Closure,
210b645116853c677aca8a316381b87441ba6004f67danno@chromium.org                   debug.ScopeType.Global], exec_state);
211b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  CheckScopeContent({}, 0, exec_state);
212b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  CheckScopeContent({z:4}, 1, exec_state);
213b645116853c677aca8a316381b87441ba6004f67danno@chromium.org  CheckScopeContent({a:1,x:2,y:3}, 2, exec_state);
214b645116853c677aca8a316381b87441ba6004f67danno@chromium.org};
215b645116853c677aca8a316381b87441ba6004f67danno@chromium.orgclosure_1(1)();
216b645116853c677aca8a316381b87441ba6004f67danno@chromium.orgEndTest();
217