| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file | |
| 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.md file. | |
| 4 | |
| 5 import 'dart:async' show | |
| 6 Completer, | |
| 7 Future, | |
| 8 Stream, | |
| 9 StreamController, | |
| 10 Zone; | |
| 11 | |
| 12 import 'dart:convert' show | |
| 13 UTF8; | |
| 14 | |
| 15 import 'package:expect/expect.dart' show | |
| 16 Expect; | |
| 17 | |
| 18 import 'package:fletchc/src/diagnostic.dart'; | |
| 19 | |
| 20 import 'package:fletchc/src/messages.dart'; | |
| 21 | |
| 22 import 'package:fletchc/src/message_examples.dart'; | |
| 23 | |
| 24 import 'package:fletchc/src/hub/sentence_parser.dart' show | |
| 25 NamedTarget, | |
| 26 Sentence, | |
| 27 parseSentence; | |
| 28 | |
| 29 import 'package:fletchc/src/verbs/actions.dart' show | |
| 30 Action; | |
| 31 | |
| 32 import 'package:fletchc/src/hub/hub_main.dart' show | |
| 33 ClientLogger, | |
| 34 ClientConnection, | |
| 35 IsolatePool, | |
| 36 handleVerb; | |
| 37 | |
| 38 import 'package:fletchc/src/worker/worker_main.dart' show | |
| 39 workerMain; | |
| 40 | |
| 41 import 'package:fletchc/src/hub/session_manager.dart' show | |
| 42 endAllSessions; | |
| 43 | |
| 44 import 'package:fletchc/src/hub/client_commands.dart' show | |
| 45 ClientCommand, | |
| 46 ClientCommandCode; | |
| 47 | |
| 48 import 'package:fletchc/src/verbs/infrastructure.dart' show | |
| 49 AnalyzedSentence, | |
| 50 Options, | |
| 51 analyzeSentence; | |
| 52 | |
| 53 import 'package:fletchc/src/worker/developer.dart' show | |
| 54 parseSettings; | |
| 55 | |
| 56 final IsolatePool pool = new IsolatePool(workerMain); | |
| 57 | |
| 58 Future<Null> main() async { | |
| 59 for (DiagnosticKind kind in DiagnosticKind.values) { | |
| 60 Expect.isNotNull(getMessage(kind), "$kind"); | |
| 61 | |
| 62 List<Example> examples = getExamples(kind); | |
| 63 Expect.isNotNull(examples, "$kind"); | |
| 64 Expect.isFalse(examples.isEmpty, "$kind"); | |
| 65 int exampleCount = 1; | |
| 66 for (Example example in examples) { | |
| 67 print("\n\nTesting $kind ${exampleCount++}"); | |
| 68 Expect.isNotNull(example); | |
| 69 await checkExample(kind, example); | |
| 70 endAllSessions(); | |
| 71 pool.shutdown(); | |
| 72 } | |
| 73 print("Done testing $kind"); | |
| 74 } | |
| 75 } | |
| 76 | |
| 77 Future<Null> checkExample(DiagnosticKind kind, Example example) async { | |
| 78 if (example is CommandLineExample) { | |
| 79 await checkCommandLineExample(kind, example); | |
| 80 } else if (example is SettingsExample) { | |
| 81 checkSettingsExample(kind, example); | |
| 82 } else if (example is Untestable) { | |
| 83 // Ignored. | |
| 84 } else { | |
| 85 throw "Unknown kind of example: $example"; | |
| 86 } | |
| 87 } | |
| 88 | |
| 89 void checkSettingsExample(DiagnosticKind kind, SettingsExample example) { | |
| 90 Uri mockUri = new Uri(scheme: "org.dartlang.tests.mock"); | |
| 91 try { | |
| 92 parseSettings(example.data, mockUri); | |
| 93 throw "Settings example: '${example.data}' " | |
| 94 "didn't produce the expected '$kind' error"; | |
| 95 } on InputError catch (e) { | |
| 96 Expect.isNotNull(e); | |
| 97 Expect.equals(kind, e.kind, '$e'); | |
| 98 // Ensure that the diagnostic can be turned into a formatted error message. | |
| 99 String message = e.asDiagnostic().formatMessage(); | |
| 100 Expect.isNotNull(message); | |
| 101 } | |
| 102 } | |
| 103 | |
| 104 Future<Null> checkCommandLineExample( | |
| 105 DiagnosticKind kind, | |
| 106 CommandLineExample example) async { | |
| 107 List<List<String>> lines = <List<String>>[]; | |
| 108 if (example.line1 != null) { | |
| 109 lines.add(example.line1); | |
| 110 } | |
| 111 if (example.line2 != null) { | |
| 112 lines.add(example.line2); | |
| 113 } | |
| 114 if (example.line3 != null) { | |
| 115 lines.add(example.line3); | |
| 116 } | |
| 117 List<String> lastLine = lines.removeLast(); | |
| 118 for (List<String> setup in lines) { | |
| 119 MockClientConnection mock = await mockCommandLine(setup); | |
| 120 await mock.done; | |
| 121 Expect.isNull(mock.recordedError); | |
| 122 Expect.equals(0, mock.recordedExitCode); | |
| 123 } | |
| 124 MockClientConnection mock = await mockCommandLine(lastLine); | |
| 125 if (kind == DiagnosticKind.socketVmConnectError) { | |
| 126 await mock.done; | |
| 127 Options options = Options.parse(lastLine); | |
| 128 Sentence sentence = parseSentence(options.nonOptionArguments); | |
| 129 NamedTarget target = sentence.targets.single; | |
| 130 String message = mock.stderrMessages.single; | |
| 131 String expectedMessage = new Diagnostic( | |
| 132 kind, getMessage(kind), | |
| 133 {DiagnosticParameter.address: target.name, | |
| 134 DiagnosticParameter.message: '.*'}) | |
| 135 .formatMessage(); | |
| 136 Expect.stringEquals( | |
| 137 message, | |
| 138 new RegExp(expectedMessage).stringMatch(message)); | |
| 139 } else if (kind == DiagnosticKind.attachToVmBeforeRun) { | |
| 140 await mock.done; | |
| 141 Expect.stringEquals(getMessage(kind), mock.stderrMessages.single); | |
| 142 } else { | |
| 143 Expect.isNotNull(mock.recordedError); | |
| 144 Expect.equals(kind, mock.recordedError.kind, '${mock.recordedError}'); | |
| 145 // Ensure that the diagnostic can be turned into a formatted error message. | |
| 146 String message = mock.recordedError.asDiagnostic().formatMessage(); | |
| 147 Expect.isNotNull(message); | |
| 148 } | |
| 149 Expect.equals(1, mock.recordedExitCode); | |
| 150 } | |
| 151 | |
| 152 Future<MockClientConnection> mockCommandLine(List<String> arguments) async { | |
| 153 print("Command line: ${arguments.join(' ')}"); | |
| 154 MockClientConnection client = new MockClientConnection(); | |
| 155 await handleVerb(arguments, client, pool); | |
| 156 return client; | |
| 157 } | |
| 158 | |
| 159 class MockClientConnection implements ClientConnection { | |
| 160 InputError recordedError; | |
| 161 | |
| 162 int recordedExitCode; | |
| 163 | |
| 164 final ClientLogger log = new MockClientLogger(); | |
| 165 | |
| 166 final Completer mockCompleter = new Completer(); | |
| 167 | |
| 168 final List<String> stderrMessages = <String>[]; | |
| 169 | |
| 170 final StreamController<ClientCommand> controller = | |
| 171 new StreamController<ClientCommand>(); | |
| 172 | |
| 173 AnalyzedSentence sentence; | |
| 174 | |
| 175 MockClientConnection(); | |
| 176 | |
| 177 get completer => mockCompleter; | |
| 178 | |
| 179 get done => completer.future; | |
| 180 | |
| 181 get commands => controller.stream; | |
| 182 | |
| 183 void sendCommandToWorker(ClientCommand command) { | |
| 184 controller.add(command); | |
| 185 } | |
| 186 | |
| 187 sendCommandToClient(ClientCommand command) { | |
| 188 switch (command.code) { | |
| 189 case ClientCommandCode.ExitCode: | |
| 190 exit(command.data); | |
| 191 break; | |
| 192 | |
| 193 case ClientCommandCode.Stderr: | |
| 194 printLineOnStderr(mockStripNewline(UTF8.decode(command.data))); | |
| 195 break; | |
| 196 | |
| 197 case ClientCommandCode.Stdout: | |
| 198 printLineOnStdout(mockStripNewline(UTF8.decode(command.data))); | |
| 199 break; | |
| 200 | |
| 201 default: | |
| 202 throw "Unexpected command: ${command.code}"; | |
| 203 } | |
| 204 } | |
| 205 | |
| 206 mockStripNewline(String line) { | |
| 207 if (line.endsWith("\n")) { | |
| 208 return line.substring(0, line.length - 1); | |
| 209 } else { | |
| 210 return line; | |
| 211 } | |
| 212 } | |
| 213 | |
| 214 endSession() { | |
| 215 completer.complete(null); | |
| 216 } | |
| 217 | |
| 218 mockPrintLine(String line) { | |
| 219 Zone zone = Zone.current.parent; | |
| 220 if (zone == null) { | |
| 221 zone = Zone.current; | |
| 222 } | |
| 223 zone.print(line); | |
| 224 } | |
| 225 | |
| 226 printLineOnStderr(line) { | |
| 227 stderrMessages.add(line); | |
| 228 mockPrintLine('stderr: $line'); | |
| 229 } | |
| 230 | |
| 231 printLineOnStdout(line) { | |
| 232 mockPrintLine('stdout: $line'); | |
| 233 } | |
| 234 | |
| 235 exit(int exitCode) { | |
| 236 recordedExitCode = exitCode; | |
| 237 if (!completer.isCompleted) { | |
| 238 endSession(); | |
| 239 } | |
| 240 } | |
| 241 | |
| 242 int reportErrorToClient(InputError error, StackTrace stackTrace) { | |
| 243 recordedError = error; | |
| 244 completer.complete(null); | |
| 245 return 1; | |
| 246 } | |
| 247 | |
| 248 AnalyzedSentence parseArguments(List<String> arguments) { | |
| 249 Options options = Options.parse(arguments); | |
| 250 Sentence sentence = parseSentence(options.nonOptionArguments); | |
| 251 this.sentence = analyzeSentence(sentence, null); | |
| 252 return this.sentence; | |
| 253 } | |
| 254 | |
| 255 handleClientCommand(_) => throw "not supported"; | |
| 256 handleClientCommandError(e, s) => throw "not supported"; | |
| 257 handleClientCommandsDone() => throw "not supported"; | |
| 258 start() => throw "not supported"; | |
| 259 get arguments => throw "not supported"; | |
| 260 get argumentsCompleter => throw "not supported"; | |
| 261 set argumentsCompleter(_) => throw "not supported"; | |
| 262 get commandSender => throw "not supported"; | |
| 263 set commandSender(_) => throw "not supported"; | |
| 264 set completer(_) => throw "not supported"; | |
| 265 get fletchVm => throw "not supported"; | |
| 266 set fletchVm(_) => throw "not supported"; | |
| 267 get requiresWorker => throw "not supported"; | |
| 268 get socket => throw "not supported"; | |
| 269 get subscription => throw "not supported"; | |
| 270 set subscription(_) => throw "not supported"; | |
| 271 } | |
| 272 | |
| 273 class MockClientLogger implements ClientLogger { | |
| 274 static int clientsAllocated = 0; | |
| 275 | |
| 276 final int id = clientsAllocated++; | |
| 277 | |
| 278 void note(object) { | |
| 279 print("$id: $object"); | |
| 280 gotArguments(null); // Removes an "unused" warning from dart2js. | |
| 281 } | |
| 282 | |
| 283 void gotArguments(_) { | |
| 284 } | |
| 285 | |
| 286 void done() { | |
| 287 } | |
| 288 | |
| 289 void error(error, StackTrace stackTrace) { | |
| 290 throw error; | |
| 291 } | |
| 292 | |
| 293 get arguments => throw "not supported"; | |
| 294 set arguments(_) => throw "not supported"; | |
| 295 get notes => throw "not supported"; | |
| 296 } | |
| OLD | NEW |