| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 // This test forks a second vm process that runs a dart script as | 5 // This test forks a second vm process that runs a dart script as |
| 6 // a debug target, single stepping through the entire program, and | 6 // a debug target, single stepping through the entire program, and |
| 7 // recording each breakpoint. At the end, a coverage map of the source | 7 // recording each breakpoint. At the end, a coverage map of the source |
| 8 // is printed. | 8 // is printed. |
| 9 // | 9 // |
| 10 // Usage: dart coverage.dart [--wire] [--verbose] target_script.dart | 10 // Usage: dart coverage.dart [--wire] [--verbose] target_script.dart |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 var stdoutStringStream = targetProcess.stdout | 170 var stdoutStringStream = targetProcess.stdout |
| 171 .transform(new StringDecoder()) | 171 .transform(new StringDecoder()) |
| 172 .transform(new LineTransformer()); | 172 .transform(new LineTransformer()); |
| 173 stdoutStringStream.listen((line) { | 173 stdoutStringStream.listen((line) { |
| 174 if (showDebuggeeOutput) { | 174 if (showDebuggeeOutput) { |
| 175 print("TARG: $line"); | 175 print("TARG: $line"); |
| 176 } | 176 } |
| 177 if (line.startsWith("Debugger listening")) { | 177 if (line.startsWith("Debugger listening")) { |
| 178 RegExp portExpr = new RegExp(r"\d+"); | 178 RegExp portExpr = new RegExp(r"\d+"); |
| 179 var port = portExpr.stringMatch(line); | 179 var port = portExpr.stringMatch(line); |
| 180 print("Debug target found listening at port '$port'"); | 180 var pid = targetProcess.pid; |
| 181 print("Coverage target process (pid $pid) found " |
| 182 "listening on port $port."); |
| 181 openConnection(int.parse(port)); | 183 openConnection(int.parse(port)); |
| 182 } | 184 } |
| 183 }); | 185 }); |
| 184 | 186 |
| 185 var stderrStringStream = targetProcess.stderr | 187 var stderrStringStream = targetProcess.stderr |
| 186 .transform(new StringDecoder()) | 188 .transform(new StringDecoder()) |
| 187 .transform(new LineTransformer()); | 189 .transform(new LineTransformer()); |
| 188 stderrStringStream.listen((line) { | 190 stderrStringStream.listen((line) { |
| 189 if (showDebuggeeOutput) { | 191 if (showDebuggeeOutput) { |
| 190 print("TARG: $line"); | 192 print("TARG: $line"); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 220 assert(libraryId != null); | 222 assert(libraryId != null); |
| 221 } | 223 } |
| 222 if (msg["params"]["reason"] == "breakpoint") { | 224 if (msg["params"]["reason"] == "breakpoint") { |
| 223 Program.recordBp(this, msg); | 225 Program.recordBp(this, msg); |
| 224 } | 226 } |
| 225 } else { | 227 } else { |
| 226 error("Error: unknown debugger event received"); | 228 error("Error: unknown debugger event received"); |
| 227 } | 229 } |
| 228 } | 230 } |
| 229 | 231 |
| 230 // Handle one JSON message object and match it to the | 232 // Handle one JSON message object. |
| 231 // expected events and responses in the debugging script. | |
| 232 void handleMessage(Map<String,dynamic> receivedMsg) { | 233 void handleMessage(Map<String,dynamic> receivedMsg) { |
| 233 currentMessage = receivedMsg; | 234 currentMessage = receivedMsg; |
| 234 if (receivedMsg["event"] != null) { | 235 if (receivedMsg["event"] != null) { |
| 235 handleEvent(receivedMsg); | 236 handleEvent(receivedMsg); |
| 236 if (errorsDetected) { | 237 if (errorsDetected) { |
| 237 error("Error while handling debugger event"); | 238 error("Error while handling event message"); |
| 238 error("Event received from debug target: $receivedMsg"); | 239 error("Event received from coverage target: $receivedMsg"); |
| 239 } | 240 } |
| 240 } else if (receivedMsg["id"] != null) { | 241 } else if (receivedMsg["id"] != null) { |
| 241 // This is a response to the last command we sent. | 242 // This is a response to the last command we sent. |
| 242 int id = receivedMsg["id"]; | 243 int id = receivedMsg["id"]; |
| 243 assert(outstandingCommand != null); | 244 assert(outstandingCommand != null); |
| 244 assert(outstandingCommand.msg["id"] == id); | 245 assert(outstandingCommand.msg["id"] == id); |
| 245 outstandingCommand.handleResponse(receivedMsg); | 246 outstandingCommand.handleResponse(receivedMsg); |
| 246 outstandingCommand = null; | 247 outstandingCommand = null; |
| 247 } else { | 248 } else { |
| 248 error("Unexpected message from target"); | 249 error("Unexpected message from target"); |
| 249 } | 250 } |
| 250 } | 251 } |
| 251 | 252 |
| 252 // Handle data received over the wire from the debug target | 253 // Handle data received over the wire from the coverage target |
| 253 // process. Split input from JSON wire format into individual | 254 // process. Split input from JSON wire format into individual |
| 254 // message objects (maps). | 255 // message objects (maps). |
| 255 void handleMessages() { | 256 void handleMessages() { |
| 256 var msg = responses.getNextMessage(); | 257 var msg = responses.getNextMessage(); |
| 257 while (msg != null) { | 258 while (msg != null) { |
| 258 if (verboseWire) print("RECV: $msg"); | 259 if (verboseWire) print("RECV: $msg"); |
| 259 if (responses.haveGarbage()) { | 260 if (responses.haveGarbage()) { |
| 260 error("Error: leftover text after message: '${responses.buffer}'"); | 261 error("Error: leftover text after message: '${responses.buffer}'"); |
| 261 error("Previous message may be malformed, was: '$msg'"); | 262 error("Previous message may be malformed, was: '$msg'"); |
| 262 cleanup(); | 263 cleanup(); |
| 263 return; | 264 return; |
| 264 } | 265 } |
| 265 var msgObj = JSON.parse(msg); | 266 var msgObj = JSON.parse(msg); |
| 266 handleMessage(msgObj); | 267 handleMessage(msgObj); |
| 267 if (errorsDetected) { | 268 if (errorsDetected) { |
| 268 error("Error while handling message from debug target"); | 269 error("Error while handling message from coverage target"); |
| 269 error("Message received from debug target: $msg"); | 270 error("Message received from coverage target: $msg"); |
| 270 cleanup(); | 271 cleanup(); |
| 271 return; | 272 return; |
| 272 } | 273 } |
| 273 if (shutdownEventSeen) { | 274 if (shutdownEventSeen) { |
| 274 if (outstandingCommand != null) { | 275 if (outstandingCommand != null) { |
| 275 error("Error: outstanding command when shutdown received"); | 276 error("Error: outstanding command when shutdown received"); |
| 276 } | 277 } |
| 277 cleanup(); | 278 cleanup(); |
| 278 return; | 279 return; |
| 279 } | 280 } |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 (str) { | 321 (str) { |
| 321 try { | 322 try { |
| 322 responses.append(str); | 323 responses.append(str); |
| 323 handleMessages(); | 324 handleMessages(); |
| 324 } catch(e, trace) { | 325 } catch(e, trace) { |
| 325 print("Unexpected exception:\n$e\n$trace"); | 326 print("Unexpected exception:\n$e\n$trace"); |
| 326 cleanup(); | 327 cleanup(); |
| 327 } | 328 } |
| 328 }, | 329 }, |
| 329 onDone: () { | 330 onDone: () { |
| 330 print("Connection closed by debug target"); | 331 print("Connection closed by coverage target"); |
| 331 cleanup(); | 332 cleanup(); |
| 332 }, | 333 }, |
| 333 onError: (e) { | 334 onError: (e) { |
| 334 print("Error '$e' detected in input stream from debug target"); | 335 print("Error '$e' detected in input stream from coverage target"); |
| 335 cleanup(); | 336 cleanup(); |
| 336 }); | 337 }); |
| 337 }, | 338 }, |
| 338 onError: (e) { | 339 onError: (e) { |
| 339 String msg = "Error while connecting to debugee: $e"; | 340 String msg = "Error while connecting to coverage target: $e"; |
| 340 var trace = getAttachedStackTrace(e); | 341 var trace = getAttachedStackTrace(e); |
| 341 if (trace != null) msg += "\nStackTrace: $trace"; | 342 if (trace != null) msg += "\nStackTrace: $trace"; |
| 342 error(msg); | 343 error(msg); |
| 343 cleanup(); | 344 cleanup(); |
| 344 }); | 345 }); |
| 345 } | 346 } |
| 346 | 347 |
| 347 void cleanup() { | 348 void cleanup() { |
| 348 if (cleanupDone) return; | 349 if (cleanupDone) return; |
| 349 if (socket != null) { | 350 if (socket != null) { |
| 350 socket.close().catchError((error) { | 351 socket.close().catchError((error) { |
| 351 // Print this directly in addition to adding it to the | 352 // Print this directly in addition to adding it to the |
| 352 // error message queue, in case the error message queue | 353 // error message queue, in case the error message queue |
| 353 // gets printed before this error handler is called. | 354 // gets printed before this error handler is called. |
| 354 print("Error occurred while closing socket: $error"); | 355 print("Error occurred while closing socket: $error"); |
| 355 error("Error while closing socket: $error"); | 356 error("Error while closing socket: $error"); |
| 356 }); | 357 }); |
| 357 } | 358 } |
| 358 var targetPid = targetProcess.pid; | 359 var targetPid = targetProcess.pid; |
| 359 print("Sending kill signal to process $targetPid..."); | 360 print("Sending kill signal to process $targetPid."); |
| 360 targetProcess.kill(); | 361 targetProcess.kill(); |
| 361 // If the process was already dead exitCode is already | 362 // If the process was already dead exitCode is already |
| 362 // available and we call exit() in the next event loop cycle. | 363 // available and we call exit() in the next event loop cycle. |
| 363 // Otherwise this will wait for the process to exit. | 364 // Otherwise this will wait for the process to exit. |
| 364 | 365 |
| 365 targetProcess.exitCode.then((exitCode) { | 366 targetProcess.exitCode.then((exitCode) { |
| 366 print("process $targetPid terminated with exit code $exitCode."); | 367 print("Process $targetPid terminated with exit code $exitCode."); |
| 367 if (errorsDetected) { | 368 if (errorsDetected) { |
| 368 print("\n===== Errors detected: ====="); | 369 print("\n===== Errors detected: ====="); |
| 369 for (int i = 0; i < errors.length; i++) print(errors[i]); | 370 for (int i = 0; i < errors.length; i++) print(errors[i]); |
| 370 print("============================\n"); | 371 print("============================\n"); |
| 371 } | 372 } |
| 372 Program.printCoverage(); | 373 Program.printCoverage(); |
| 373 exit(errors.length); | 374 exit(errors.length); |
| 374 }); | 375 }); |
| 375 cleanupDone = true; | 376 cleanupDone = true; |
| 376 } | 377 } |
| 377 } | 378 } |
| 378 | 379 |
| 379 | 380 |
| 380 // Class to buffer wire protocol data from debug target and | 381 // Class to buffer wire protocol data from coverage target and |
| 381 // break it down to individual json messages. | 382 // break it down to individual json messages. |
| 382 class JsonBuffer { | 383 class JsonBuffer { |
| 383 String buffer = null; | 384 String buffer = null; |
| 384 | 385 |
| 385 append(String s) { | 386 append(String s) { |
| 386 if (buffer == null || buffer.length == 0) { | 387 if (buffer == null || buffer.length == 0) { |
| 387 buffer = s; | 388 buffer = s; |
| 388 } else { | 389 } else { |
| 389 buffer = buffer.concat(s); | 390 buffer = buffer.concat(s); |
| 390 } | 391 } |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 483 targetOpts.add(str); | 484 targetOpts.add(str); |
| 484 break; | 485 break; |
| 485 } | 486 } |
| 486 } | 487 } |
| 487 | 488 |
| 488 Process.start(options.executable, targetOpts).then((Process process) { | 489 Process.start(options.executable, targetOpts).then((Process process) { |
| 489 process.stdin.close(); | 490 process.stdin.close(); |
| 490 var debugger = new Debugger(process); | 491 var debugger = new Debugger(process); |
| 491 }); | 492 }); |
| 492 } | 493 } |
| OLD | NEW |