| // Copyright (c) 2016, 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.md file. | |
| library testing.run_tests; | |
| import 'dart:async' show Future; | |
| import 'dart:io' show Directory, File, FileSystemEntity; | |
| import 'dart:io' as io show exitCode; | |
| import 'dart:isolate' show Isolate; | |
| import 'error_handling.dart' show withErrorHandling; | |
| import 'test_root.dart' show TestRoot; | |
| import 'zone_helper.dart' show runGuarded; | |
| import 'log.dart' | |
| show | |
| enableVerboseOutput, | |
| isVerbose, | |
| logMessage, | |
| logSuiteComplete, | |
| logTestComplete; | |
| import 'run.dart' show SuiteRunner, runProgram; | |
| class CommandLine { | |
| final Set<String> options; | |
| final List<String> arguments; | |
| CommandLine(this.options, this.arguments); | |
| bool get verbose => options.contains("--verbose") || options.contains("-v"); | |
| Set<String> get skip => commaSeparated("--skip="); | |
| Set<String> commaSeparated(String prefix) { | |
| return new Set<String>.from(options.expand((String s) { | |
| if (!s.startsWith(prefix)) return const []; | |
| s = s.substring(prefix.length); | |
| return s.split(","); | |
| })); | |
| } | |
| Map<String, String> get environment { | |
| Map<String, String> result = <String, String>{}; | |
| for (String option in options) { | |
| if (option.startsWith("-D")) { | |
| int equalIndex = option.indexOf("="); | |
| if (equalIndex != -1) { | |
| String key = option.substring(2, equalIndex); | |
| String value = option.substring(equalIndex + 1); | |
| result[key] = value; | |
| } | |
| } | |
| } | |
| return result; | |
| } | |
| Set<String> get selectedSuites { | |
| return selectors.map((String selector) { | |
| int index = selector.indexOf("/"); | |
| return index == -1 ? selector : selector.substring(0, index); | |
| }).toSet(); | |
| } | |
| Iterable<String> get selectors => arguments; | |
| Future<Uri> get configuration async { | |
| const String configPrefix = "--config="; | |
| List<String> configurationPaths = options | |
| .where((String option) => option.startsWith(configPrefix)) | |
| .map((String option) => option.substring(configPrefix.length)) | |
| .toList(); | |
| if (configurationPaths.length > 1) { | |
| return fail("Only one --config option is supported"); | |
| } | |
| String configurationPath; | |
| if (configurationPaths.length == 1) { | |
| configurationPath = configurationPaths.single; | |
| } else { | |
| configurationPath = "testing.json"; | |
| if (!await new File(configurationPath).exists()) { | |
| Directory test = new Directory("test"); | |
| if (await test.exists()) { | |
| List<FileSystemEntity> candidates = await test | |
| .list(recursive: true, followLinks: false) | |
| .where((FileSystemEntity entity) { | |
| return entity is File && entity.uri.path.endsWith("/testing.json"); | |
| }).toList(); | |
| switch (candidates.length) { | |
| case 0: | |
| return fail("Couldn't locate: '$configurationPath'."); | |
| case 1: | |
| configurationPath = candidates.single.path; | |
| break; | |
| default: | |
| return fail( | |
| "Usage: run_tests.dart [$configPrefix=configuration_file]\n" | |
| "Where configuration_file is one of:\n " | |
| "${candidates.map((file) => file.path).join('\n ')}"); | |
| } | |
| } | |
| } | |
| } | |
| logMessage("Reading configuration file '$configurationPath'."); | |
| Uri configuration = | |
| await Isolate.resolvePackageUri(Uri.base.resolve(configurationPath)); | |
| if (configuration == null || | |
| !await new File.fromUri(configuration).exists()) { | |
| return fail("Couldn't locate: '$configurationPath'."); | |
| } | |
| return configuration; | |
| } | |
| static CommandLine parse(List<String> arguments) { | |
| int index = arguments.indexOf("--"); | |
| Set<String> options; | |
| if (index != -1) { | |
| options = new Set<String>.from(arguments.getRange(0, index)); | |
| arguments = arguments.sublist(index + 1); | |
| } else { | |
| options = arguments.where((argument) => argument.startsWith("-")).toSet(); | |
| arguments = | |
| arguments.where((argument) => !argument.startsWith("-")).toList(); | |
| } | |
| return new CommandLine(options, arguments); | |
| } | |
| } | |
| fail(String message) { | |
| print(message); | |
| io.exitCode = 1; | |
| return null; | |
| } | |
| main(List<String> arguments) => withErrorHandling(() async { | |
| CommandLine cl = CommandLine.parse(arguments); | |
| if (cl.verbose) { | |
| enableVerboseOutput(); | |
| } | |
| Map<String, String> environment = cl.environment; | |
| Uri configuration = await cl.configuration; | |
| if (configuration == null) return; | |
| if (!isVerbose) { | |
| print("Use --verbose to display more details."); | |
| } | |
| TestRoot root = await TestRoot.fromUri(configuration); | |
| SuiteRunner runner = new SuiteRunner( | |
| root.suites, environment, cl.selectors, cl.selectedSuites, cl.skip); | |
| String program = await runner.generateDartProgram(); | |
| bool hasAnalyzerSuites = await runner.analyze(root.packages); | |
| Stopwatch sw = new Stopwatch()..start(); | |
| if (program == null) { | |
| if (!hasAnalyzerSuites) { | |
| fail("No tests configured."); | |
| } | |
| } else { | |
| await runProgram(program, root.packages); | |
| } | |
| print("Running tests took: ${sw.elapsed}."); | |
| }); | |
| Future<void> runTests(Map<String, Function> tests) => | |
| withErrorHandling<void>(() async { | |
| int completed = 0; | |
| for (String name in tests.keys) { | |
| StringBuffer sb = new StringBuffer(); | |
| try { | |
| await runGuarded(() { | |
| print("Running test $name"); | |
| return tests[name](); | |
| }, printLineOnStdout: sb.writeln); | |
| logMessage(sb); | |
| } catch (e) { | |
| print(sb); | |
| rethrow; | |
| } | |
| logTestComplete(++completed, 0, tests.length, null, null); | |
| } | |
| logSuiteComplete(); | |
| }); |