[testing] Migrate pkg/testing to null safety
Change-Id: I64caff0a9163305ff122965105e7484c05b9cafb Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/207138 Commit-Queue: Johnni Winther <johnniwinther@google.com> Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
45ae00676a
commit
0073b55575
@@ -18,21 +18,21 @@ import 'log.dart' show isVerbose, splitLines;
|
||||
import 'suite.dart' show Suite;
|
||||
|
||||
class Analyze extends Suite {
|
||||
final Uri analysisOptions;
|
||||
final Uri? analysisOptions;
|
||||
|
||||
final List<Uri> uris;
|
||||
|
||||
final List<RegExp> exclude;
|
||||
|
||||
final List<String> gitGrepPathspecs;
|
||||
final List<String>? gitGrepPathspecs;
|
||||
|
||||
final List<String> gitGrepPatterns;
|
||||
final List<String>? gitGrepPatterns;
|
||||
|
||||
Analyze(this.analysisOptions, this.uris, this.exclude, this.gitGrepPathspecs,
|
||||
this.gitGrepPatterns)
|
||||
: super("analyze", "analyze", null);
|
||||
|
||||
Future<Null> run(Uri packages, List<Uri> extraUris) {
|
||||
Future<Null> run(Uri packages, List<Uri>? extraUris) {
|
||||
List<Uri> allUris = new List<Uri>.from(uris);
|
||||
if (extraUris != null) {
|
||||
allUris.addAll(extraUris);
|
||||
@@ -43,8 +43,8 @@ class Analyze extends Suite {
|
||||
|
||||
static Future<Analyze> fromJsonMap(
|
||||
Uri base, Map json, List<Suite> suites) async {
|
||||
String optionsPath = json["options"];
|
||||
Uri optionsUri = optionsPath == null ? null : base.resolve(optionsPath);
|
||||
String? optionsPath = json["options"];
|
||||
Uri? optionsUri = optionsPath == null ? null : base.resolve(optionsPath);
|
||||
|
||||
List<Uri> uris = json["uris"].map<Uri>((relative) {
|
||||
String r = relative;
|
||||
@@ -54,9 +54,9 @@ class Analyze extends Suite {
|
||||
List<RegExp> exclude =
|
||||
json["exclude"].map<RegExp>((p) => new RegExp(p)).toList();
|
||||
|
||||
Map gitGrep = json["git grep"];
|
||||
List<String> gitGrepPathspecs;
|
||||
List<String> gitGrepPatterns;
|
||||
Map? gitGrep = json["git grep"];
|
||||
List<String>? gitGrepPathspecs;
|
||||
List<String>? gitGrepPatterns;
|
||||
if (gitGrep != null) {
|
||||
gitGrepPathspecs = gitGrep["pathspecs"] == null
|
||||
? const <String>["."]
|
||||
@@ -73,13 +73,13 @@ class Analyze extends Suite {
|
||||
}
|
||||
|
||||
class AnalyzerDiagnostic {
|
||||
final String kind;
|
||||
final String? kind;
|
||||
|
||||
final String detailedKind;
|
||||
final String? detailedKind;
|
||||
|
||||
final String code;
|
||||
final String? code;
|
||||
|
||||
final Uri uri;
|
||||
final Uri? uri;
|
||||
|
||||
final int line;
|
||||
|
||||
@@ -106,7 +106,7 @@ class AnalyzerDiagnostic {
|
||||
addPart() {
|
||||
parts.add(line
|
||||
.substring(start, index == -1 ? null : index)
|
||||
.replaceAllMapped(unescapePattern, (Match m) => m[1]));
|
||||
.replaceAllMapped(unescapePattern, (Match m) => m[1]!));
|
||||
}
|
||||
|
||||
while (index != -1) {
|
||||
@@ -136,8 +136,8 @@ class AnalyzerDiagnostic {
|
||||
String toString() {
|
||||
return kind == null
|
||||
? "Malformed output from dartanalyzer:\n$message"
|
||||
: "${uri.toFilePath()}:$line:$startColumn: "
|
||||
"${kind == 'INFO' ? 'warning: hint' : kind.toLowerCase()}:\n"
|
||||
: "${uri!.toFilePath()}:$line:$startColumn: "
|
||||
"${kind == 'INFO' ? 'warning: hint' : kind!.toLowerCase()}:\n"
|
||||
"[$code] $message";
|
||||
}
|
||||
}
|
||||
@@ -154,12 +154,12 @@ Stream<AnalyzerDiagnostic> parseAnalyzerOutput(
|
||||
|
||||
/// Run dartanalyzer on all tests in [uris].
|
||||
Future<Null> analyzeUris(
|
||||
Uri analysisOptions,
|
||||
Uri? analysisOptions,
|
||||
Uri packages,
|
||||
List<Uri> uris,
|
||||
List<RegExp> exclude,
|
||||
List<String> gitGrepPathspecs,
|
||||
List<String> gitGrepPatterns) async {
|
||||
List<String>? gitGrepPathspecs,
|
||||
List<String>? gitGrepPatterns) async {
|
||||
if (uris.isEmpty) return;
|
||||
String topLevel;
|
||||
try {
|
||||
@@ -205,7 +205,7 @@ Future<Null> analyzeUris(
|
||||
arguments.addAll(
|
||||
gitGrepPatterns.expand((String pattern) => <String>["-e", pattern]));
|
||||
arguments.add("--");
|
||||
arguments.addAll(gitGrepPathspecs);
|
||||
arguments.addAll(gitGrepPathspecs!);
|
||||
filesToAnalyze.addAll(splitLines(await git("grep", arguments))
|
||||
.map((String line) => line.trimRight()));
|
||||
}
|
||||
@@ -245,7 +245,7 @@ Future<Null> analyzeUris(
|
||||
processAnalyzerOutput(Stream<AnalyzerDiagnostic> diagnostics) async {
|
||||
await for (AnalyzerDiagnostic diagnostic in diagnostics) {
|
||||
if (diagnostic.uri != null) {
|
||||
String path = toFilePath(diagnostic.uri);
|
||||
String path = toFilePath(diagnostic.uri!);
|
||||
if (!filesToAnalyze.contains(path)) continue;
|
||||
}
|
||||
String message = "$diagnostic";
|
||||
@@ -283,7 +283,7 @@ String _findSdkPath() {
|
||||
}
|
||||
|
||||
Future<String> git(String command, Iterable<String> arguments,
|
||||
{String workingDirectory}) async {
|
||||
{String? workingDirectory}) async {
|
||||
ProcessResult result = await Process.run(
|
||||
Platform.isWindows ? "git.bat" : "git",
|
||||
<String>[command]..addAll(arguments),
|
||||
|
||||
@@ -115,7 +115,7 @@ abstract class ChainContext {
|
||||
.map((s) => s.substring(0, s.length - 3))
|
||||
.toList();
|
||||
TestExpectations expectations = await ReadTestExpectations(
|
||||
<String>[suite.statusFile.toFilePath()], {}, expectationSet);
|
||||
<String>[suite.statusFile!.toFilePath()], {}, expectationSet);
|
||||
Stream<TestDescription> stream = list(suite);
|
||||
if (suite.processMultitests) {
|
||||
stream = stream.transform(new MultitestTransformer());
|
||||
@@ -149,12 +149,12 @@ abstract class ChainContext {
|
||||
final Set<Expectation> expectedOutcomes = processExpectedOutcomes(
|
||||
expectations.expectations(description.shortName), description);
|
||||
final StringBuffer sb = new StringBuffer();
|
||||
final Step lastStep = steps.isNotEmpty ? steps.last : null;
|
||||
final Step? lastStep = steps.isNotEmpty ? steps.last : null;
|
||||
final Iterator<Step> iterator = steps.iterator;
|
||||
|
||||
Result result;
|
||||
Result? result;
|
||||
// Records the outcome of the last step that was run.
|
||||
Step lastStepRun;
|
||||
Step? lastStepRun;
|
||||
|
||||
/// Performs one step of [iterator].
|
||||
///
|
||||
@@ -194,30 +194,30 @@ abstract class ChainContext {
|
||||
future = new Future.value(null);
|
||||
}
|
||||
future = future.then((_currentResult) async {
|
||||
Result currentResult = _currentResult;
|
||||
Result? currentResult = _currentResult;
|
||||
if (currentResult != null) {
|
||||
logger.logStepComplete(completed, unexpectedResults.length,
|
||||
descriptions.length, suite, description, lastStepRun);
|
||||
descriptions.length, suite, description, lastStepRun!);
|
||||
result = currentResult;
|
||||
if (currentResult.outcome == Expectation.Pass) {
|
||||
// The input to the next step is the output of this step.
|
||||
return doStep(result.output);
|
||||
return doStep(result!.output);
|
||||
}
|
||||
}
|
||||
await cleanUp(description, result);
|
||||
await cleanUp(description, result!);
|
||||
result =
|
||||
processTestResult(description, result, lastStep == lastStepRun);
|
||||
if (!expectedOutcomes.contains(result.outcome) &&
|
||||
!expectedOutcomes.contains(result.outcome.canonical)) {
|
||||
result.addLog("$sb");
|
||||
unexpectedResults[description] = result;
|
||||
processTestResult(description, result!, lastStep == lastStepRun);
|
||||
if (!expectedOutcomes.contains(result!.outcome) &&
|
||||
!expectedOutcomes.contains(result!.outcome.canonical)) {
|
||||
result!.addLog("$sb");
|
||||
unexpectedResults[description] = result!;
|
||||
unexpectedOutcomes[description] = expectedOutcomes;
|
||||
logger.logUnexpectedResult(
|
||||
suite, description, result, expectedOutcomes);
|
||||
suite, description, result!, expectedOutcomes);
|
||||
exitCode = 1;
|
||||
} else {
|
||||
logger.logExpectedResult(
|
||||
suite, description, result, expectedOutcomes);
|
||||
suite, description, result!, expectedOutcomes);
|
||||
logger.logMessage(sb);
|
||||
}
|
||||
logger.logTestComplete(++completed, unexpectedResults.length,
|
||||
@@ -241,7 +241,7 @@ abstract class ChainContext {
|
||||
if (unexpectedResults.isNotEmpty) {
|
||||
unexpectedResults.forEach((TestDescription description, Result result) {
|
||||
logger.logUnexpectedResult(
|
||||
suite, description, result, unexpectedOutcomes[description]);
|
||||
suite, description, result, unexpectedOutcomes[description]!);
|
||||
});
|
||||
print("${unexpectedResults.length} failed:");
|
||||
unexpectedResults.forEach((TestDescription description, Result result) {
|
||||
@@ -278,7 +278,7 @@ abstract class ChainContext {
|
||||
TestDescription description, Result result, bool last) {
|
||||
if (description is FileBasedTestDescription &&
|
||||
description.multitestExpectations != null) {
|
||||
if (isError(description.multitestExpectations)) {
|
||||
if (isError(description.multitestExpectations!)) {
|
||||
result =
|
||||
toNegativeTestResult(result, description.multitestExpectations);
|
||||
}
|
||||
@@ -286,14 +286,14 @@ abstract class ChainContext {
|
||||
if (result.outcome == Expectation.Pass) {
|
||||
result.addLog("Negative test didn't report an error.\n");
|
||||
} else if (result.outcome == Expectation.Fail) {
|
||||
result.addLog("Negative test reported an error as expeceted.\n");
|
||||
result.addLog("Negative test reported an error as expected.\n");
|
||||
}
|
||||
result = toNegativeTestResult(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Result toNegativeTestResult(Result result, [Set<String> expectations]) {
|
||||
Result toNegativeTestResult(Result result, [Set<String>? expectations]) {
|
||||
Expectation outcome = result.outcome;
|
||||
if (outcome == Expectation.Pass) {
|
||||
if (expectations == null) {
|
||||
@@ -312,9 +312,9 @@ abstract class ChainContext {
|
||||
return result.copyWithOutcome(outcome);
|
||||
}
|
||||
|
||||
Future<void> cleanUp(TestDescription description, Result result) => null;
|
||||
Future<void> cleanUp(TestDescription description, Result result) async {}
|
||||
|
||||
Future<void> postRun() => null;
|
||||
Future<void> postRun() async {}
|
||||
}
|
||||
|
||||
abstract class Step<I, O, C extends ChainContext> {
|
||||
@@ -355,25 +355,25 @@ abstract class Step<I, O, C extends ChainContext> {
|
||||
|
||||
Result<O> crash(error, StackTrace trace) => new Result<O>.crash(error, trace);
|
||||
|
||||
Result<O> fail(O output, [error, StackTrace trace]) {
|
||||
Result<O> fail(O output, [error, StackTrace? trace]) {
|
||||
return new Result<O>.fail(output, error, trace);
|
||||
}
|
||||
}
|
||||
|
||||
class Result<O> {
|
||||
final O output;
|
||||
final O? output;
|
||||
|
||||
final Expectation outcome;
|
||||
|
||||
final error;
|
||||
|
||||
final StackTrace trace;
|
||||
final StackTrace? trace;
|
||||
|
||||
final List<String> logs = <String>[];
|
||||
|
||||
/// If set, running the test with '-D$autoFixCommand' will automatically
|
||||
/// update the test to match new expectations.
|
||||
final String autoFixCommand;
|
||||
final String? autoFixCommand;
|
||||
|
||||
/// If set, the test can be fixed by running
|
||||
///
|
||||
@@ -391,7 +391,7 @@ class Result<O> {
|
||||
Result.crash(error, StackTrace trace)
|
||||
: this(null, Expectation.Crash, error, trace: trace);
|
||||
|
||||
Result.fail(O output, [error, StackTrace trace])
|
||||
Result.fail(O output, [error, StackTrace? trace])
|
||||
: this(output, Expectation.Fail, error, trace: trace);
|
||||
|
||||
bool get isPass => outcome == Expectation.Pass;
|
||||
@@ -420,7 +420,8 @@ class Result<O> {
|
||||
Future<Null> runChain(CreateContext f, Map<String, String> environment,
|
||||
Set<String> selectors, String jsonText) {
|
||||
return withErrorHandling(() async {
|
||||
Chain suite = new Suite.fromJsonMap(Uri.base, json.decode(jsonText));
|
||||
Chain suite =
|
||||
new Suite.fromJsonMap(Uri.base, json.decode(jsonText)) as Chain;
|
||||
print("Running ${suite.name}");
|
||||
ChainContext context = await f(suite, environment);
|
||||
return context.run(suite, selectors);
|
||||
|
||||
@@ -20,10 +20,10 @@ List<String> get dartArguments =>
|
||||
<String>["-c", "--packages=${packageConfig.toFilePath()}"];
|
||||
|
||||
Stream<FileBasedTestDescription> listTests(List<Uri> testRoots,
|
||||
{Pattern pattern}) {
|
||||
{Pattern? pattern}) {
|
||||
StreamController<FileBasedTestDescription> controller =
|
||||
new StreamController<FileBasedTestDescription>();
|
||||
Map<Uri, StreamSubscription> subscriptions = <Uri, StreamSubscription>{};
|
||||
Map<Uri, StreamSubscription?> subscriptions = <Uri, StreamSubscription>{};
|
||||
for (Uri testRootUri in testRoots) {
|
||||
subscriptions[testRootUri] = null;
|
||||
Directory testRoot = new Directory.fromUri(testRootUri);
|
||||
@@ -32,8 +32,9 @@ Stream<FileBasedTestDescription> listTests(List<Uri> testRoots,
|
||||
Stream<FileSystemEntity> stream =
|
||||
testRoot.list(recursive: true, followLinks: false);
|
||||
var subscription = stream.listen((FileSystemEntity entity) {
|
||||
FileBasedTestDescription description = FileBasedTestDescription
|
||||
.from(testRootUri, entity, pattern: pattern);
|
||||
FileBasedTestDescription? description = FileBasedTestDescription.from(
|
||||
testRootUri, entity,
|
||||
pattern: pattern);
|
||||
if (description != null) {
|
||||
controller.add(description);
|
||||
}
|
||||
@@ -59,7 +60,7 @@ Stream<FileBasedTestDescription> listTests(List<Uri> testRoots,
|
||||
}
|
||||
|
||||
Uri computePackageConfig() {
|
||||
String path = Platform.packageConfig;
|
||||
String? path = Platform.packageConfig;
|
||||
if (path != null) return Uri.base.resolve(path);
|
||||
return Uri.base.resolve(".packages");
|
||||
}
|
||||
@@ -72,7 +73,7 @@ const _dartSdk = (String.fromEnvironment("DART_SDK", defaultValue: "1") ==
|
||||
: null;
|
||||
|
||||
Uri computeDartSdk() {
|
||||
String dartSdkPath = Platform.environment["DART_SDK"] ?? _dartSdk;
|
||||
String? dartSdkPath = Platform.environment["DART_SDK"] ?? _dartSdk;
|
||||
if (dartSdkPath != null) {
|
||||
return Uri.base.resolveUri(new Uri.file(dartSdkPath));
|
||||
} else {
|
||||
@@ -83,7 +84,7 @@ Uri computeDartSdk() {
|
||||
}
|
||||
|
||||
Future<Process> startDart(Uri program,
|
||||
[List<String> arguments, List<String> vmArguments]) {
|
||||
[List<String>? arguments, List<String>? vmArguments]) {
|
||||
List<String> allArguments = <String>[];
|
||||
allArguments.addAll(vmArguments ?? dartArguments);
|
||||
allArguments.add(program.toFilePath());
|
||||
|
||||
@@ -12,13 +12,14 @@ import 'dart:isolate' show ReceivePort;
|
||||
|
||||
import 'log.dart';
|
||||
|
||||
Future<T> withErrorHandling<T>(Future<T> f(), {Logger logger}) async {
|
||||
Future<T?> withErrorHandling<T>(Future<T> f(), {Logger? logger}) async {
|
||||
final ReceivePort port = new ReceivePort();
|
||||
try {
|
||||
return await f();
|
||||
} catch (e, trace) {
|
||||
exitCode = 1;
|
||||
stderr.writeln(e);
|
||||
// ignore: unnecessary_null_comparison
|
||||
if (trace != null) {
|
||||
stderr.writeln(trace);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ class Expectation {
|
||||
|
||||
String toString() => name;
|
||||
|
||||
static Expectation fromGroup(ExpectationGroup group) {
|
||||
static Expectation? fromGroup(ExpectationGroup group) {
|
||||
switch (group) {
|
||||
case ExpectationGroup.Crash:
|
||||
return Expectation.Crash;
|
||||
@@ -57,7 +57,6 @@ class Expectation {
|
||||
case ExpectationGroup.Timeout:
|
||||
return Expectation.Timeout;
|
||||
}
|
||||
throw "Unhandled group: '$group'.";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,8 +88,8 @@ class ExpectationSet {
|
||||
Map<String, Expectation> internalMap =
|
||||
new Map<String, Expectation>.from(Default.internalMap);
|
||||
for (Map map in data) {
|
||||
String name;
|
||||
String group;
|
||||
String? name;
|
||||
String? group;
|
||||
map.forEach((_key, _value) {
|
||||
String key = _key;
|
||||
String value = _value;
|
||||
@@ -113,12 +112,12 @@ class ExpectationSet {
|
||||
if (group == null) {
|
||||
throw "No group provided in '$map'";
|
||||
}
|
||||
Expectation expectation = new Expectation(name, groupFromString(group));
|
||||
name = name.toLowerCase();
|
||||
Expectation expectation = new Expectation(name!, groupFromString(group!));
|
||||
name = name!.toLowerCase();
|
||||
if (internalMap.containsKey(name)) {
|
||||
throw "Duplicated expectation name: '$name'.";
|
||||
}
|
||||
internalMap[name] = expectation;
|
||||
internalMap[name!] = expectation;
|
||||
}
|
||||
return new ExpectationSet(internalMap);
|
||||
}
|
||||
|
||||
@@ -78,19 +78,19 @@ abstract class Logger {
|
||||
class StdoutLogger implements Logger {
|
||||
const StdoutLogger();
|
||||
|
||||
void logTestStart(int completed, int failed, int total, Suite suite,
|
||||
TestDescription description) {}
|
||||
void logTestStart(int completed, int failed, int total, Suite? suite,
|
||||
TestDescription? description) {}
|
||||
|
||||
void logTestComplete(int completed, int failed, int total, Suite suite,
|
||||
TestDescription description) {
|
||||
void logTestComplete(int completed, int failed, int total, Suite? suite,
|
||||
TestDescription? description) {
|
||||
String message = formatProgress(completed, failed, total);
|
||||
if (suite != null) {
|
||||
message += ": ${formatTestDescription(suite, description)}";
|
||||
message += ": ${formatTestDescription(suite, description!)}";
|
||||
}
|
||||
logProgress(message);
|
||||
}
|
||||
|
||||
void logStepStart(int completed, int failed, int total, Suite suite,
|
||||
void logStepStart(int completed, int failed, int total, Suite? suite,
|
||||
TestDescription description, Step step) {
|
||||
String message = formatProgress(completed, failed, total);
|
||||
if (suite != null) {
|
||||
@@ -102,7 +102,7 @@ class StdoutLogger implements Logger {
|
||||
logProgress(message);
|
||||
}
|
||||
|
||||
void logStepComplete(int completed, int failed, int total, Suite suite,
|
||||
void logStepComplete(int completed, int failed, int total, Suite? suite,
|
||||
TestDescription description, Step step) {
|
||||
if (!step.isAsync) return;
|
||||
String message = formatProgress(completed, failed, total);
|
||||
@@ -152,7 +152,7 @@ class StdoutLogger implements Logger {
|
||||
void logUnexpectedResult(Suite suite, TestDescription description,
|
||||
Result result, Set<Expectation> expectedOutcomes) {
|
||||
print("${eraseLine}UNEXPECTED: ${suite.name}/${description.shortName}");
|
||||
Uri statusFile = suite.statusFile;
|
||||
Uri? statusFile = suite.statusFile;
|
||||
if (statusFile != null) {
|
||||
String path = statusFile.toFilePath();
|
||||
if (result.outcome == Expectation.Pass) {
|
||||
@@ -186,6 +186,7 @@ class StdoutLogger implements Logger {
|
||||
|
||||
void logUncaughtError(error, StackTrace stackTrace) {
|
||||
logMessage(error);
|
||||
// ignore: unnecessary_null_comparison
|
||||
if (stackTrace != null) {
|
||||
logMessage(stackTrace);
|
||||
}
|
||||
|
||||
@@ -51,8 +51,8 @@ class MultitestTransformer
|
||||
|
||||
nextTest:
|
||||
await for (TestDescription test in stream) {
|
||||
FileBasedTestDescription multitest;
|
||||
String contents;
|
||||
FileBasedTestDescription? multitest;
|
||||
String? contents;
|
||||
if (test is FileBasedTestDescription) {
|
||||
contents = await test.file.readAsString();
|
||||
if (contents.contains(multitestMarker)) {
|
||||
@@ -73,11 +73,11 @@ class MultitestTransformer
|
||||
"none": new Set<String>(),
|
||||
};
|
||||
int lineNumber = 0;
|
||||
for (String line in splitLines(contents)) {
|
||||
for (String line in splitLines(contents!)) {
|
||||
lineNumber++;
|
||||
int index = line.indexOf(multitestMarker);
|
||||
String subtestName;
|
||||
List<String> subtestOutcomesList;
|
||||
String? subtestName;
|
||||
List<String>? subtestOutcomesList;
|
||||
if (index != -1) {
|
||||
String annotationText =
|
||||
line.substring(index + _multitestMarkerLength).trim();
|
||||
@@ -102,7 +102,7 @@ class MultitestTransformer
|
||||
lines.add(line);
|
||||
Set<String> subtestOutcomes =
|
||||
outcomes.putIfAbsent(subtestName, () => new Set<String>());
|
||||
if (subtestOutcomesList.length != 1 ||
|
||||
if (subtestOutcomesList!.length != 1 ||
|
||||
subtestOutcomesList.single != "continued") {
|
||||
for (String outcome in subtestOutcomesList) {
|
||||
if (validOutcomes.contains(outcome)) {
|
||||
@@ -125,8 +125,9 @@ class MultitestTransformer
|
||||
Directory generated =
|
||||
new Directory.fromUri(root.resolve(multitest.shortName));
|
||||
generated = await generated.create(recursive: true);
|
||||
for (String name in testsAsLines.keys) {
|
||||
List<String> lines = testsAsLines[name];
|
||||
for (MapEntry<String, List<String>> entry in testsAsLines.entries) {
|
||||
String name = entry.key;
|
||||
List<String> lines = entry.value;
|
||||
Uri uri = generated.uri.resolve("${name}_generated.dart");
|
||||
FileBasedTestDescription subtest =
|
||||
new FileBasedTestDescription(root, new File.fromUri(uri));
|
||||
|
||||
@@ -34,10 +34,10 @@ import 'zone_helper.dart' show acknowledgeControlMessages;
|
||||
|
||||
import 'run_tests.dart' show CommandLine;
|
||||
|
||||
Future<TestRoot> computeTestRoot(String configurationPath, Uri base) {
|
||||
Future<TestRoot> computeTestRoot(String? configurationPath, Uri? base) {
|
||||
Uri configuration = configurationPath == null
|
||||
? Uri.base.resolve("testing.json")
|
||||
: base.resolve(configurationPath);
|
||||
: base!.resolve(configurationPath);
|
||||
return TestRoot.fromUri(configuration);
|
||||
}
|
||||
|
||||
@@ -50,8 +50,8 @@ Future<TestRoot> computeTestRoot(String configurationPath, Uri base) {
|
||||
/// `testing.json` isn't located in the current working directory and is a path
|
||||
/// relative to [me] which defaults to `Platform.script`.
|
||||
Future<Null> runMe(List<String> arguments, CreateContext f,
|
||||
{String configurationPath,
|
||||
Uri me,
|
||||
{String? configurationPath,
|
||||
Uri? me,
|
||||
int shards = 1,
|
||||
int shard = 0,
|
||||
Logger logger: const StdoutLogger()}) {
|
||||
@@ -98,7 +98,7 @@ Future<Null> runMe(List<String> arguments, CreateContext f,
|
||||
/// `testing.json` isn't located in the current working directory and is a path
|
||||
/// relative to `Uri.base`.
|
||||
Future<Null> run(List<String> arguments, List<String> suiteNames,
|
||||
[String configurationPath]) {
|
||||
[String? configurationPath]) {
|
||||
return withErrorHandling(() async {
|
||||
TestRoot root = await computeTestRoot(configurationPath, Uri.base);
|
||||
List<Suite> suites = root.suites
|
||||
@@ -106,7 +106,7 @@ Future<Null> run(List<String> arguments, List<String> suiteNames,
|
||||
.toList();
|
||||
SuiteRunner runner = new SuiteRunner(suites, <String, String>{},
|
||||
const <String>[], new Set<String>(), new Set<String>());
|
||||
String program = await runner.generateDartProgram();
|
||||
String? program = await runner.generateDartProgram();
|
||||
await runner.analyze(root.packages);
|
||||
if (program != null) {
|
||||
await runProgram(program, root.packages);
|
||||
@@ -125,7 +125,7 @@ Future<Null> runProgram(String program, Uri packages) async {
|
||||
errorsAreFatal: false,
|
||||
checked: true,
|
||||
packageConfig: packages);
|
||||
List error;
|
||||
List? error;
|
||||
var subscription = isolate.errors.listen((data) {
|
||||
error = data;
|
||||
exitPort.close();
|
||||
@@ -137,7 +137,7 @@ Future<Null> runProgram(String program, Uri packages) async {
|
||||
subscription.cancel();
|
||||
return error == null
|
||||
? null
|
||||
: new Future<Null>.error(error[0], new StackTrace.fromString(error[1]));
|
||||
: new Future<Null>.error(error![0], new StackTrace.fromString(error![1]));
|
||||
}
|
||||
|
||||
class SuiteRunner {
|
||||
@@ -162,7 +162,7 @@ class SuiteRunner {
|
||||
(selectedSuites.isEmpty || selectedSuites.contains(suite.name));
|
||||
}
|
||||
|
||||
Future<String> generateDartProgram() async {
|
||||
Future<String?> generateDartProgram() async {
|
||||
testUris.clear();
|
||||
StringBuffer imports = new StringBuffer();
|
||||
StringBuffer dart = new StringBuffer();
|
||||
@@ -238,10 +238,10 @@ Future<Null> main() async {
|
||||
}
|
||||
|
||||
Stream<FileBasedTestDescription> listDescriptions() async* {
|
||||
for (Dart suite in suites.where((Suite suite) => suite is Dart)) {
|
||||
for (Dart suite in suites.whereType<Dart>()) {
|
||||
await for (FileBasedTestDescription description
|
||||
in listTests(<Uri>[suite.uri], pattern: "")) {
|
||||
testUris.add(await Isolate.resolvePackageUri(description.uri));
|
||||
testUris.add((await Isolate.resolvePackageUri(description.uri))!);
|
||||
if (shouldRunSuite(suite)) {
|
||||
String path = description.file.uri.path;
|
||||
if (suite.exclude.any((RegExp r) => path.contains(r))) continue;
|
||||
@@ -254,19 +254,19 @@ Future<Null> main() async {
|
||||
}
|
||||
|
||||
Stream<Chain> listChainSuites() async* {
|
||||
for (Chain suite in suites.where((Suite suite) => suite is Chain)) {
|
||||
testUris.add(await Isolate.resolvePackageUri(suite.source));
|
||||
for (Chain suite in suites.whereType<Chain>()) {
|
||||
testUris.add((await Isolate.resolvePackageUri(suite.source))!);
|
||||
if (shouldRunSuite(suite)) {
|
||||
yield suite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Iterable<Suite> listTestDartSuites() {
|
||||
return suites.where((Suite suite) => suite is TestDart);
|
||||
Iterable<TestDart> listTestDartSuites() {
|
||||
return suites.whereType<TestDart>();
|
||||
}
|
||||
|
||||
Iterable<Suite> listAnalyzerSuites() {
|
||||
return suites.where((Suite suite) => suite is Analyze);
|
||||
Iterable<Analyze> listAnalyzerSuites() {
|
||||
return suites.whereType<Analyze>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ class CommandLine {
|
||||
|
||||
Iterable<String> get selectors => arguments;
|
||||
|
||||
Future<Uri> get configuration async {
|
||||
Future<Uri?> get configuration async {
|
||||
const String configPrefix = "--config=";
|
||||
List<String> configurationPaths = options
|
||||
.where((String option) => option.startsWith(configPrefix))
|
||||
@@ -111,7 +111,7 @@ class CommandLine {
|
||||
}
|
||||
const StdoutLogger()
|
||||
.logMessage("Reading configuration file '$configurationPath'.");
|
||||
Uri configuration =
|
||||
Uri? configuration =
|
||||
await Isolate.resolvePackageUri(Uri.base.resolve(configurationPath));
|
||||
if (configuration == null ||
|
||||
!await new File.fromUri(configuration).exists()) {
|
||||
@@ -147,7 +147,7 @@ main(List<String> arguments) => withErrorHandling(() async {
|
||||
enableVerboseOutput();
|
||||
}
|
||||
Map<String, String> environment = cl.environment;
|
||||
Uri configuration = await cl.configuration;
|
||||
Uri? configuration = await cl.configuration;
|
||||
if (configuration == null) return;
|
||||
if (!isVerbose) {
|
||||
print("Use --verbose to display more details.");
|
||||
@@ -155,7 +155,7 @@ main(List<String> arguments) => withErrorHandling(() async {
|
||||
TestRoot root = await TestRoot.fromUri(configuration);
|
||||
SuiteRunner runner = new SuiteRunner(
|
||||
root.suites, environment, cl.selectors, cl.selectedSuites, cl.skip);
|
||||
String program = await runner.generateDartProgram();
|
||||
String? program = await runner.generateDartProgram();
|
||||
bool hasAnalyzerSuites = await runner.analyze(root.packages);
|
||||
Stopwatch sw = new Stopwatch()..start();
|
||||
if (program == null) {
|
||||
@@ -178,7 +178,7 @@ Future<void> runTests(Map<String, Function> tests) =>
|
||||
try {
|
||||
await runGuarded(() {
|
||||
print("Running test $name");
|
||||
return tests[name]();
|
||||
return tests[name]!();
|
||||
}, printLineOnStdout: sb.writeln);
|
||||
const StdoutLogger().logMessage(sb);
|
||||
} catch (e) {
|
||||
|
||||
@@ -41,13 +41,13 @@ class StdioProcess {
|
||||
}
|
||||
|
||||
static Future<StdioProcess> run(String executable, List<String> arguments,
|
||||
{String input,
|
||||
Duration timeout: const Duration(seconds: 60),
|
||||
{String? input,
|
||||
Duration? timeout: const Duration(seconds: 60),
|
||||
bool suppressOutput: true,
|
||||
bool runInShell: false}) async {
|
||||
Process process =
|
||||
await Process.start(executable, arguments, runInShell: runInShell);
|
||||
Timer timer;
|
||||
Timer? timer;
|
||||
StringBuffer sb = new StringBuffer();
|
||||
if (timeout != null) {
|
||||
timer = new Timer(timeout, () {
|
||||
@@ -75,8 +75,8 @@ class StdioProcess {
|
||||
stdoutStream = stdoutStream.transform(transformToStdio(io.stdout));
|
||||
stderrStream = stderrStream.transform(transformToStdio(io.stderr));
|
||||
}
|
||||
Future<List<String>> stdoutFuture = stdoutStream.toList();
|
||||
Future<List<String>> stderrFuture = stderrStream.toList();
|
||||
Future<List<String>> stdoutFuture = stdoutStream.toList() as Future<List<String>>;
|
||||
Future<List<String>> stderrFuture = stderrStream.toList() as Future<List<String>>;
|
||||
int exitCode = await process.exitCode;
|
||||
timer?.cancel();
|
||||
sb.writeAll(await stdoutFuture);
|
||||
|
||||
@@ -14,7 +14,7 @@ abstract class Suite {
|
||||
|
||||
final String kind;
|
||||
|
||||
final Uri statusFile;
|
||||
final Uri? statusFile;
|
||||
|
||||
Suite(this.name, this.kind, this.statusFile);
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ class Path {
|
||||
Path makeCanonical() {
|
||||
bool isAbs = isAbsolute;
|
||||
List segs = segments();
|
||||
String drive;
|
||||
String? drive;
|
||||
if (isAbs && !segs.isEmpty && segs[0].length == 2 && segs[0][1] == ':') {
|
||||
drive = segs[0];
|
||||
segs.removeRange(0, 1);
|
||||
@@ -267,7 +267,7 @@ class Path {
|
||||
}
|
||||
|
||||
List<String> segments() {
|
||||
List result = _path.split('/');
|
||||
List<String> result = _path.split('/');
|
||||
if (isAbsolute) result.removeRange(0, 1);
|
||||
if (hasTrailingSeparator) result.removeLast();
|
||||
return result;
|
||||
|
||||
@@ -64,7 +64,9 @@ class Tokenizer {
|
||||
if (!testRegexp.hasMatch(expression)) {
|
||||
throw new FormatException("Syntax error in '$expression'");
|
||||
}
|
||||
for (Match match in regexp.allMatches(expression)) tokens.add(match[0]);
|
||||
for (Match match in regexp.allMatches(expression)) {
|
||||
tokens.add(match[0]!);
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
@@ -179,8 +181,8 @@ class SetConstant implements SetExpression {
|
||||
// An iterator that allows peeking at the current token.
|
||||
class Scanner {
|
||||
List<String> tokens;
|
||||
Iterator tokenIterator;
|
||||
String current;
|
||||
late Iterator tokenIterator;
|
||||
String? current;
|
||||
|
||||
Scanner(this.tokens) {
|
||||
tokenIterator = tokens.iterator;
|
||||
@@ -241,11 +243,11 @@ class ExpressionParser {
|
||||
scanner.advance();
|
||||
return value;
|
||||
}
|
||||
if (!new RegExp(r"^\w+$").hasMatch(scanner.current)) {
|
||||
if (!new RegExp(r"^\w+$").hasMatch(scanner.current!)) {
|
||||
throw new FormatException(
|
||||
"Expected identifier in expression, got ${scanner.current}");
|
||||
}
|
||||
SetExpression value = new SetConstant(scanner.current);
|
||||
SetExpression value = new SetConstant(scanner.current!);
|
||||
scanner.advance();
|
||||
return value;
|
||||
}
|
||||
@@ -290,21 +292,21 @@ class ExpressionParser {
|
||||
"Expected \$ in expression, got ${scanner.current}");
|
||||
}
|
||||
scanner.advance();
|
||||
if (!new RegExp(r"^\w+$").hasMatch(scanner.current)) {
|
||||
if (!new RegExp(r"^\w+$").hasMatch(scanner.current!)) {
|
||||
throw new FormatException(
|
||||
"Expected identifier in expression, got ${scanner.current}");
|
||||
}
|
||||
TermVariable left = new TermVariable(scanner.current);
|
||||
TermVariable left = new TermVariable(scanner.current!);
|
||||
scanner.advance();
|
||||
if (scanner.current == Token.EQUALS ||
|
||||
scanner.current == Token.NOT_EQUALS) {
|
||||
bool negate = scanner.current == Token.NOT_EQUALS;
|
||||
scanner.advance();
|
||||
if (!new RegExp(r"^\w+$").hasMatch(scanner.current)) {
|
||||
if (!new RegExp(r"^\w+$").hasMatch(scanner.current!)) {
|
||||
throw new FormatException(
|
||||
"Expected value in expression, got ${scanner.current}");
|
||||
}
|
||||
TermConstant right = new TermConstant(scanner.current);
|
||||
TermConstant right = new TermConstant(scanner.current!);
|
||||
scanner.advance();
|
||||
return new Comparison(left, right, negate);
|
||||
} else {
|
||||
|
||||
@@ -29,7 +29,7 @@ class StatusFile {
|
||||
class Section {
|
||||
final StatusFile statusFile;
|
||||
|
||||
final BooleanExpression condition;
|
||||
final BooleanExpression? condition;
|
||||
final List<TestRule> testRules;
|
||||
final int lineNumber;
|
||||
|
||||
@@ -40,7 +40,7 @@ class Section {
|
||||
: testRules = <TestRule>[];
|
||||
|
||||
bool isEnabled(Map<String, String> environment) =>
|
||||
condition == null || condition.evaluate(environment);
|
||||
condition == null || condition!.evaluate(environment);
|
||||
|
||||
String toString() {
|
||||
return "Section: $condition";
|
||||
@@ -93,17 +93,17 @@ void ReadConfigurationInto(Path path, List<Section> sections, void onDone()) {
|
||||
|
||||
lines.listen((String line) {
|
||||
lineNumber++;
|
||||
Match match = SplitComment.firstMatch(line);
|
||||
line = (match == null) ? "" : match[1];
|
||||
Match? match = SplitComment.firstMatch(line);
|
||||
line = (match == null) ? "" : match[1]!;
|
||||
line = line.trim();
|
||||
if (line.isEmpty) return;
|
||||
|
||||
// Extract the comment to get the issue number if needed.
|
||||
String comment = (match == null || match[2] == null) ? "" : match[2];
|
||||
String comment = (match == null || match[2] == null) ? "" : match[2]!;
|
||||
|
||||
match = HeaderPattern.firstMatch(line);
|
||||
if (match != null) {
|
||||
String condition_string = match[1].trim();
|
||||
String condition_string = match[1]!.trim();
|
||||
List<String> tokens = new Tokenizer(condition_string).tokenize();
|
||||
ExpressionParser parser = new ExpressionParser(new Scanner(tokens));
|
||||
currentSection =
|
||||
@@ -114,21 +114,21 @@ void ReadConfigurationInto(Path path, List<Section> sections, void onDone()) {
|
||||
|
||||
match = RulePattern.firstMatch(line);
|
||||
if (match != null) {
|
||||
String name = match[1].trim();
|
||||
String name = match[1]!.trim();
|
||||
// TODO(whesse): Handle test names ending in a wildcard (*).
|
||||
String expression_string = match[2].trim();
|
||||
String expression_string = match[2]!.trim();
|
||||
List<String> tokens = new Tokenizer(expression_string).tokenize();
|
||||
SetExpression expression =
|
||||
new ExpressionParser(new Scanner(tokens)).parseSetExpression();
|
||||
|
||||
// Look for issue number in comment.
|
||||
String issueString = null;
|
||||
String? issueString = null;
|
||||
match = IssueNumberPattern.firstMatch(comment);
|
||||
if (match != null) {
|
||||
issueString = match[1];
|
||||
if (issueString == null) issueString = match[2];
|
||||
}
|
||||
int issue = issueString != null ? int.parse(issueString) : null;
|
||||
int? issue = issueString != null ? int.parse(issueString) : null;
|
||||
currentSection.testRules
|
||||
.add(new TestRule(name, expression, issue, lineNumber));
|
||||
return;
|
||||
@@ -141,7 +141,7 @@ void ReadConfigurationInto(Path path, List<Section> sections, void onDone()) {
|
||||
class TestRule {
|
||||
String name;
|
||||
SetExpression expression;
|
||||
int issue;
|
||||
int? issue;
|
||||
int lineNumber;
|
||||
|
||||
TestRule(this.name, this.expression, this.issue, this.lineNumber);
|
||||
@@ -161,8 +161,8 @@ class TestExpectations {
|
||||
|
||||
Map<String, Set<Expectation>> _map;
|
||||
bool _preprocessed = false;
|
||||
Map<String, RegExp> _regExpCache;
|
||||
Map<String, List<RegExp>> _keyToRegExps;
|
||||
Map<String, RegExp>? _regExpCache;
|
||||
Map<String, List<RegExp>>? _keyToRegExps;
|
||||
|
||||
/**
|
||||
* Create a TestExpectations object. See the [expectations] method
|
||||
@@ -203,7 +203,7 @@ class TestExpectations {
|
||||
_preprocessForMatching();
|
||||
|
||||
_map.forEach((key, expectation) {
|
||||
List regExps = _keyToRegExps[key];
|
||||
List<RegExp> regExps = _keyToRegExps![key]!;
|
||||
if (regExps.length > splitFilename.length) return;
|
||||
for (var i = 0; i < regExps.length; i++) {
|
||||
if (!regExps[i].hasMatch(splitFilename[i])) return;
|
||||
@@ -231,20 +231,19 @@ class TestExpectations {
|
||||
_regExpCache = {};
|
||||
|
||||
_map.forEach((key, expectations) {
|
||||
if (_keyToRegExps[key] != null) return;
|
||||
if (_keyToRegExps![key] != null) return;
|
||||
var splitKey = key.split('/');
|
||||
var regExps = new List<RegExp>.filled(splitKey.length, null);
|
||||
for (var i = 0; i < splitKey.length; i++) {
|
||||
var regExps = new List<RegExp>.generate(splitKey.length, (int i) {
|
||||
var component = splitKey[i];
|
||||
var regExp = _regExpCache[component];
|
||||
var regExp = _regExpCache![component];
|
||||
if (regExp == null) {
|
||||
var pattern = "^${splitKey[i]}\$".replaceAll('*', '.*');
|
||||
regExp = new RegExp(pattern);
|
||||
_regExpCache[component] = regExp;
|
||||
_regExpCache![component] = regExp;
|
||||
}
|
||||
regExps[i] = regExp;
|
||||
}
|
||||
_keyToRegExps[key] = regExps;
|
||||
return regExp;
|
||||
}, growable: false);
|
||||
_keyToRegExps![key] = regExps;
|
||||
});
|
||||
|
||||
_regExpCache = null;
|
||||
|
||||
@@ -17,11 +17,11 @@ abstract class TestDescription implements Comparable<TestDescription> {
|
||||
class FileBasedTestDescription extends TestDescription {
|
||||
final Uri root;
|
||||
final File file;
|
||||
final Uri output;
|
||||
final Uri? output;
|
||||
|
||||
/// If non-null, this is a generated multitest, and the set contains the
|
||||
/// expected outcomes.
|
||||
Set<String> multitestExpectations;
|
||||
Set<String>? multitestExpectations;
|
||||
|
||||
FileBasedTestDescription(this.root, this.file, {this.output});
|
||||
|
||||
@@ -52,8 +52,8 @@ class FileBasedTestDescription extends TestDescription {
|
||||
sink.writeln('.main,');
|
||||
}
|
||||
|
||||
static FileBasedTestDescription from(Uri root, FileSystemEntity entity,
|
||||
{Pattern pattern}) {
|
||||
static FileBasedTestDescription? from(Uri root, FileSystemEntity entity,
|
||||
{Pattern? pattern}) {
|
||||
if (entity is! File) return null;
|
||||
pattern ??= "_test.dart";
|
||||
String path = entity.uri.path;
|
||||
|
||||
@@ -49,7 +49,7 @@ class TestRoot {
|
||||
|
||||
TestRoot(this.packages, this.suites);
|
||||
|
||||
Analyze get analyze => suites.last;
|
||||
Analyze get analyze => suites.last as Analyze;
|
||||
|
||||
List<Uri> get urisToAnalyze => analyze.uris;
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ import 'dart:isolate' show Capability, Isolate, ReceivePort;
|
||||
import 'log.dart' show StdoutLogger;
|
||||
|
||||
Future runGuarded(Future f(),
|
||||
{void printLineOnStdout(line),
|
||||
void handleLateError(error, StackTrace stackTrace)}) {
|
||||
{void Function(String)? printLineOnStdout,
|
||||
void Function(dynamic, StackTrace)? handleLateError}) {
|
||||
var printWrapper;
|
||||
if (printLineOnStdout != null) {
|
||||
printWrapper = (_1, _2, _3, String line) {
|
||||
@@ -39,6 +39,7 @@ Future runGuarded(Future f(),
|
||||
// Ignored.
|
||||
}
|
||||
stderr
|
||||
// ignore: unnecessary_null_comparison
|
||||
.write("$errorString\n" + (stackTrace == null ? "" : "$stackTrace"));
|
||||
stderr.flush();
|
||||
exit(255);
|
||||
@@ -81,7 +82,7 @@ Future runGuarded(Future f(),
|
||||
/// Ping [isolate] to ensure control messages have been delivered. Control
|
||||
/// messages are things like [Isolate.addErrorListener] and
|
||||
/// [Isolate.addOnExitListener].
|
||||
Future acknowledgeControlMessages(Isolate isolate, {Capability resume}) {
|
||||
Future acknowledgeControlMessages(Isolate isolate, {Capability? resume}) {
|
||||
ReceivePort ping = new ReceivePort();
|
||||
Isolate.current.ping(ping.sendPort);
|
||||
if (resume == null) {
|
||||
|
||||
@@ -4,4 +4,4 @@ name: testing
|
||||
# This package is not intended for consumption on pub.dev. DO NOT publish.
|
||||
publish_to: none
|
||||
environment:
|
||||
sdk: '>=2.0.0 <3.0.0'
|
||||
sdk: '>=2.12.0 <3.0.0'
|
||||
|
||||
Reference in New Issue
Block a user