blob: 4c01c051227f0d461eab186d41d37811acf9296f [file] [log] [blame]
// Copyright (c) 2019, 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.
/// A runner that executes a pipeline on a folder containing modular tests.
import 'dart:io';
import 'package:args/args.dart';
import 'package:modular_test/src/io_pipeline.dart';
import 'package:modular_test/src/loader.dart';
import 'package:modular_test/src/suite.dart';
import 'generic_runner.dart' as generic;
Uri relativize(Uri uri, Uri base) {
return Uri.parse(uri.path.substring(base.path.length));
Future<void> runSuite(Uri suiteFolder, String suiteName, Options options,
IOPipeline pipeline) async {
var dir = Directory.fromUri(suiteFolder);
var entries = (await dir.list(recursive: false).toList())
.map((e) => _PipelineTest(e.uri, suiteFolder, options, pipeline))
await generic.runSuite(
suiteName: suiteName,
configurationName: options.configurationName,
filter: options.filter,
logDir: options.outputDirectory,
shard: options.shard,
shards: options.shards,
verbose: options.verbose,
reproTemplate: '%executable %script --verbose --filter %name'));
await pipeline.cleanup();
class _PipelineTest implements generic.Test {
final String name;
final Uri uri;
final Options options;
final IOPipeline pipeline;
_PipelineTest(this.uri, Uri suiteFolder, this.options, this.pipeline)
// Use the name of the folder as the test name by trimming out the prefix
// from the suite and the trailing `/`.
: name = uri.path.substring(suiteFolder.path.length, uri.path.length - 1);
Future<void> run() async {
ModularTest test = await loadTest(uri);
if (options.verbose) print(test.debugString());
class Options {
bool showSkipped = false;
bool verbose = false;
String? filter;
int shards = 1;
int shard = 1;
String? configurationName;
Uri? outputDirectory;
bool useSdk = false;
static Options parse(List<String> args) {
var parser = ArgParser()
abbr: 'v',
defaultsTo: false,
help: 'print detailed information about the test and modular steps')
defaultsTo: false,
help: 'print the name of the tests skipped by the filtering option')
defaultsTo: false, help: 'whether to use snapshots from a built sdk')
help: 'only run tests containing this filter as a substring')
help: 'total number of shards a suite is going to be split into.',
defaultsTo: '1')
help: 'which shard this script is executing. This should be between 0'
' and `shards - 1`.')
help: 'location where to emit the jsonl result and log files')
abbr: 'n',
help: 'configuration name to use for emitting jsonl result files.');
ArgResults argResults = parser.parse(args);
int shards = int.tryParse(argResults['shards']) ?? 1;
int shard = 1;
if (shards > 1) {
shard = int.tryParse(argResults['shard']) ?? 1;
if (shard <= 0 || shard >= shards) {
print('Error: shard should be between 0 and ${shards - 1},'
' but got $shard');
Uri? toUri(s) => s == null ? null : Uri.base.resolveUri(Uri.file(s));
return Options()
..showSkipped = argResults['show-skipped']
..verbose = argResults['verbose']
..useSdk = argResults['use-sdk']
..filter = argResults['filter']
..shards = shards
..shard = shard
..configurationName = argResults['named-configuration']
..outputDirectory = toUri(argResults['output-directory']);