blob: 84f91e0c5bc4f4304b3182b36b396bda3109a96c [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:io';
import 'package:args/args.dart';
import 'package:fxtest/fxtest.dart';
import 'package:io/ansi.dart';
void usage(ArgParser parser) {
stdout
..writeln(wrapWith(
'Warning! This is an experimental new test command.',
[magenta],
))
..writeln()
..writeln('Usage: fx test [testName ...]')
..writeln()
..writeln(
'The value(s) supplied for `testName` can be fully-formed Fuchsia '
'Package URLs, Fuchsia package names, or Fuchsia-tree directories. '
'Partial tree paths will execute all descendent tests.',
)
..writeln()
..writeln('Options:')
..writeln(parser.usage);
}
/// CLI-flavored wrapper for [FuchsiaTestCommand]
Future<void> main(List<String> args) async {
var fuchsiaLocator = FuchsiaLocator();
final parser = ArgParser()
..addMultiOption('testNames', abbr: 't')
..addFlag('help', abbr: 'h', defaultsTo: false, negatable: false)
..addFlag('host',
defaultsTo: false,
negatable: false,
help: 'If true, only runs host tests. The opposite of `--device`')
..addFlag('device',
abbr: 'd',
defaultsTo: false,
negatable: false,
help: 'If true, only runs device tests. The opposite of `--host`')
..addFlag('printtests',
defaultsTo: false,
negatable: false,
help: 'If true, prints the contents of '
'`${fuchsiaLocator.userFriendlyBuildDir}/tests.json`')
..addFlag('random',
abbr: 'r',
defaultsTo: false,
negatable: false,
help: 'If true, randomizes test execution order')
..addFlag('dry',
defaultsTo: false,
negatable: false,
help: 'If true, does not invoke any tests')
..addFlag('fail',
abbr: 'f',
defaultsTo: false,
negatable: false,
help: 'If true, halts test suite execution on the first failed test')
..addOption('limit',
defaultsTo: null,
help: 'If passed, ends test suite execution after N tests')
..addOption('warnslow',
defaultsTo: null,
help: 'If passed, prints a debug message for each test that takes '
'longer than N seconds to execute')
..addFlag('skipped',
abbr: 's',
defaultsTo: false,
negatable: false,
help: 'If true, prints a debug statement about each skipped test')
..addFlag('simple',
defaultsTo: false,
negatable: false,
help: 'If true, removes any color or decoration from output')
..addFlag('output',
abbr: 'o',
defaultsTo: false,
negatable: false,
help: 'If true, also displays the output from passing tests')
..addFlag('silenceunsupported',
abbr: 'u',
defaultsTo: false,
negatable: false,
help: 'If true, will reduce unsupported tests to a warning and '
'continue executing.\nThis is dangerous outside of the local '
'development cycle, as "unsupported"\ntests are likely a problem '
'with this command, not the tests.')
..addFlag('verbose', abbr: 'v', defaultsTo: false, negatable: false);
List<String> passThroughTokens = [];
if (args.contains('--')) {
// Starting at the <position of '--' + 1> to avoid capturing '--' itself
passThroughTokens = args.sublist(args.indexOf('--') + 1);
// ignore: parameter_assignments
args = args.sublist(0, args.indexOf('--'));
}
ArgResults argResults;
try {
argResults = parser.parse(args);
} on Exception catch (ex) {
stderr.writeln('Invalid syntax: $ex');
usage(parser);
exitCode = 64; // Improper usage
return;
}
if (argResults['help']) {
usage(parser);
return;
}
if (argResults['printtests']) {
ProcessResult result = await Process.run(
'cat',
['tests.json'],
workingDirectory: fuchsiaLocator.buildDir,
);
stdout.write(result.stdout);
return;
}
var testNamesCollector = TestNamesCollector([
argResults['testNames'],
argResults.rest,
]);
var testFlags = TestFlags(
allOutput: argResults['output'],
dryRun: argResults['dry'],
isVerbose: argResults['verbose'] || argResults['output'],
limit: int.parse(argResults['limit'] ?? '0'),
passThroughTokens: passThroughTokens,
simpleOutput: !argResults['simple'],
shouldFailFast: argResults['fail'],
shouldOnlyRunDeviceTests: argResults['device'],
shouldOnlyRunHostTests: argResults['host'],
shouldPrintSkipped: argResults['skipped'],
shouldRandomizeTestOrder: argResults['random'],
shouldSilenceUnsupported: argResults['silenceunsupported'],
testNames: testNamesCollector.collect(),
warnSlowerThan: int.parse(argResults['warnslow'] ?? '0'),
);
var slowTestThreshold = testFlags.warnSlowerThan > 0
? Duration(seconds: testFlags.warnSlowerThan)
: null;
var formatter = testFlags.isVerbose
? VerboseOutputFormatter(
slowTestThreshold: slowTestThreshold,
shouldColorizeOutput: testFlags.simpleOutput,
shouldShowPassedTestsOutput: testFlags.allOutput,
)
: CondensedOutputFormatter(
slowTestThreshold: slowTestThreshold,
shouldColorizeOutput: testFlags.simpleOutput,
);
var cmd = FuchsiaTestCommand(
fuchsiaLocator: fuchsiaLocator,
outputFormatter: formatter,
testFlags: testFlags,
);
try {
exitCode = await cmd.runTestSuite();
} on Exception catch (err) {
stdout.write(wrapWith(err.toString(), [red]));
// ignore: cascade_invocations
stdout.writeln('');
exitCode = 2;
} finally {
// Close all streams
cmd.dispose();
}
}