[pkg/testing] analyze using package:lints

Change-Id: If43bc64029ac00575dc154b797fc7630d4dac82e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/250764
Commit-Queue: Devon Carew <devoncarew@google.com>
Reviewed-by: Nate Bosch <nbosch@google.com>
This commit is contained in:
Devon Carew
2022-07-06 18:55:40 +00:00
committed by Commit Bot
parent 6e3ef8b9e6
commit b27709f1b8
21 changed files with 268 additions and 263 deletions
+2
View File
@@ -2,6 +2,8 @@
# 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.
include: package:lints/core.yaml
analyzer:
errors:
# Allow having TODOs in the code
+2 -2
View File
@@ -8,11 +8,11 @@ import 'testing.dart';
Future<ChainContext> createContext(
Chain suite, Map<String, String> environment) async {
return new VmContext();
return VmContext();
}
class VmContext extends ChainContext {
final List<Step> steps = const <Step>[const DartVmStep()];
final List<Step> steps = const <Step>[DartVmStep()];
}
class DartVmStep extends Step<FileBasedTestDescription, int, VmContext> {
+23 -22
View File
@@ -33,7 +33,7 @@ class Analyze extends Suite {
: super("analyze", "analyze", null);
Future<Null> run(Uri packages, List<Uri>? extraUris) {
List<Uri> allUris = new List<Uri>.from(uris);
List<Uri> allUris = List<Uri>.from(uris);
if (extraUris != null) {
allUris.addAll(extraUris);
}
@@ -52,7 +52,7 @@ class Analyze extends Suite {
}).toList();
List<RegExp> exclude =
json["exclude"].map<RegExp>((p) => new RegExp(p)).toList();
json["exclude"].map<RegExp>((p) => RegExp(p)).toList();
Map? gitGrep = json["git grep"];
List<String>? gitGrepPathspecs;
@@ -60,12 +60,13 @@ class Analyze extends Suite {
if (gitGrep != null) {
gitGrepPathspecs = gitGrep["pathspecs"] == null
? const <String>["."]
: new List<String>.from(gitGrep["pathspecs"]);
if (gitGrep["patterns"] != null)
gitGrepPatterns = new List<String>.from(gitGrep["patterns"]);
: List<String>.from(gitGrep["pathspecs"]);
if (gitGrep["patterns"] != null) {
gitGrepPatterns = List<String>.from(gitGrep["patterns"]);
}
}
return new Analyze(
return Analyze(
optionsUri, uris, exclude, gitGrepPathspecs, gitGrepPatterns);
}
@@ -89,9 +90,9 @@ class AnalyzerDiagnostic {
final String message;
static final Pattern potentialSplitPattern = new RegExp(r"\\|\|");
static final Pattern potentialSplitPattern = RegExp(r"\\|\|");
static final Pattern unescapePattern = new RegExp(r"\\(.)");
static final Pattern unescapePattern = RegExp(r"\\(.)");
AnalyzerDiagnostic(this.kind, this.detailedKind, this.code, this.uri,
this.line, this.startColumn, this.endColumn, this.message);
@@ -120,13 +121,13 @@ class AnalyzerDiagnostic {
}
addPart();
if (parts.length != 8) {
return new AnalyzerDiagnostic.malformed(line);
return AnalyzerDiagnostic.malformed(line);
}
return new AnalyzerDiagnostic(
return AnalyzerDiagnostic(
parts[0],
parts[1],
parts[2],
Uri.base.resolveUri(new Uri.file(parts[3])),
Uri.base.resolveUri(Uri.file(parts[3])),
int.parse(parts[4]),
int.parse(parts[5]),
int.parse(parts[6]),
@@ -145,10 +146,10 @@ class AnalyzerDiagnostic {
Stream<AnalyzerDiagnostic> parseAnalyzerOutput(
Stream<List<int>> stream) async* {
Stream<String> lines =
stream.transform(utf8.decoder).transform(new LineSplitter());
stream.transform(utf8.decoder).transform(LineSplitter());
await for (String line in lines) {
if (line.startsWith(">>> ")) continue;
yield new AnalyzerDiagnostic.fromLine(line);
yield AnalyzerDiagnostic.fromLine(line);
}
}
@@ -163,7 +164,7 @@ Future<Null> analyzeUris(
if (uris.isEmpty) return;
String topLevel;
try {
topLevel = new Uri.directory(
topLevel = Uri.directory(
(await git("rev-parse", <String>["--show-toplevel"])).trimRight())
.toFilePath(windows: false);
} catch (e) {
@@ -183,17 +184,17 @@ Future<Null> analyzeUris(
: path;
}
Set<String> filesToAnalyze = new Set<String>();
Set<String> filesToAnalyze = Set<String>();
for (Uri uri in uris) {
if (await new Directory.fromUri(uri).exists()) {
await for (FileSystemEntity entity in new Directory.fromUri(uri)
.list(recursive: true, followLinks: false)) {
if (await Directory.fromUri(uri).exists()) {
await for (FileSystemEntity entity
in Directory.fromUri(uri).list(recursive: true, followLinks: false)) {
if (entity is File && entity.path.endsWith(".dart")) {
filesToAnalyze.add(toFilePath(entity.uri));
}
}
} else if (await new File.fromUri(uri).exists()) {
} else if (await File.fromUri(uri).exists()) {
filesToAnalyze.add(toFilePath(uri));
} else {
throw "File not found: ${uri}";
@@ -212,7 +213,7 @@ Future<Null> analyzeUris(
const String analyzerPath = "pkg/analyzer_cli/bin/analyzer.dart";
Uri analyzer = Uri.base.resolve(analyzerPath);
if (!await new File.fromUri(analyzer).exists()) {
if (!await File.fromUri(analyzer).exists()) {
throw "Couldn't find '$analyzerPath' in '${toFilePath(Uri.base)}'";
}
List<String> arguments = <String>[
@@ -233,14 +234,14 @@ Future<Null> analyzeUris(
} else {
print("Running dartanalyzer.");
}
Stopwatch sw = new Stopwatch()..start();
Stopwatch sw = Stopwatch()..start();
Process process = await startDart(
analyzer, const <String>["--batch"], dartArguments..remove("-c"));
process.stdin.writeln(arguments.join(" "));
process.stdin.close();
bool hasOutput = false;
Set<String> seen = new Set<String>();
Set<String> seen = Set<String>();
processAnalyzerOutput(Stream<AnalyzerDiagnostic> diagnostics) async {
await for (AnalyzerDiagnostic diagnostic in diagnostics) {
+29 -27
View File
@@ -15,7 +15,7 @@ import 'suite.dart' show Suite;
import '../testing.dart' show FileBasedTestDescription, TestDescription;
import 'test_dart/status_file_parser.dart'
show ReadTestExpectations, TestExpectations;
show readTestExpectations, TestExpectations;
import 'zone_helper.dart' show runGuarded;
@@ -27,7 +27,7 @@ import 'multitest.dart' show MultitestTransformer, isError;
import 'expectation.dart' show Expectation, ExpectationGroup, ExpectationSet;
typedef Future<ChainContext> CreateContext(
typedef CreateContext = Future<ChainContext> Function(
Chain suite, Map<String, String> environment);
/// A test suite for tool chains, for example, a compiler.
@@ -55,11 +55,11 @@ class Chain extends Suite {
Uri uri = base.resolve(path);
Uri statusFile = base.resolve(json["status"]);
List<RegExp> pattern =
json["pattern"].map<RegExp>((p) => new RegExp(p)).toList();
json["pattern"].map<RegExp>((p) => RegExp(p)).toList();
List<RegExp> exclude =
json["exclude"].map<RegExp>((p) => new RegExp(p)).toList();
json["exclude"].map<RegExp>((p) => RegExp(p)).toList();
bool processMultitests = json["process-multitests"] ?? false;
return new Chain(name, kind, source, uri, statusFile, pattern, exclude,
return Chain(name, kind, source, uri, statusFile, pattern, exclude,
processMultitests);
}
@@ -77,7 +77,7 @@ class Chain extends Suite {
sink.writeln(".createContext, environment, selectors, r'''");
const String jsonExtraIndent = " ";
sink.write(jsonExtraIndent);
sink.writeAll(splitLines(new JsonEncoder.withIndent(" ").convert(this)),
sink.writeAll(splitLines(JsonEncoder.withIndent(" ").convert(this)),
jsonExtraIndent);
sink.writeln("''');");
}
@@ -106,7 +106,7 @@ abstract class ChainContext {
Future<Null> run(Chain suite, Set<String> selectors,
{int shards = 1,
int shard = 0,
Logger logger: const StdoutLogger()}) async {
Logger logger = const StdoutLogger()}) async {
assert(shards >= 1, "Invalid shards count: $shards");
assert(0 <= shard && shard < shards,
"Invalid shard index: $shard, not in range [0,$shards[.");
@@ -114,11 +114,11 @@ abstract class ChainContext {
.where((s) => s.endsWith('...'))
.map((s) => s.substring(0, s.length - 3))
.toList();
TestExpectations expectations = await ReadTestExpectations(
TestExpectations expectations = await readTestExpectations(
<String>[suite.statusFile!.toFilePath()], {}, expectationSet);
Stream<TestDescription> stream = list(suite);
if (suite.processMultitests) {
stream = stream.transform(new MultitestTransformer());
stream = stream.transform(MultitestTransformer());
}
List<TestDescription> descriptions = await stream.toList();
descriptions.sort();
@@ -156,7 +156,7 @@ abstract class ChainContext {
}
}
if (shouldSkip) continue;
final StringBuffer sb = new StringBuffer();
final StringBuffer sb = StringBuffer();
final Step? lastStep = steps.isNotEmpty ? steps.last : null;
final Iterator<Step> iterator = steps.iterator;
@@ -199,7 +199,7 @@ abstract class ChainContext {
}
}, printLineOnStdout: sb.writeln);
} else {
future = new Future.value(null);
future = Future.value(null);
}
future = future.then((_currentResult) async {
Result? currentResult = _currentResult;
@@ -260,7 +260,7 @@ abstract class ChainContext {
}
Stream<TestDescription> list(Chain suite) async* {
Directory testRoot = new Directory.fromUri(suite.uri);
Directory testRoot = Directory.fromUri(suite.uri);
if (await testRoot.exists()) {
Stream<FileSystemEntity> files =
testRoot.list(recursive: true, followLinks: false);
@@ -269,7 +269,7 @@ abstract class ChainContext {
String path = entity.uri.path;
if (suite.exclude.any((RegExp r) => path.contains(r))) continue;
if (suite.pattern.any((RegExp r) => path.contains(r))) {
yield new FileBasedTestDescription(suite.uri, entity);
yield FileBasedTestDescription(suite.uri, entity);
}
}
} else {
@@ -356,15 +356,15 @@ abstract class Step<I, O, C extends ChainContext> {
Future<Result<O>> run(I input, C context);
Result<O> unhandledError(error, StackTrace trace) {
return new Result<O>.crash(error, trace);
return Result<O>.crash(error, trace);
}
Result<O> pass(O output) => new Result<O>.pass(output);
Result<O> pass(O output) => Result<O>.pass(output);
Result<O> crash(error, StackTrace trace) => new Result<O>.crash(error, trace);
Result<O> crash(error, StackTrace trace) => Result<O>.crash(error, trace);
Result<O> fail(O output, [error, StackTrace? trace]) {
return new Result<O>.fail(output, error, trace);
return Result<O>.fail(output, error, trace);
}
}
@@ -373,7 +373,7 @@ class Result<O> {
final Expectation outcome;
final error;
final Object? error;
final StackTrace? trace;
@@ -389,10 +389,14 @@ class Result<O> {
///
final bool canBeFixWithUpdateExpectations;
Result(this.output, this.outcome, this.error,
{this.trace,
this.autoFixCommand,
this.canBeFixWithUpdateExpectations: false});
Result(
this.output,
this.outcome,
this.error, {
this.trace,
this.autoFixCommand,
this.canBeFixWithUpdateExpectations = false,
});
Result.pass(O output) : this(output, Expectation.Pass, null);
@@ -411,12 +415,11 @@ class Result<O> {
}
Result<O> copyWithOutcome(Expectation outcome) {
return new Result<O>(output, outcome, error, trace: trace)
..logs.addAll(logs);
return Result<O>(output, outcome, error, trace: trace)..logs.addAll(logs);
}
Result<O2> copyWithOutput<O2>(O2 output) {
return new Result<O2>(output, outcome, error,
return Result<O2>(output, outcome, error,
trace: trace,
autoFixCommand: autoFixCommand,
canBeFixWithUpdateExpectations: canBeFixWithUpdateExpectations)
@@ -428,8 +431,7 @@ 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)) as Chain;
Chain suite = Suite.fromJsonMap(Uri.base, json.decode(jsonText)) as Chain;
print("Running ${suite.name}");
ChainContext context = await f(suite, environment);
return context.run(suite, selectors);
+4 -4
View File
@@ -22,11 +22,11 @@ List<String> get dartArguments =>
Stream<FileBasedTestDescription> listTests(List<Uri> testRoots,
{Pattern? pattern}) {
StreamController<FileBasedTestDescription> controller =
new StreamController<FileBasedTestDescription>();
StreamController<FileBasedTestDescription>();
Map<Uri, StreamSubscription?> subscriptions = <Uri, StreamSubscription>{};
for (Uri testRootUri in testRoots) {
subscriptions[testRootUri] = null;
Directory testRoot = new Directory.fromUri(testRootUri);
Directory testRoot = Directory.fromUri(testRootUri);
testRoot.exists().then((bool exists) {
if (exists) {
Stream<FileSystemEntity> stream =
@@ -75,10 +75,10 @@ const _dartSdk = (String.fromEnvironment("DART_SDK", defaultValue: "1") ==
Uri computeDartSdk() {
String? dartSdkPath = Platform.environment["DART_SDK"] ?? _dartSdk;
if (dartSdkPath != null) {
return Uri.base.resolveUri(new Uri.file(dartSdkPath));
return Uri.base.resolveUri(Uri.file(dartSdkPath));
} else {
return Uri.base
.resolveUri(new Uri.file(Platform.resolvedExecutable))
.resolveUri(Uri.file(Platform.resolvedExecutable))
.resolve("../");
}
}
+1 -1
View File
@@ -13,7 +13,7 @@ import 'dart:isolate' show ReceivePort;
import 'log.dart';
Future<T?> withErrorHandling<T>(Future<T> f(), {Logger? logger}) async {
final ReceivePort port = new ReceivePort();
final ReceivePort port = ReceivePort();
try {
return await f();
} catch (e, trace) {
+12 -17
View File
@@ -13,20 +13,16 @@ library testing.expectation;
/// use the canonical expectation instead of a more specific one. Note this
/// isn't implemented yet.
class Expectation {
static const Expectation Pass =
const Expectation("Pass", ExpectationGroup.Pass);
static const Expectation Pass = Expectation("Pass", ExpectationGroup.Pass);
static const Expectation Crash =
const Expectation("Crash", ExpectationGroup.Crash);
static const Expectation Crash = Expectation("Crash", ExpectationGroup.Crash);
static const Expectation Timeout =
const Expectation("Timeout", ExpectationGroup.Timeout);
Expectation("Timeout", ExpectationGroup.Timeout);
static const Expectation Fail =
const Expectation("Fail", ExpectationGroup.Fail);
static const Expectation Fail = Expectation("Fail", ExpectationGroup.Fail);
static const Expectation Skip =
const Expectation("Skip", ExpectationGroup.Skip);
static const Expectation Skip = Expectation("Skip", ExpectationGroup.Skip);
final String name;
@@ -61,18 +57,17 @@ class Expectation {
}
class ExpectationSet {
static const ExpectationSet Default =
const ExpectationSet(const <String, Expectation>{
static const ExpectationSet Default = ExpectationSet(<String, Expectation>{
"pass": Expectation.Pass,
"crash": Expectation.Crash,
"timeout": Expectation.Timeout,
"fail": Expectation.Fail,
"skip": Expectation.Skip,
"missingcompiletimeerror":
const Expectation("MissingCompileTimeError", ExpectationGroup.Fail),
Expectation("MissingCompileTimeError", ExpectationGroup.Fail),
"missingruntimeerror":
const Expectation("MissingRuntimeError", ExpectationGroup.Fail),
"runtimeerror": const Expectation("RuntimeError", ExpectationGroup.Fail),
Expectation("MissingRuntimeError", ExpectationGroup.Fail),
"runtimeerror": Expectation("RuntimeError", ExpectationGroup.Fail),
});
final Map<String, Expectation> internalMap;
@@ -86,7 +81,7 @@ class ExpectationSet {
factory ExpectationSet.fromJsonList(List data) {
Map<String, Expectation> internalMap =
new Map<String, Expectation>.from(Default.internalMap);
Map<String, Expectation>.from(Default.internalMap);
for (Map map in data) {
String? name;
String? group;
@@ -112,14 +107,14 @@ class ExpectationSet {
if (group == null) {
throw "No group provided in '$map'";
}
Expectation expectation = new Expectation(name!, groupFromString(group!));
Expectation expectation = Expectation(name!, groupFromString(group!));
name = name!.toLowerCase();
if (internalMap.containsKey(name)) {
throw "Duplicated expectation name: '$name'.";
}
internalMap[name!] = expectation;
}
return new ExpectationSet(internalMap);
return ExpectationSet(internalMap);
}
}
+4 -4
View File
@@ -28,7 +28,7 @@ final String cursorUp = enableAnsiEscapes ? cursorUpCodes : "";
final String eraseLine = enableAnsiEscapes ? eraseLineCodes : "";
final Stopwatch wallclock = new Stopwatch()..start();
final Stopwatch wallclock = Stopwatch()..start();
bool _isVerbose = const bool.fromEnvironment("verbose");
@@ -195,13 +195,13 @@ class StdoutLogger implements Logger {
void noticeFrameworkCatchError(error, StackTrace stackTrace) {}
}
String pad(Object o, int pad, {String filler: " "}) {
String pad(Object o, int pad, {String filler = " "}) {
String result = (filler * pad) + "$o";
return result.substring(result.length - pad);
}
String numberedLines(String text) {
StringBuffer result = new StringBuffer();
StringBuffer result = StringBuffer();
int lineNumber = 1;
List<String> lines = splitLines(text);
int pad = "${lines.length}".length;
@@ -217,5 +217,5 @@ String numberedLines(String text) {
}
List<String> splitLines(String text) {
return text.split(new RegExp('^', multiLine: true));
return text.split(RegExp('^', multiLine: true));
}
+9 -10
View File
@@ -26,10 +26,10 @@ bool isCheckedModeError(Set<String> expectations) {
class MultitestTransformer
extends StreamTransformerBase<TestDescription, TestDescription> {
static RegExp multitestMarker = new RegExp(r"//[#/]");
static RegExp multitestMarker = RegExp(r"//[#/]");
static int _multitestMarkerLength = 3;
static const List<String> validOutcomesList = const <String>[
static const List<String> validOutcomesList = <String>[
"ok",
"syntax error",
"compile-time error",
@@ -39,8 +39,7 @@ class MultitestTransformer
"checked mode compile-time error",
];
static final Set<String> validOutcomes =
new Set<String>.from(validOutcomesList);
static final Set<String> validOutcomes = Set<String>.from(validOutcomesList);
Stream<TestDescription> bind(Stream<TestDescription> stream) async* {
List<String> errors = <String>[];
@@ -70,7 +69,7 @@ class MultitestTransformer
"none": linesWithoutAnnotations,
};
Map<String, Set<String>> outcomes = <String, Set<String>>{
"none": new Set<String>(),
"none": Set<String>(),
};
int lineNumber = 0;
for (String line in splitLines(contents!)) {
@@ -97,11 +96,11 @@ class MultitestTransformer
}
}
if (subtestName != null) {
List<String> lines = testsAsLines.putIfAbsent(subtestName,
() => new List<String>.from(linesWithoutAnnotations));
List<String> lines = testsAsLines.putIfAbsent(
subtestName, () => List<String>.from(linesWithoutAnnotations));
lines.add(line);
Set<String> subtestOutcomes =
outcomes.putIfAbsent(subtestName, () => new Set<String>());
outcomes.putIfAbsent(subtestName, () => Set<String>());
if (subtestOutcomesList!.length != 1 ||
subtestOutcomesList.single != "continued") {
for (String outcome in subtestOutcomesList) {
@@ -123,14 +122,14 @@ class MultitestTransformer
}
Uri root = Uri.base.resolve("generated/");
Directory generated =
new Directory.fromUri(root.resolve(multitest.shortName));
Directory.fromUri(root.resolve(multitest.shortName));
generated = await generated.create(recursive: true);
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));
FileBasedTestDescription(root, File.fromUri(uri));
subtest.multitestExpectations = outcomes[name];
await subtest.file.writeAsString(lines.join(""));
yield subtest;
+10 -10
View File
@@ -54,7 +54,7 @@ Future<Null> runMe(List<String> arguments, CreateContext f,
Uri? me,
int shards = 1,
int shard = 0,
Logger logger: const StdoutLogger()}) {
Logger logger = const StdoutLogger()}) {
me ??= Platform.script;
return withErrorHandling(() async {
TestRoot testRoot = await computeTestRoot(configurationPath, me);
@@ -63,7 +63,7 @@ Future<Null> runMe(List<String> arguments, CreateContext f,
for (Chain suite in testRoot.toolChains) {
if (me == suite.source) {
ChainContext context = await f(suite, cl.environment);
await context.run(suite, new Set<String>.from(cl.selectors),
await context.run(suite, Set<String>.from(cl.selectors),
shards: shards, shard: shard, logger: logger);
}
}
@@ -104,8 +104,8 @@ Future<Null> run(List<String> arguments, List<String> suiteNames,
List<Suite> suites = root.suites
.where((Suite suite) => suiteNames.contains(suite.name))
.toList();
SuiteRunner runner = new SuiteRunner(suites, <String, String>{},
const <String>[], new Set<String>(), new Set<String>());
SuiteRunner runner = SuiteRunner(suites, <String, String>{},
const <String>[], Set<String>(), Set<String>());
String? program = await runner.generateDartProgram();
await runner.analyze(root.packages);
if (program != null) {
@@ -117,8 +117,8 @@ Future<Null> run(List<String> arguments, List<String> suiteNames,
Future<Null> runProgram(String program, Uri packages) async {
const StdoutLogger().logMessage("Running:");
const StdoutLogger().logNumberedLines(program);
Uri dataUri = new Uri.dataFromString(program);
ReceivePort exitPort = new ReceivePort();
Uri dataUri = Uri.dataFromString(program);
ReceivePort exitPort = ReceivePort();
Isolate isolate = await Isolate.spawnUri(dataUri, <String>[], null,
paused: true,
onExit: exitPort.sendPort,
@@ -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]));
: Future<Null>.error(error![0], StackTrace.fromString(error![1]));
}
class SuiteRunner {
@@ -164,9 +164,9 @@ class SuiteRunner {
Future<String?> generateDartProgram() async {
testUris.clear();
StringBuffer imports = new StringBuffer();
StringBuffer dart = new StringBuffer();
StringBuffer chain = new StringBuffer();
StringBuffer imports = StringBuffer();
StringBuffer dart = StringBuffer();
StringBuffer chain = StringBuffer();
bool hasRunnableTests = false;
await for (FileBasedTestDescription description in listDescriptions()) {
+10 -11
View File
@@ -33,7 +33,7 @@ class CommandLine {
Set<String> get skip => commaSeparated("--skip=");
Set<String> commaSeparated(String prefix) {
return new Set<String>.from(options.expand((String s) {
return Set<String>.from(options.expand((String s) {
if (!s.startsWith(prefix)) return const [];
s = s.substring(prefix.length);
return s.split(",");
@@ -76,7 +76,7 @@ class CommandLine {
String configurationPath;
if (configurationPaths.length == 1) {
configurationPath = configurationPaths.single;
File file = new File(configurationPath);
File file = File(configurationPath);
if (await file.exists()) {
// If [configurationPath] exists as a file, use the absolute URI. This
// handles absolute paths on Windows.
@@ -84,8 +84,8 @@ class CommandLine {
}
} else {
configurationPath = "testing.json";
if (!await new File(configurationPath).exists()) {
Directory test = new Directory("test");
if (!await File(configurationPath).exists()) {
Directory test = Directory("test");
if (await test.exists()) {
List<FileSystemEntity> candidates = await test
.list(recursive: true, followLinks: false)
@@ -113,8 +113,7 @@ class CommandLine {
.logMessage("Reading configuration file '$configurationPath'.");
Uri? configuration =
await Isolate.resolvePackageUri(Uri.base.resolve(configurationPath));
if (configuration == null ||
!await new File.fromUri(configuration).exists()) {
if (configuration == null || !await File.fromUri(configuration).exists()) {
return fail("Couldn't locate: '$configurationPath'.");
}
return configuration;
@@ -124,14 +123,14 @@ class CommandLine {
int index = arguments.indexOf("--");
Set<String> options;
if (index != -1) {
options = new Set<String>.from(arguments.getRange(0, index));
options = 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);
return CommandLine(options, arguments);
}
}
@@ -153,11 +152,11 @@ main(List<String> arguments) => withErrorHandling(() async {
print("Use --verbose to display more details.");
}
TestRoot root = await TestRoot.fromUri(configuration);
SuiteRunner runner = new SuiteRunner(
SuiteRunner runner = 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();
Stopwatch sw = Stopwatch()..start();
if (program == null) {
if (!hasAnalyzerSuites) {
fail("No tests configured.");
@@ -174,7 +173,7 @@ Future<void> runTests(Map<String, Function> tests) =>
for (String name in tests.keys) {
const StdoutLogger()
.logTestStart(completed, 0, tests.length, null, null);
StringBuffer sb = new StringBuffer();
StringBuffer sb = StringBuffer();
try {
await runGuarded(() {
print("Running test $name");
+15 -13
View File
@@ -23,17 +23,17 @@ class StdioProcess {
StdioProcess(this.exitCode, this.output);
Result<int> toResult({int expected: 0}) {
Result<int> toResult({int expected = 0}) {
if (exitCode == expected) {
return new Result<int>.pass(exitCode);
return Result<int>.pass(exitCode);
} else {
return new Result<int>(
return Result<int>(
exitCode, ExpectationSet.Default["RuntimeError"], output);
}
}
static StreamTransformer<String, String> transformToStdio(Stdout stdio) {
return new StreamTransformer<String, String>.fromHandlers(
return StreamTransformer<String, String>.fromHandlers(
handleData: (String data, EventSink<String> sink) {
sink.add(data);
stdio.write(data);
@@ -42,15 +42,15 @@ class StdioProcess {
static Future<StdioProcess> run(String executable, List<String> arguments,
{String? input,
Duration? timeout: const Duration(seconds: 60),
bool suppressOutput: true,
bool runInShell: false}) async {
Duration? timeout = const Duration(seconds: 60),
bool suppressOutput = true,
bool runInShell = false}) async {
Process process =
await Process.start(executable, arguments, runInShell: runInShell);
Timer? timer;
StringBuffer sb = new StringBuffer();
StringBuffer sb = StringBuffer();
if (timeout != null) {
timer = new Timer(timeout, () {
timer = Timer(timeout, () {
sb.write("Process timed out: ");
sb.write(executable);
sb.write(" ");
@@ -58,7 +58,7 @@ class StdioProcess {
sb.writeln();
sb.writeln("Sending SIGTERM to process");
process.kill();
timer = new Timer(const Duration(seconds: 10), () {
timer = Timer(const Duration(seconds: 10), () {
sb.writeln("Sending SIGKILL to process");
process.kill(ProcessSignal.sigkill);
});
@@ -75,13 +75,15 @@ class StdioProcess {
stdoutStream = stdoutStream.transform(transformToStdio(io.stdout));
stderrStream = stderrStream.transform(transformToStdio(io.stderr));
}
Future<List<String>> stdoutFuture = stdoutStream.toList() as Future<List<String>>;
Future<List<String>> stderrFuture = stderrStream.toList() as Future<List<String>>;
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);
sb.writeAll(await stderrFuture);
await closeFuture;
return new StdioProcess(exitCode, "$sb");
return StdioProcess(exitCode, "$sb");
}
}
+6 -6
View File
@@ -23,13 +23,13 @@ abstract class Suite {
String name = json["name"];
switch (kind) {
case "dart":
return new Dart.fromJsonMap(base, json, name);
return Dart.fromJsonMap(base, json, name);
case "chain":
return new Chain.fromJsonMap(base, json, name, kind);
return Chain.fromJsonMap(base, json, name, kind);
case "test_dart":
return new TestDart.fromJsonMap(base, json, name, kind);
return TestDart.fromJsonMap(base, json, name, kind);
default:
throw "Suite '$name' has unknown kind '$kind'.";
@@ -78,10 +78,10 @@ class Dart extends Suite {
factory Dart.fromJsonMap(Uri base, Map json, String name) {
Uri uri = base.resolve(json["path"]);
List<RegExp> pattern =
new List<RegExp>.from(json["pattern"].map((String p) => new RegExp(p)));
List<RegExp>.from(json["pattern"].map((String p) => RegExp(p)));
List<RegExp> exclude =
new List<RegExp>.from(json["exclude"].map((String p) => new RegExp(p)));
return new Dart(name, uri, pattern, exclude);
List<RegExp>.from(json["exclude"].map((String p) => RegExp(p)));
return Dart(name, uri, pattern, exclude);
}
String toString() => "Dart($name, $uri, $pattern, $exclude)";
+2 -2
View File
@@ -30,9 +30,9 @@ class TestDart extends Suite {
String common = json["common"] ?? "";
String processes = json["processes"] ?? "-j${Platform.numberOfProcessors}";
List<String> commandLines = json["command-lines"] == null
? new List<String>.from(json["command-lines"])
? List<String>.from(json["command-lines"])
: <String>[];
return new TestDart(name, common, processes, commandLines);
return TestDart(name, common, processes, commandLines);
}
void writeFirstImportOn(StringSink sink) {
+27 -20
View File
@@ -49,6 +49,12 @@ class Path {
}
int get hashCode => _path.hashCode;
@override
bool operator ==(Object other) {
return other is Path && _path == other._path;
}
bool get isEmpty => _path.isEmpty;
bool get isAbsolute => _path.startsWith('/');
bool get hasTrailingSeparator => _path.endsWith('/');
@@ -61,7 +67,7 @@ class Path {
// Throws exception if an impossible case is reached.
if (base.isAbsolute != isAbsolute ||
base.isWindowsShare != isWindowsShare) {
throw new ArgumentError("Invalid case of Path.relativeTo(base):\n"
throw ArgumentError("Invalid case of Path.relativeTo(base):\n"
" Path and base must both be relative, or both absolute.\n"
" Arguments: $_path.relativeTo($base)");
}
@@ -81,22 +87,22 @@ class Path {
if (basePath[1] != _path[1]) {
// Replace the drive letter in basePath with that from _path.
basePath = '/${_path[1]}:/${basePath.substring(4)}';
base = new Path(basePath);
base = Path(basePath);
}
} else {
throw new ArgumentError("Invalid case of Path.relativeTo(base):\n"
throw ArgumentError("Invalid case of Path.relativeTo(base):\n"
" Base path and target path are on different Windows drives.\n"
" Arguments: $_path.relativeTo($base)");
}
} else if (baseHasDrive != pathHasDrive) {
throw new ArgumentError("Invalid case of Path.relativeTo(base):\n"
throw ArgumentError("Invalid case of Path.relativeTo(base):\n"
" Base path must start with a drive letter if and "
"only if target path does.\n"
" Arguments: $_path.relativeTo($base)");
}
}
if (_path.startsWith(basePath)) {
if (_path == basePath) return new Path('.');
if (_path == basePath) return Path('.');
// There must be a '/' at the end of the match, or immediately after.
int matchEnd = basePath.length;
if (_path[matchEnd - 1] == '/' || _path[matchEnd] == '/') {
@@ -104,7 +110,7 @@ class Path {
while (matchEnd < _path.length && _path[matchEnd] == '/') {
matchEnd++;
}
return new Path(_path.substring(matchEnd)).canonicalize();
return Path(_path.substring(matchEnd)).canonicalize();
}
}
@@ -124,7 +130,7 @@ class Path {
final segments = <String>[];
if (common < baseSegments.length && baseSegments[common] == '..') {
throw new ArgumentError("Invalid case of Path.relativeTo(base):\n"
throw ArgumentError("Invalid case of Path.relativeTo(base):\n"
" Base path has more '..'s than path does.\n"
" Arguments: $_path.relativeTo($base)");
}
@@ -140,22 +146,21 @@ class Path {
if (hasTrailingSeparator) {
segments.add('');
}
return new Path(segments.join('/'));
return Path(segments.join('/'));
}
Path join(Path further) {
if (further.isAbsolute) {
throw new ArgumentError(
"Path.join called with absolute Path as argument.");
throw ArgumentError("Path.join called with absolute Path as argument.");
}
if (isEmpty) {
return further.canonicalize();
}
if (hasTrailingSeparator) {
var joined = new Path._internal('$_path${further}', isWindowsShare);
var joined = Path._internal('$_path${further}', isWindowsShare);
return joined.canonicalize();
}
var joined = new Path._internal('$_path/${further}', isWindowsShare);
var joined = Path._internal('$_path/${further}', isWindowsShare);
return joined.canonicalize();
}
@@ -193,7 +198,7 @@ class Path {
bool isAbs = isAbsolute;
List segs = segments();
String? drive;
if (isAbs && !segs.isEmpty && segs[0].length == 2 && segs[0][1] == ':') {
if (isAbs && segs.isNotEmpty && segs[0].length == 2 && segs[0][1] == ':') {
drive = segs[0];
segs.removeRange(0, 1);
}
@@ -244,7 +249,7 @@ class Path {
segmentsToJoin.add('');
}
}
return new Path._internal(segmentsToJoin.join('/'), isWindowsShare);
return Path._internal(segmentsToJoin.join('/'), isWindowsShare);
}
String toNativePath() {
@@ -275,11 +280,11 @@ class Path {
Path append(String finalSegment) {
if (isEmpty) {
return new Path._internal(finalSegment, isWindowsShare);
return Path._internal(finalSegment, isWindowsShare);
} else if (hasTrailingSeparator) {
return new Path._internal('$_path$finalSegment', isWindowsShare);
return Path._internal('$_path$finalSegment', isWindowsShare);
} else {
return new Path._internal('$_path/$finalSegment', isWindowsShare);
return Path._internal('$_path/$finalSegment', isWindowsShare);
}
}
@@ -298,10 +303,12 @@ class Path {
Path get directoryPath {
int pos = _path.lastIndexOf('/');
if (pos < 0) return new Path('');
while (pos > 0 && _path[pos - 1] == '/') --pos;
if (pos < 0) return Path('');
while (pos > 0 && _path[pos - 1] == '/') {
--pos;
}
var dirPath = (pos > 0) ? _path.substring(0, pos) : '/';
return new Path._internal(dirPath, isWindowsShare);
return Path._internal(dirPath, isWindowsShare);
}
String get filename {
@@ -4,31 +4,29 @@
library test_dart_copy.status_expression;
/**
* Parse and evaluate expressions in a .status file for Dart and V8.
* There are set expressions and Boolean expressions in a .status file.
* The grammar is:
* BooleanExpression := $variableName == value | $variableName != value |
* $variableName | (BooleanExpression) |
* BooleanExpression && BooleanExpression |
* BooleanExpression || BooleanExpression
*
* SetExpression := value | (SetExpression) |
* SetExpression || SetExpression |
* SetExpression if BooleanExpression |
* SetExpression , SetExpression
*
* Productions are listed in order of precedence, and the || and , operators
* both evaluate to set union, but with different precedence.
*
* Values and variableNames are non-empty strings of word characters, matching
* the RegExp \w+.
*
* Expressions evaluate as expected, with values of variables found in
* an environment passed to the evaluator. The SetExpression "value"
* evaluates to a singleton set containing that value. "A if B" evaluates
* to A if B is true, and to the empty set if B is false.
*/
/// Parse and evaluate expressions in a .status file for Dart and V8.
/// There are set expressions and Boolean expressions in a .status file.
/// The grammar is:
/// BooleanExpression := $variableName == value | $variableName != value |
/// $variableName | (BooleanExpression) |
/// BooleanExpression && BooleanExpression |
/// BooleanExpression || BooleanExpression
///
/// SetExpression := value | (SetExpression) |
/// SetExpression || SetExpression |
/// SetExpression if BooleanExpression |
/// SetExpression , SetExpression
///
/// Productions are listed in order of precedence, and the || and , operators
/// both evaluate to set union, but with different precedence.
///
/// Values and variableNames are non-empty strings of word characters, matching
/// the RegExp \w+.
///
/// Expressions evaluate as expected, with values of variables found in
/// an environment passed to the evaluator. The SetExpression "value"
/// evaluates to a singleton set containing that value. "A if B" evaluates
/// to A if B is true, and to the empty set if B is false.
class ExprEvaluationException {
String error;
@@ -57,12 +55,12 @@ class Tokenizer {
// Tokens are : "(", ")", "$", ",", "&&", "||", "==", "!=", and (maximal) \w+.
static final testRegexp =
new RegExp(r"^([()$\w\s,]|(\&\&)|(\|\|)|(\=\=)|(\!\=))+$");
static final regexp = new RegExp(r"[()$,]|(\&\&)|(\|\|)|(\=\=)|(\!\=)|\w+");
RegExp(r"^([()$\w\s,]|(\&\&)|(\|\|)|(\=\=)|(\!\=))+$");
static final regexp = RegExp(r"[()$,]|(\&\&)|(\|\|)|(\=\=)|(\!\=)|\w+");
List<String> tokenize() {
if (!testRegexp.hasMatch(expression)) {
throw new FormatException("Syntax error in '$expression'");
throw FormatException("Syntax error in '$expression'");
}
for (Match match in regexp.allMatches(expression)) {
tokens.add(match[0]!);
@@ -103,7 +101,7 @@ class TermVariable {
String termValue(environment) {
var value = environment[name];
if (value == null) {
throw new ExprEvaluationException("Could not find '$name' in environment "
throw ExprEvaluationException("Could not find '$name' in environment "
"while evaluating status file expression.");
}
return value.toString();
@@ -163,9 +161,8 @@ class SetIf implements SetExpression {
SetIf(this.left, this.right);
Set<String> evaluate(environment) => right.evaluate(environment)
? left.evaluate(environment)
: new Set<String>();
Set<String> evaluate(environment) =>
right.evaluate(environment) ? left.evaluate(environment) : Set<String>();
String toString() => "($left if $right)";
}
@@ -174,7 +171,7 @@ class SetConstant implements SetExpression {
SetConstant(String v) : value = v.toLowerCase();
Set<String> evaluate(environment) => new Set<String>.from([value]);
Set<String> evaluate(environment) => Set<String>.from([value]);
String toString() => value;
}
@@ -208,7 +205,7 @@ class ExpressionParser {
while (scanner.hasMore() && scanner.current == Token.UNION) {
scanner.advance();
SetExpression right = parseSetIf();
left = new SetUnion(left, right);
left = SetUnion(left, right);
}
return left;
}
@@ -218,7 +215,7 @@ class ExpressionParser {
while (scanner.hasMore() && scanner.current == "if") {
scanner.advance();
BooleanExpression right = parseBooleanExpression();
left = new SetIf(left, right);
left = SetIf(left, right);
}
return left;
}
@@ -228,7 +225,7 @@ class ExpressionParser {
while (scanner.hasMore() && scanner.current == Token.OR) {
scanner.advance();
SetExpression right = parseSetAtomic();
left = new SetUnion(left, right);
left = SetUnion(left, right);
}
return left;
}
@@ -238,16 +235,16 @@ class ExpressionParser {
scanner.advance();
SetExpression value = parseSetExpression();
if (scanner.current != Token.RIGHT_PAREN) {
throw new FormatException("Missing right parenthesis in expression");
throw FormatException("Missing right parenthesis in expression");
}
scanner.advance();
return value;
}
if (!new RegExp(r"^\w+$").hasMatch(scanner.current!)) {
throw new FormatException(
if (!RegExp(r"^\w+$").hasMatch(scanner.current!)) {
throw FormatException(
"Expected identifier in expression, got ${scanner.current}");
}
SetExpression value = new SetConstant(scanner.current!);
SetExpression value = SetConstant(scanner.current!);
scanner.advance();
return value;
}
@@ -259,7 +256,7 @@ class ExpressionParser {
while (scanner.hasMore() && scanner.current == Token.OR) {
scanner.advance();
BooleanExpression right = parseBooleanAnd();
left = new BooleanOperation(Token.OR, left, right);
left = BooleanOperation(Token.OR, left, right);
}
return left;
}
@@ -269,7 +266,7 @@ class ExpressionParser {
while (scanner.hasMore() && scanner.current == Token.AND) {
scanner.advance();
BooleanExpression right = parseBooleanAtomic();
left = new BooleanOperation(Token.AND, left, right);
left = BooleanOperation(Token.AND, left, right);
}
return left;
}
@@ -279,7 +276,7 @@ class ExpressionParser {
scanner.advance();
BooleanExpression value = parseBooleanExpression();
if (scanner.current != Token.RIGHT_PAREN) {
throw new FormatException("Missing right parenthesis in expression");
throw FormatException("Missing right parenthesis in expression");
}
scanner.advance();
return value;
@@ -288,29 +285,29 @@ class ExpressionParser {
// The only atomic booleans are of the form $variable == value or
// of the form $variable.
if (scanner.current != Token.DOLLAR_SYMBOL) {
throw new FormatException(
throw FormatException(
"Expected \$ in expression, got ${scanner.current}");
}
scanner.advance();
if (!new RegExp(r"^\w+$").hasMatch(scanner.current!)) {
throw new FormatException(
if (!RegExp(r"^\w+$").hasMatch(scanner.current!)) {
throw FormatException(
"Expected identifier in expression, got ${scanner.current}");
}
TermVariable left = new TermVariable(scanner.current!);
TermVariable left = 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!)) {
throw new FormatException(
if (!RegExp(r"^\w+$").hasMatch(scanner.current!)) {
throw FormatException(
"Expected value in expression, got ${scanner.current}");
}
TermConstant right = new TermConstant(scanner.current!);
TermConstant right = TermConstant(scanner.current!);
scanner.advance();
return new Comparison(left, right, negate);
return Comparison(left, right, negate);
} else {
return new BooleanVariable(left);
return BooleanVariable(left);
}
}
}
@@ -13,10 +13,10 @@ import "status_expression.dart";
import '../expectation.dart' show Expectation, ExpectationSet;
final RegExp SplitComment = new RegExp("^([^#]*)(#.*)?\$");
final RegExp HeaderPattern = new RegExp(r"^\[([^\]]+)\]");
final RegExp RulePattern = new RegExp(r"\s*([^: ]*)\s*:(.*)");
final RegExp IssueNumberPattern = new RegExp("[Ii]ssue ([0-9]+)");
final RegExp splitComment = RegExp("^([^#]*)(#.*)?\$");
final RegExp headerPattern = RegExp(r"^\[([^\]]+)\]");
final RegExp rulePattern = RegExp(r"\s*([^: ]*)\s*:(.*)");
final RegExp issueNumberPattern = RegExp("[Ii]ssue ([0-9]+)");
class StatusFile {
final Path location;
@@ -47,17 +47,17 @@ class Section {
}
}
Future<TestExpectations> ReadTestExpectations(List<String> statusFilePaths,
Future<TestExpectations> readTestExpectations(List<String> statusFilePaths,
Map<String, String> environment, ExpectationSet expectationSet) {
var testExpectations = new TestExpectations(expectationSet);
var testExpectations = TestExpectations(expectationSet);
return Future.wait(statusFilePaths.map((String statusFile) {
return ReadTestExpectationsInto(testExpectations, statusFile, environment);
return readTestExpectationsInto(testExpectations, statusFile, environment);
})).then((_) => testExpectations);
}
Future<void> ReadTestExpectationsInto(TestExpectations expectations,
Future<void> readTestExpectationsInto(TestExpectations expectations,
String statusFilePath, Map<String, String> environment) {
var completer = new Completer();
var completer = Completer();
List<Section> sections = <Section>[];
void sectionsRead() {
@@ -71,29 +71,29 @@ Future<void> ReadTestExpectationsInto(TestExpectations expectations,
completer.complete();
}
ReadConfigurationInto(new Path(statusFilePath), sections, sectionsRead);
readConfigurationInto(Path(statusFilePath), sections, sectionsRead);
return completer.future;
}
void ReadConfigurationInto(Path path, List<Section> sections, void onDone()) {
StatusFile statusFile = new StatusFile(path);
File file = new File(path.toNativePath());
void readConfigurationInto(Path path, List<Section> sections, void onDone()) {
StatusFile statusFile = StatusFile(path);
File file = File(path.toNativePath());
if (!file.existsSync()) {
throw new Exception('Cannot find test status file $path');
throw Exception('Cannot find test status file $path');
}
int lineNumber = 0;
Stream<String> lines = file
.openRead()
.cast<List<int>>()
.transform(utf8.decoder)
.transform(new LineSplitter());
.transform(LineSplitter());
Section currentSection = new Section.always(statusFile, -1);
Section currentSection = Section.always(statusFile, -1);
sections.add(currentSection);
lines.listen((String line) {
lineNumber++;
Match? match = SplitComment.firstMatch(line);
Match? match = splitComment.firstMatch(line);
line = (match == null) ? "" : match[1]!;
line = line.trim();
if (line.isEmpty) return;
@@ -101,36 +101,36 @@ void ReadConfigurationInto(Path path, List<Section> sections, void onDone()) {
// Extract the comment to get the issue number if needed.
String comment = (match == null || match[2] == null) ? "" : match[2]!;
match = HeaderPattern.firstMatch(line);
match = headerPattern.firstMatch(line);
if (match != null) {
String condition_string = match[1]!.trim();
List<String> tokens = new Tokenizer(condition_string).tokenize();
ExpressionParser parser = new ExpressionParser(new Scanner(tokens));
String conditionString = match[1]!.trim();
List<String> tokens = Tokenizer(conditionString).tokenize();
ExpressionParser parser = ExpressionParser(Scanner(tokens));
currentSection =
new Section(statusFile, parser.parseBooleanExpression(), lineNumber);
Section(statusFile, parser.parseBooleanExpression(), lineNumber);
sections.add(currentSection);
return;
}
match = RulePattern.firstMatch(line);
match = rulePattern.firstMatch(line);
if (match != null) {
String name = match[1]!.trim();
// TODO(whesse): Handle test names ending in a wildcard (*).
String expression_string = match[2]!.trim();
List<String> tokens = new Tokenizer(expression_string).tokenize();
String expressionString = match[2]!.trim();
List<String> tokens = Tokenizer(expressionString).tokenize();
SetExpression expression =
new ExpressionParser(new Scanner(tokens)).parseSetExpression();
ExpressionParser(Scanner(tokens)).parseSetExpression();
// Look for issue number in comment.
String? issueString = null;
match = IssueNumberPattern.firstMatch(comment);
match = issueNumberPattern.firstMatch(comment);
if (match != null) {
issueString = match[1];
if (issueString == null) issueString = match[2];
}
int? issue = issueString != null ? int.parse(issueString) : null;
currentSection.testRules
.add(new TestRule(name, expression, issue, lineNumber));
.add(TestRule(name, expression, issue, lineNumber));
return;
}
@@ -164,15 +164,11 @@ class TestExpectations {
Map<String, RegExp>? _regExpCache;
Map<String, List<RegExp>>? _keyToRegExps;
/**
* Create a TestExpectations object. See the [expectations] method
* for an explanation of matching.
*/
/// Create a TestExpectations object. See the [expectations] method
/// for an explanation of matching.
TestExpectations(this.expectationSet) : _map = {};
/**
* Add a rule to the expectations.
*/
/// Add a rule to the expectations.
void addRule(TestRule testRule, Map<String, String> environment) {
// Once we have started using the expectations we cannot add more
// rules.
@@ -181,22 +177,20 @@ class TestExpectations {
}
var names = testRule.expression.evaluate(environment);
var expectations = names.map((name) => expectationSet[name]);
_map.putIfAbsent(testRule.name, () => new Set()).addAll(expectations);
_map.putIfAbsent(testRule.name, () => Set()).addAll(expectations);
}
/**
* Compute the expectations for a test based on the filename.
*
* For every (key, expectation) pair. Match the key with the file
* name. Return the union of the expectations for all the keys
* that match.
*
* Normal matching splits the key and the filename into path
* components and checks that the anchored regular expression
* "^$keyComponent\$" matches the corresponding filename component.
*/
/// Compute the expectations for a test based on the filename.
///
/// For every (key, expectation) pair. Match the key with the file
/// name. Return the union of the expectations for all the keys
/// that match.
///
/// Normal matching splits the key and the filename into path
/// components and checks that the anchored regular expression
/// "^$keyComponent\$" matches the corresponding filename component.
Set<Expectation> expectations(String filename) {
var result = new Set<Expectation>();
var result = Set<Expectation>();
var splitFilename = filename.split('/');
// Create mapping from keys to list of RegExps once and for all.
@@ -233,12 +227,12 @@ class TestExpectations {
_map.forEach((key, expectations) {
if (_keyToRegExps![key] != null) return;
var splitKey = key.split('/');
var regExps = new List<RegExp>.generate(splitKey.length, (int i) {
var regExps = List<RegExp>.generate(splitKey.length, (int i) {
var component = splitKey[i];
var regExp = _regExpCache![component];
if (regExp == null) {
var pattern = "^${splitKey[i]}\$".replaceAll('*', '.*');
regExp = new RegExp(pattern);
regExp = RegExp(pattern);
_regExpCache![component] = regExp;
}
return regExp;
+1 -1
View File
@@ -63,7 +63,7 @@ class FileBasedTestDescription extends TestDescription {
} else if (path.contains(pattern)) {
hasMatch = true;
}
return hasMatch ? new FileBasedTestDescription(root, entity) : null;
return hasMatch ? FileBasedTestDescription(root, entity) : null;
}
String formatError(String message) {
+5 -5
View File
@@ -56,11 +56,11 @@ class TestRoot {
List<RegExp> get excludedFromAnalysis => analyze.exclude;
Iterable<Dart> get dartSuites {
return new List<Dart>.from(suites.where((Suite suite) => suite is Dart));
return List<Dart>.from(suites.whereType<Dart>());
}
Iterable<Chain> get toolChains {
return new List<Chain>.from(suites.where((Suite suite) => suite is Chain));
return List<Chain>.from(suites.whereType<Chain>());
}
String toString() {
@@ -68,7 +68,7 @@ class TestRoot {
}
static Future<TestRoot> fromUri(Uri uri) async {
String jsonText = await new File.fromUri(uri).readAsString();
String jsonText = await File.fromUri(uri).readAsString();
Map data = json.decode(jsonText);
addDefaults(data);
@@ -76,14 +76,14 @@ class TestRoot {
Uri packages = uri.resolve(data["packages"]);
List<Suite> suites = data["suites"]
.map<Suite>((json) => new Suite.fromJsonMap(uri, json))
.map<Suite>((json) => Suite.fromJsonMap(uri, json))
.toList();
Analyze analyze = await Analyze.fromJsonMap(uri, data["analyze"], suites);
suites.add(analyze);
return new TestRoot(packages, suites);
return TestRoot(packages, suites);
}
static void addDefaults(Map data) {
+8 -6
View File
@@ -16,14 +16,16 @@ import 'log.dart' show StdoutLogger;
Future runGuarded(Future f(),
{void Function(String)? printLineOnStdout,
void Function(dynamic, StackTrace)? handleLateError}) {
// ignore: prefer_typing_uninitialized_variables
var printWrapper;
if (printLineOnStdout != null) {
// ignore: non_constant_identifier_names
printWrapper = (_1, _2, _3, String line) {
printLineOnStdout(line);
};
}
Completer completer = new Completer();
Completer completer = Completer();
handleUncaughtError(error, StackTrace stackTrace) {
StdoutLogger().logUncaughtError(error, stackTrace);
@@ -46,9 +48,9 @@ Future runGuarded(Future f(),
}
}
ZoneSpecification specification = new ZoneSpecification(print: printWrapper);
ZoneSpecification specification = ZoneSpecification(print: printWrapper);
ReceivePort errorPort = new ReceivePort();
ReceivePort errorPort = ReceivePort();
Future errorFuture = errorPort.listen((_errors) {
List errors = _errors;
Isolate.current.removeErrorListener(errorPort.sendPort);
@@ -56,7 +58,7 @@ Future runGuarded(Future f(),
var error = errors[0];
var stackTrace = errors[1];
if (stackTrace != null) {
stackTrace = new StackTrace.fromString(stackTrace);
stackTrace = StackTrace.fromString(stackTrace);
}
handleUncaughtError(error, stackTrace);
}).asFuture();
@@ -65,7 +67,7 @@ Future runGuarded(Future f(),
Isolate.current.addErrorListener(errorPort.sendPort);
return acknowledgeControlMessages(Isolate.current).then((_) {
runZonedGuarded(
() => new Future(f).then(completer.complete),
() => Future(f).then(completer.complete),
handleUncaughtError,
zoneSpecification: specification,
);
@@ -83,7 +85,7 @@ Future runGuarded(Future f(),
/// messages are things like [Isolate.addErrorListener] and
/// [Isolate.addOnExitListener].
Future acknowledgeControlMessages(Isolate isolate, {Capability? resume}) {
ReceivePort ping = new ReceivePort();
ReceivePort ping = ReceivePort();
Isolate.current.ping(ping.sendPort);
if (resume == null) {
return ping.first;
+5
View File
@@ -3,5 +3,10 @@
name: testing
# This package is not intended for consumption on pub.dev. DO NOT publish.
publish_to: none
environment:
sdk: '>=2.12.0 <3.0.0'
# Use 'any' constraints here; we get our versions from the DEPS file.
dev_dependency:
lints: any