| // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file | 
 | // for details. All rights reserved. Use of this source code is governed by a | 
 | // BSD-style license that can be found in the LICENSE file. | 
 |  | 
 | library record_and_replay; | 
 |  | 
 | import 'dart:io'; | 
 | import 'dart:json' as json; | 
 | import 'dart:utf'; | 
 |  | 
 | import 'test_runner.dart'; | 
 | import 'utils.dart' show Path; | 
 |  | 
 | /* | 
 |  * Json files look like this: | 
 |  * | 
 |  * [ | 
 |  *   { | 
 |  *     'name' : '...', | 
 |  *     'command' : { | 
 |  *       'timeout_limit' : 60, | 
 |  *       'executable' : '...', | 
 |  *       'arguments' : ['arg1, 'arg2', '...'], | 
 |  *     }, | 
 |  *     'command_output' : { | 
 |  *       'exit_code' : 42, | 
 |  *       'stdout' : '...', | 
 |  *       'stderr' : '...', | 
 |  *       'duration' : 1.5, | 
 |  *       'did_timeout' : false, | 
 |  *     }, | 
 |  *   }, | 
 |  *   .... | 
 |  * ] | 
 |  */ | 
 |  | 
 | List<String> makePathsRelativeToDart(String cwd, List<String> arguments) { | 
 |   var relativeArguments = []; | 
 |   for (var rawArgument in arguments) { | 
 |     if (rawArgument.startsWith(cwd)) { | 
 |       var relative = new Path(rawArgument).relativeTo(new Path(cwd)); | 
 |       relativeArguments.add(relative.toNativePath()); | 
 |     } else { | 
 |       relativeArguments.add(rawArgument); | 
 |     } | 
 |   } | 
 |   return relativeArguments; | 
 | } | 
 |  | 
 | class TestCaseRecorder { | 
 |   Path _outputPath; | 
 |   List<Map> _recordedCommandInvocations = []; | 
 |   var _cwd; | 
 |  | 
 |   TestCaseRecorder(this._outputPath) { | 
 |     _cwd  = Directory.current.path; | 
 |   } | 
 |  | 
 |   void nextCommand(Command command, int timeout) { | 
 |     // Convert arguments from absolute to relative paths (relative to the dart | 
 |     // directory) because the absolute path on the machine where we record | 
 |     // may be different from the absolute path on the machine where we execute | 
 |     // the commands. | 
 |     var arguments = makePathsRelativeToDart(_cwd, command.arguments); | 
 |  | 
 |     var commandExecution = { | 
 |       'name' : command.displayName, | 
 |       'command' : { | 
 |         'timeout_limit' : timeout, | 
 |         'executable' : command.executable, | 
 |         'arguments' : arguments, | 
 |       }, | 
 |     }; | 
 |     _recordedCommandInvocations.add(commandExecution); | 
 |   } | 
 |  | 
 |   void finish() { | 
 |     var file = new File(_outputPath.toNativePath()); | 
 |     var jsonString = json.stringify(_recordedCommandInvocations); | 
 |     file.writeAsStringSync(jsonString); | 
 |     print("TestCaseRecorder: written all TestCases to ${_outputPath}"); | 
 |   } | 
 | } | 
 |  | 
 | class TestCaseOutputArchive { | 
 |   Map<String, Map> _commandOutputRecordings; | 
 |   var _cwd; | 
 |  | 
 |   TestCaseOutputArchive() { | 
 |     _cwd  = Directory.current.path; | 
 |   } | 
 |  | 
 |   void loadFromPath(Path recordingPath) { | 
 |     var file = new File(recordingPath.toNativePath()); | 
 |     var commandRecordings = json.parse(file.readAsStringSync()); | 
 |     _commandOutputRecordings = {}; | 
 |     for (var commandRecording in commandRecordings) { | 
 |       var key = _indexKey(commandRecording['command']['executable'], | 
 |                           commandRecording['command']['arguments'].join(' ')); | 
 |       _commandOutputRecordings[key] = commandRecording['command_output']; | 
 |     } | 
 |   } | 
 |  | 
 |   CommandOutput outputOf(Command command) { | 
 |     // Convert arguments from absolute to relative paths (relative to the dart | 
 |     // directory) because the absolute path on the machine where we record | 
 |     // may be different from the absolute path on the machine where we execute | 
 |     // the commands. | 
 |     var arguments = makePathsRelativeToDart(_cwd, command.arguments); | 
 |  | 
 |     var key = _indexKey(command.executable, arguments.join(' ')); | 
 |     var command_output = _commandOutputRecordings[key]; | 
 |     if (command_output == null) { | 
 |       print("Sorry, but there is no command output for ${command.displayName}" | 
 |             " ($command)"); | 
 |       exit(42); | 
 |     } | 
 |  | 
 |     double seconds = command_output['duration']; | 
 |     var duration = new Duration(seconds: seconds.round(), | 
 |                                 milliseconds: (seconds/1000).round()); | 
 |     var commandOutput = createCommandOutput( | 
 |         command, | 
 |         command_output['exit_code'], | 
 |         command_output['did_timeout'], | 
 |         encodeUtf8(command_output['stdout']), | 
 |         encodeUtf8(command_output['stderr']), | 
 |         duration, | 
 |         false); | 
 |     return commandOutput; | 
 |   } | 
 |  | 
 |   String _indexKey(String executable, String arguments) { | 
 |     return "${executable}__$arguments"; | 
 |   } | 
 | } | 
 |  |