| // 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(); |
| }); |