OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2015, the Dart 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 file. |
| 4 |
| 5 // TODO(nweiz): This is under lib so that it can be used by the unittest dummy |
| 6 // package. Once that package is no longer being updated, move this back into |
| 7 // bin. |
| 8 library test.executable; |
| 9 |
| 10 import 'dart:io'; |
| 11 |
| 12 import 'package:stack_trace/stack_trace.dart'; |
| 13 import 'package:yaml/yaml.dart'; |
| 14 |
| 15 import 'runner.dart'; |
| 16 import 'runner/application_exception.dart'; |
| 17 import 'runner/configuration.dart'; |
| 18 import 'util/exit_codes.dart' as exit_codes; |
| 19 import 'util/io.dart'; |
| 20 import 'utils.dart'; |
| 21 |
| 22 /// A merged stream of all signals that tell the test runner to shut down |
| 23 /// gracefully. |
| 24 /// |
| 25 /// Signals will only be captured as long as this has an active subscription. |
| 26 /// Otherwise, they'll be handled by Dart's default signal handler, which |
| 27 /// terminates the program immediately. |
| 28 final _signals = Platform.isWindows |
| 29 ? ProcessSignal.SIGINT.watch() |
| 30 : mergeStreams([ |
| 31 ProcessSignal.SIGTERM.watch(), |
| 32 ProcessSignal.SIGINT.watch() |
| 33 ]); |
| 34 |
| 35 /// Returns whether the current package has a pubspec which uses the |
| 36 /// `test/pub_serve` transformer. |
| 37 bool get _usesTransformer { |
| 38 if (!new File('pubspec.yaml').existsSync()) return false; |
| 39 var contents = new File('pubspec.yaml').readAsStringSync(); |
| 40 |
| 41 var yaml; |
| 42 try { |
| 43 yaml = loadYaml(contents); |
| 44 } on FormatException { |
| 45 return false; |
| 46 } |
| 47 |
| 48 if (yaml is! Map) return false; |
| 49 |
| 50 var transformers = yaml['transformers']; |
| 51 if (transformers == null) return false; |
| 52 if (transformers is! List) return false; |
| 53 |
| 54 return transformers.any((transformer) { |
| 55 if (transformer is String) return transformer == 'test/pub_serve'; |
| 56 if (transformer is! Map) return false; |
| 57 if (transformer.keys.length != 1) return false; |
| 58 return transformer.keys.single == 'test/pub_serve'; |
| 59 }); |
| 60 } |
| 61 |
| 62 main(List<String> args) async { |
| 63 var configuration; |
| 64 try { |
| 65 configuration = new Configuration.parse(args); |
| 66 } on FormatException catch (error) { |
| 67 _printUsage(error.message); |
| 68 exitCode = exit_codes.usage; |
| 69 return; |
| 70 } |
| 71 |
| 72 if (configuration.help) { |
| 73 _printUsage(); |
| 74 return; |
| 75 } |
| 76 |
| 77 if (configuration.version) { |
| 78 if (!_printVersion()) { |
| 79 stderr.writeln("Couldn't find version number."); |
| 80 exitCode = exit_codes.data; |
| 81 } |
| 82 return; |
| 83 } |
| 84 |
| 85 if (configuration.pubServeUrl != null && !_usesTransformer) { |
| 86 stderr.write(''' |
| 87 When using --pub-serve, you must include the "test/pub_serve" transformer in |
| 88 your pubspec: |
| 89 |
| 90 transformers: |
| 91 - test/pub_serve: |
| 92 \$include: test/**_test.dart |
| 93 '''); |
| 94 exitCode = exit_codes.data; |
| 95 return; |
| 96 } |
| 97 |
| 98 if (!configuration.explicitPaths && |
| 99 !new Directory(configuration.paths.single).existsSync()) { |
| 100 _printUsage('No test files were passed and the default "test/" ' |
| 101 "directory doesn't exist."); |
| 102 exitCode = exit_codes.data; |
| 103 return; |
| 104 } |
| 105 |
| 106 var runner = new Runner(configuration); |
| 107 |
| 108 var signalSubscription; |
| 109 close() async { |
| 110 if (signalSubscription == null) return; |
| 111 signalSubscription.cancel(); |
| 112 signalSubscription = null; |
| 113 stdinLines.cancel(immediate: true); |
| 114 await runner.close(); |
| 115 } |
| 116 |
| 117 signalSubscription = _signals.listen((_) => close()); |
| 118 |
| 119 try { |
| 120 exitCode = (await runner.run()) ? 0 : 1; |
| 121 } on ApplicationException catch (error) { |
| 122 stderr.writeln(error.message); |
| 123 exitCode = exit_codes.data; |
| 124 } catch (error, stackTrace) { |
| 125 stderr.writeln(getErrorMessage(error)); |
| 126 stderr.writeln(new Trace.from(stackTrace).terse); |
| 127 stderr.writeln( |
| 128 "This is an unexpected error. Please file an issue at " |
| 129 "http://github.com/dart-lang/test\n" |
| 130 "with the stack trace and instructions for reproducing the error."); |
| 131 exitCode = exit_codes.software; |
| 132 } finally { |
| 133 await close(); |
| 134 } |
| 135 } |
| 136 |
| 137 /// Print usage information for this command. |
| 138 /// |
| 139 /// If [error] is passed, it's used in place of the usage message and the whole |
| 140 /// thing is printed to stderr instead of stdout. |
| 141 void _printUsage([String error]) { |
| 142 var output = stdout; |
| 143 |
| 144 var message = "Runs tests in this package."; |
| 145 if (error != null) { |
| 146 message = error; |
| 147 output = stderr; |
| 148 } |
| 149 |
| 150 output.write("""$message |
| 151 |
| 152 Usage: pub run test:test [files or directories...] |
| 153 |
| 154 ${Configuration.usage} |
| 155 """); |
| 156 } |
| 157 |
| 158 /// Prints the version number of the test package. |
| 159 /// |
| 160 /// This loads the version number from the current package's lockfile. It |
| 161 /// returns true if it successfully printed the version number and false if it |
| 162 /// couldn't be loaded. |
| 163 bool _printVersion() { |
| 164 var lockfile; |
| 165 try { |
| 166 lockfile = loadYaml(new File("pubspec.lock").readAsStringSync()); |
| 167 } on FormatException catch (_) { |
| 168 return false; |
| 169 } on IOException catch (_) { |
| 170 return false; |
| 171 } |
| 172 |
| 173 if (lockfile is! Map) return false; |
| 174 var packages = lockfile["packages"]; |
| 175 if (packages is! Map) return false; |
| 176 var package = packages["test"]; |
| 177 if (package is! Map) return false; |
| 178 |
| 179 var source = package["source"]; |
| 180 if (source is! String) return false; |
| 181 |
| 182 switch (source) { |
| 183 case "hosted": |
| 184 var version = package["version"]; |
| 185 if (version is! String) return false; |
| 186 |
| 187 print(version); |
| 188 return true; |
| 189 |
| 190 case "git": |
| 191 var version = package["version"]; |
| 192 if (version is! String) return false; |
| 193 var description = package["description"]; |
| 194 if (description is! Map) return false; |
| 195 var ref = description["resolved-ref"]; |
| 196 if (ref is! String) return false; |
| 197 |
| 198 print("$version (${ref.substring(0, 7)})"); |
| 199 return true; |
| 200 |
| 201 case "path": |
| 202 var version = package["version"]; |
| 203 if (version is! String) return false; |
| 204 var description = package["description"]; |
| 205 if (description is! Map) return false; |
| 206 var path = description["path"]; |
| 207 if (path is! String) return false; |
| 208 |
| 209 print("$version (from $path)"); |
| 210 return true; |
| 211 |
| 212 default: return false; |
| 213 } |
| 214 } |
OLD | NEW |