Index: test/debugger/test-api.js |
diff --git a/test/debugger/test-api.js b/test/debugger/test-api.js |
index 69c7c5d21937feace158cef15452dcaeb2c4ebbc..05acbbb8aa80f63aaa7ee7846efc24f983384ba8 100644 |
--- a/test/debugger/test-api.js |
+++ b/test/debugger/test-api.js |
@@ -155,18 +155,22 @@ class DebugWrapper { |
this.takeReplyChecked(msgid); |
} |
- // Returns the serialized result of the given expression. For example: |
- // {"type":"number", "value":33, "description":"33"}. |
- evaluate(frameid, expression) { |
+ debuggerFlags() { |
+ return { breakPointsActive : |
+ { setValue : (enabled) => this.setBreakPointsActive(enabled) } |
+ }; |
+ } |
+ |
+ scripts() { |
+ // Collect all scripts in the heap. |
+ return %DebugGetLoadedScripts(); |
+ } |
+ |
+ setBreakPointsActive(enabled) { |
const {msgid, msg} = this.createMessage( |
- "Debugger.evaluateOnCallFrame", |
- { callFrameId : frameid, |
- expression : expression |
- }); |
+ "Debugger.setBreakpointsActive", { active : enabled }); |
this.sendMessage(msg); |
- |
- const reply = this.takeReplyChecked(msgid); |
- return reply.result.result; |
+ this.takeReplyChecked(msgid); |
} |
// --- Internal methods. ----------------------------------------------------- |
@@ -236,13 +240,64 @@ class DebugWrapper { |
} |
} |
+ execStateScopeObjectProperty(serialized_scope, prop) { |
+ let found = null; |
+ for (let i = 0; i < serialized_scope.length; i++) { |
+ const elem = serialized_scope[i]; |
+ if (elem.name == prop) { |
+ found = elem; |
+ break; |
+ } |
+ } |
+ |
+ if (found == null) return { isUndefined : true } |
+ |
+ const val = { value : () => found.value.value }; |
+ return { value : () => val, |
+ isUndefined : () => found.value.type == "undefined" |
+ }; |
+ } |
+ |
// Returns an array of property descriptors of the scope object. |
// This is in contrast to the original API, which simply passed object |
// mirrors. |
execStateScopeObject(obj) { |
const serialized_scope = this.getProperties(obj.objectId); |
- const scope = {} |
- const scope_tuples = serialized_scope.forEach((elem) => { |
+ const scope = this.propertiesToObject(serialized_scope); |
+ return { value : () => scope, |
+ property : (prop) => |
+ this.execStateScopeObjectProperty(serialized_scope, prop) |
+ }; |
+ } |
+ |
+ setVariableValue(frame, scope_index, name, value) { |
+ const frameid = frame.callFrameId; |
+ const {msgid, msg} = this.createMessage( |
+ "Debugger.setVariableValue", |
+ { callFrameId : frameid, |
+ scopeNumber : scope_index, |
+ variableName : name, |
+ newValue : { value : value } |
+ }); |
+ this.sendMessage(msg); |
+ this.takeReplyChecked(msgid); |
+ } |
+ |
+ execStateScope(frame, scope_index) { |
+ const scope = frame.scopeChain[scope_index]; |
+ return { scopeType : () => this.execStateScopeType(scope.type), |
+ scopeObject : () => this.execStateScopeObject(scope.object), |
+ setVariableValue : |
+ (name, value) => this.setVariableValue(frame, scope_index, |
+ name, value) |
+ }; |
+ } |
+ |
+ // Takes a list of properties as produced by getProperties and turns them |
+ // into an object. |
+ propertiesToObject(props) { |
+ const obj = {} |
+ props.forEach((elem) => { |
const key = elem.name; |
let value; |
@@ -254,16 +309,10 @@ class DebugWrapper { |
} |
} |
- scope[key] = value; |
+ obj[key] = value; |
}) |
- return { value : () => scope }; |
- } |
- |
- execStateScope(scope) { |
- return { scopeType : () => this.execStateScopeType(scope.type), |
- scopeObject : () => this.execStateScopeObject(scope.object) |
- }; |
+ return obj; |
} |
getProperties(objectId) { |
@@ -312,7 +361,38 @@ class DebugWrapper { |
return { value : () => localValue }; |
} |
- execStateFrameEvaluate(frame, expr) { |
+ reconstructRemoteObject(obj) { |
+ let value = obj.value; |
+ if (obj.type == "object") { |
+ if (obj.subtype == "error") { |
+ const desc = obj.description; |
+ switch (obj.className) { |
+ case "EvalError": throw new EvalError(desc); |
+ case "RangeError": throw new RangeError(desc); |
+ case "ReferenceError": throw new ReferenceError(desc); |
+ case "SyntaxError": throw new SyntaxError(desc); |
+ case "TypeError": throw new TypeError(desc); |
+ case "URIError": throw new URIError(desc); |
+ default: throw new Error(desc); |
+ } |
+ } else if (obj.subtype == "array") { |
+ const array = []; |
+ const props = this.propertiesToObject( |
+ this.getProperties(obj.objectId)); |
+ for (let i = 0; i < props.length; i++) { |
+ array[i] = props[i]; |
+ } |
+ value = array; |
+ } |
+ } |
+ |
+ return { value : () => value, |
+ isUndefined : () => obj.type == "undefined" |
+ }; |
+ |
+ } |
+ |
+ evaluateOnCallFrame(frame, expr) { |
const frameid = frame.callFrameId; |
const {msgid, msg} = this.createMessage( |
"Debugger.evaluateOnCallFrame", |
@@ -323,11 +403,7 @@ class DebugWrapper { |
const reply = this.takeReplyChecked(msgid); |
const result = reply.result.result; |
- if (result.subtype == "error") { |
- throw new Error(result.description); |
- } |
- |
- return { value : () => result.value }; |
+ return this.reconstructRemoteObject(result); |
} |
execStateFrame(frame) { |
@@ -336,17 +412,68 @@ class DebugWrapper { |
const column = frame.location.columnNumber; |
const loc = %ScriptLocationFromLine2(scriptid, line, column, 0); |
const func = { name : () => frame.functionName }; |
- return { sourceLineText : () => loc.sourceText, |
- evaluate : (expr) => this.execStateFrameEvaluate(frame, expr), |
+ |
+ function allScopes() { |
+ const scopes = []; |
+ for (let i = 0; i < frame.scopeChain.length; i++) { |
+ scopes.push(this.execStateScope(frame, i)); |
+ } |
+ return scopes; |
+ }; |
+ |
+ return { sourceColumn : () => loc.column, |
+ sourceLine : () => loc.line + 1, |
+ sourceLineText : () => loc.sourceText, |
+ evaluate : (expr) => this.evaluateOnCallFrame(frame, expr), |
functionName : () => frame.functionName, |
func : () => func, |
localCount : () => this.execStateFrameLocalCount(frame), |
localName : (ix) => this.execStateFrameLocalName(frame, ix), |
localValue: (ix) => this.execStateFrameLocalValue(frame, ix), |
scopeCount : () => frame.scopeChain.length, |
- scope : (index) => this.execStateScope(frame.scopeChain[index]), |
- allScopes : () => frame.scopeChain.map( |
- this.execStateScope.bind(this)) |
+ scope : (index) => this.execStateScope(frame, index), |
+ allScopes : allScopes.bind(this) |
+ }; |
+ } |
+ |
+ eventDataException(params) { |
+ switch (params.data.type) { |
+ case "string": { |
+ return params.data.value; |
+ } |
+ case "object": { |
+ const props = this.getProperties(params.data.objectId); |
+ return this.propertiesToObject(props); |
+ } |
+ default: { |
+ return undefined; |
+ } |
+ } |
+ } |
+ |
+ eventDataScriptSource(id) { |
+ const {msgid, msg} = this.createMessage( |
+ "Debugger.getScriptSource", { scriptId : id }); |
+ this.sendMessage(msg); |
+ const reply = this.takeReplyChecked(msgid); |
+ return reply.result.scriptSource; |
+ } |
+ |
+ eventDataScriptSetSource(id, src) { |
+ const {msgid, msg} = this.createMessage( |
+ "Debugger.setScriptSource", { scriptId : id, scriptSource : src }); |
+ this.sendMessage(msg); |
+ this.takeReplyChecked(msgid); |
+ } |
+ |
+ eventDataScript(params) { |
+ const id = params.scriptId; |
+ const name = params.url ? params.url : undefined; |
+ |
+ return { id : () => id, |
+ name : () => name, |
+ source : () => this.eventDataScriptSource(id), |
+ setSource : (src) => this.eventDataScriptSetSource(id, src) |
}; |
} |
@@ -358,6 +485,8 @@ class DebugWrapper { |
this.handleDebuggerPaused(message); |
} else if (method == "Debugger.scriptParsed") { |
this.handleDebuggerScriptParsed(message); |
+ } else if (method == "Debugger.scriptFailedToParse") { |
+ this.handleDebuggerScriptFailedToParse(message); |
} |
} |
@@ -391,6 +520,7 @@ class DebugWrapper { |
let eventData = this.execStateFrame(params.callFrames[0]); |
if (debugEvent == this.DebugEvent.Exception) { |
eventData.uncaught = () => params.data.uncaught; |
+ eventData.exception = () => this.eventDataException(params); |
} |
this.invokeListener(debugEvent, execState, eventData); |
@@ -399,6 +529,7 @@ class DebugWrapper { |
handleDebuggerScriptParsed(message) { |
const params = message.params; |
let eventData = { scriptId : params.scriptId, |
+ script : () => this.eventDataScript(params), |
eventType : this.DebugEvent.AfterCompile |
} |
@@ -408,6 +539,19 @@ class DebugWrapper { |
undefined); |
} |
+ handleDebuggerScriptFailedToParse(message) { |
+ const params = message.params; |
+ let eventData = { scriptId : params.scriptId, |
+ script : () => this.eventDataScript(params), |
+ eventType : this.DebugEvent.CompileError |
+ } |
+ |
+ // TODO(jgruber): Arguments as needed. Still completely missing exec_state, |
+ // and eventData used to contain the script mirror instead of its id. |
+ this.invokeListener(this.DebugEvent.CompileError, undefined, eventData, |
+ undefined); |
+ } |
+ |
invokeListener(event, exec_state, event_data, data) { |
if (this.listener) { |
this.listener(event, exec_state, event_data, data); |