blob: b962194cfd22cd370fe5d715fbfd7e0f2f1205ca [file] [log] [blame]
// Copyright 2020 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:io';
import 'package:args/args.dart';
import 'package:fxtest/fxtest.dart';
import 'package:io/ansi.dart';
import 'package:meta/meta.dart';
/// Translator for command line arguments into [FuchsiaTestCommand] primitives.
class FuchsiaTestCommandCli {
/// Raw string arguments received from the command line.
final List<String> rawArgs;
/// Arguments hydrated into their respective data type representations
/// ([bool], [String], [int], etc).
final ArgResults parsedArgs;
/// Raw string arguments to be forwarded down to each executed test.
///
/// These tokens have no impact whatsoever on how `fx test` finds, filters,
/// and invokes tests. They are exclusively used by the underlying tests.
final List<String> passThroughTokens;
/// Callable that prints help/usage information for when the user passes
/// invalid arguments or "--help".
final Function(ArgParser) usage;
/// The underlying class which does all the work.
FuchsiaTestCommand _cmd;
FuchsiaTestCommandCli(this.rawArgs, {@required this.usage})
: passThroughTokens = FuchsiaTestCommandCli.extractPassThroughTokens(
rawArgs,
),
parsedArgs = FuchsiaTestCommandCli.parseArgs(rawArgs, usage);
/// Splits a list of command line arguments into the half intended for
/// local use and the half intended to be passed through to sub-commands.
static List<List<String>> splitArgs(List<String> rawArgs) {
var dashDashIndex = rawArgs.indexOf('--');
if (dashDashIndex == -1) {
dashDashIndex = rawArgs.length;
}
return [
rawArgs.take(dashDashIndex).toList(),
rawArgs.skip(dashDashIndex + 1).toList(),
];
}
static List<String> extractPassThroughTokens(List<String> rawArgs) {
return FuchsiaTestCommandCli.splitArgs(rawArgs)[1];
}
static ArgResults parseArgs(List<String> rawArgs, Function(ArgParser) usage) {
var localArgs = FuchsiaTestCommandCli.splitArgs(rawArgs)[0];
try {
return fxTestArgParser.parse(localArgs);
} on Exception catch (ex) {
stderr.writeln('Invalid syntax: $ex');
usage(fxTestArgParser);
exitCode = 64; // Improper usage
return null;
}
}
Future<bool> preRunChecks() async {
if (parsedArgs['help']) {
usage(fxTestArgParser);
return false;
}
if (parsedArgs['printtests']) {
ProcessResult result = await Process.run('cat', ['tests.json'],
workingDirectory: FuchsiaLocator.shared.buildDir);
stdout.write(result.stdout);
return false;
}
return true;
}
Future<void> run() async {
bool shouldRun = await preRunChecks();
if (!shouldRun) return;
var testNamesCollector = TestNamesCollector([
parsedArgs['testNames'],
parsedArgs.rest,
]);
var testsConfig = TestsConfig.fromArgResults(
results: parsedArgs,
passThroughTokens: passThroughTokens,
testNames: testNamesCollector.collect(),
);
var formatter = _getFormatter(testsConfig);
_cmd = FuchsiaTestCommand(
analyticsReporter: testsConfig.flags.dryRun
? AnalyticsReporter.noop()
: AnalyticsReporter(
fuchsiaLocator: FuchsiaLocator.shared,
),
fuchsiaLocator: FuchsiaLocator.shared,
outputFormatter: formatter,
testsConfig: testsConfig,
);
if (testsConfig.flags.shouldRebuild) {
formatter.update(TestInfo(wrapWith('> fx build', [green, styleBold])));
await rebuildFuchsia();
}
exitCode = await _cmd.runTestSuite(manifestReader: TestsManifestReader());
}
OutputFormatter _getFormatter(TestsConfig testsConfig) {
if (testsConfig.flags.infoOnly) {
return InfoFormatter();
}
var slowTestThreshold = testsConfig.flags.warnSlowerThan > 0
? Duration(seconds: testsConfig.flags.warnSlowerThan)
: null;
return testsConfig.flags.isVerbose
? VerboseOutputFormatter(
slowTestThreshold: slowTestThreshold,
shouldColorizeOutput: testsConfig.flags.simpleOutput,
)
: CondensedOutputFormatter(
slowTestThreshold: slowTestThreshold,
shouldColorizeOutput: testsConfig.flags.simpleOutput,
);
}
Future<void> terminateEarly() async {
_cmd?.emitEvent(AllTestsCompleted());
}
Future<void> cleanUp() async {
await _cmd?.cleanUp();
}
}