Reformat pkg/status_file.
I was starting to migrate it to use primary constructors but realized the formatting was out of date, so I figured I may as well fix that first so that the migration CL is easier to read. There are no changes in this CL, I only ran `dart format .`. Change-Id: I25f772ce0e0a00d83f1f8b561fc8bb9fe9486859 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/506741 Auto-Submit: Bob Nystrom <rnystrom@google.com> Commit-Queue: Bob Nystrom <rnystrom@google.com> Reviewed-by: Paul Berry <paulberry@google.com>
This commit is contained in:
committed by
dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent
8b555128be
commit
1e5aebc601
@@ -12,30 +12,40 @@ import 'package:status_file/utils.dart';
|
||||
|
||||
ArgParser buildParser() {
|
||||
var parser = ArgParser();
|
||||
parser.addFlag("check-for-disjunctions",
|
||||
negatable: false,
|
||||
defaultsTo: false,
|
||||
help: "Warn if a status header expression contains '||'.");
|
||||
parser.addFlag("check-for-non-existing",
|
||||
negatable: true,
|
||||
defaultsTo: true,
|
||||
help: "Check for and error on non-existing test entries.");
|
||||
parser.addFlag("text",
|
||||
abbr: "t",
|
||||
negatable: false,
|
||||
defaultsTo: false,
|
||||
help: "Lint text passed in stdin.");
|
||||
parser.addFlag("help",
|
||||
abbr: "h",
|
||||
negatable: false,
|
||||
defaultsTo: false,
|
||||
help: "Show help and commands for this tool.");
|
||||
parser.addFlag(
|
||||
"check-for-disjunctions",
|
||||
negatable: false,
|
||||
defaultsTo: false,
|
||||
help: "Warn if a status header expression contains '||'.",
|
||||
);
|
||||
parser.addFlag(
|
||||
"check-for-non-existing",
|
||||
negatable: true,
|
||||
defaultsTo: true,
|
||||
help: "Check for and error on non-existing test entries.",
|
||||
);
|
||||
parser.addFlag(
|
||||
"text",
|
||||
abbr: "t",
|
||||
negatable: false,
|
||||
defaultsTo: false,
|
||||
help: "Lint text passed in stdin.",
|
||||
);
|
||||
parser.addFlag(
|
||||
"help",
|
||||
abbr: "h",
|
||||
negatable: false,
|
||||
defaultsTo: false,
|
||||
help: "Show help and commands for this tool.",
|
||||
);
|
||||
return parser;
|
||||
}
|
||||
|
||||
void printHelp(ArgParser parser) {
|
||||
print("Usage: 'dart status_file/bin/lint.dart <path>' or 'dart "
|
||||
"status_file/bin/lint.dart -t <input>' for text input.");
|
||||
print(
|
||||
"Usage: 'dart status_file/bin/lint.dart <path>' or 'dart "
|
||||
"status_file/bin/lint.dart -t <input>' for text input.",
|
||||
);
|
||||
print(parser.usage);
|
||||
}
|
||||
|
||||
@@ -51,20 +61,26 @@ void main(List<String> arguments) {
|
||||
bool usePipe = results["text"];
|
||||
if (usePipe) {
|
||||
lintStdIn(
|
||||
checkForDisjunctions: checkForDisjunctions, checkForNonExisting: false);
|
||||
checkForDisjunctions: checkForDisjunctions,
|
||||
checkForNonExisting: false,
|
||||
);
|
||||
} else {
|
||||
if (results.rest.length != 1) {
|
||||
printHelp(parser);
|
||||
exit(1);
|
||||
}
|
||||
lintPath(results.rest.first,
|
||||
checkForDisjunctions: checkForDisjunctions,
|
||||
checkForNonExisting: checkForNonExisting);
|
||||
lintPath(
|
||||
results.rest.first,
|
||||
checkForDisjunctions: checkForDisjunctions,
|
||||
checkForNonExisting: checkForNonExisting,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void lintStdIn(
|
||||
{bool checkForDisjunctions = false, required bool checkForNonExisting}) {
|
||||
void lintStdIn({
|
||||
bool checkForDisjunctions = false,
|
||||
required bool checkForNonExisting,
|
||||
}) {
|
||||
var strings = <String>[];
|
||||
try {
|
||||
while (true) {
|
||||
@@ -80,13 +96,18 @@ void lintStdIn(
|
||||
}
|
||||
}
|
||||
|
||||
void lintPath(String path,
|
||||
{bool checkForDisjunctions = false, required bool checkForNonExisting}) {
|
||||
void lintPath(
|
||||
String path, {
|
||||
bool checkForDisjunctions = false,
|
||||
required bool checkForNonExisting,
|
||||
}) {
|
||||
var filesWithErrors = <String>[];
|
||||
if (FileSystemEntity.isFileSync(path)) {
|
||||
if (!lintFile(path,
|
||||
checkForDisjunctions: checkForDisjunctions,
|
||||
checkForNonExisting: checkForNonExisting)) {
|
||||
if (!lintFile(
|
||||
path,
|
||||
checkForDisjunctions: checkForDisjunctions,
|
||||
checkForNonExisting: checkForNonExisting,
|
||||
)) {
|
||||
filesWithErrors.add(path);
|
||||
}
|
||||
} else if (FileSystemEntity.isDirectorySync(path)) {
|
||||
@@ -94,9 +115,11 @@ void lintPath(String path,
|
||||
if (!canLint(entry.path)) {
|
||||
return;
|
||||
}
|
||||
if (!lintFile(entry.path,
|
||||
checkForDisjunctions: checkForDisjunctions,
|
||||
checkForNonExisting: checkForNonExisting)) {
|
||||
if (!lintFile(
|
||||
entry.path,
|
||||
checkForDisjunctions: checkForDisjunctions,
|
||||
checkForNonExisting: checkForNonExisting,
|
||||
)) {
|
||||
filesWithErrors.add(entry.path);
|
||||
}
|
||||
});
|
||||
@@ -110,37 +133,52 @@ void lintPath(String path,
|
||||
}
|
||||
}
|
||||
|
||||
bool lintText(List<String> text,
|
||||
{bool checkForDisjunctions = false, required bool checkForNonExisting}) {
|
||||
bool lintText(
|
||||
List<String> text, {
|
||||
bool checkForDisjunctions = false,
|
||||
required bool checkForNonExisting,
|
||||
}) {
|
||||
try {
|
||||
var statusFile = StatusFile.parse("stdin", text);
|
||||
return lintStatusFile(statusFile,
|
||||
checkForDisjunctions: checkForDisjunctions,
|
||||
checkForNonExisting: checkForNonExisting);
|
||||
return lintStatusFile(
|
||||
statusFile,
|
||||
checkForDisjunctions: checkForDisjunctions,
|
||||
checkForNonExisting: checkForNonExisting,
|
||||
);
|
||||
} on status_file.SyntaxError {
|
||||
stderr.writeln("Could not parse stdin.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lintFile(String path,
|
||||
{bool checkForDisjunctions = false, required bool checkForNonExisting}) {
|
||||
bool lintFile(
|
||||
String path, {
|
||||
bool checkForDisjunctions = false,
|
||||
required bool checkForNonExisting,
|
||||
}) {
|
||||
try {
|
||||
var statusFile = StatusFile.read(path);
|
||||
return lintStatusFile(statusFile,
|
||||
checkForDisjunctions: checkForDisjunctions,
|
||||
checkForNonExisting: checkForNonExisting);
|
||||
return lintStatusFile(
|
||||
statusFile,
|
||||
checkForDisjunctions: checkForDisjunctions,
|
||||
checkForNonExisting: checkForNonExisting,
|
||||
);
|
||||
} on status_file.SyntaxError catch (error) {
|
||||
stderr.writeln("Could not parse $path:\n$error");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lintStatusFile(StatusFile statusFile,
|
||||
{bool checkForDisjunctions = false, required bool checkForNonExisting}) {
|
||||
var lintingErrors = lint(statusFile,
|
||||
checkForDisjunctions: checkForDisjunctions,
|
||||
checkForNonExisting: checkForNonExisting);
|
||||
bool lintStatusFile(
|
||||
StatusFile statusFile, {
|
||||
bool checkForDisjunctions = false,
|
||||
required bool checkForNonExisting,
|
||||
}) {
|
||||
var lintingErrors = lint(
|
||||
statusFile,
|
||||
checkForDisjunctions: checkForDisjunctions,
|
||||
checkForNonExisting: checkForNonExisting,
|
||||
);
|
||||
if (lintingErrors.isEmpty) {
|
||||
print("${statusFile.path}\n Status file passed all tests");
|
||||
print("");
|
||||
|
||||
@@ -13,21 +13,27 @@ import 'package:status_file/utils.dart';
|
||||
|
||||
ArgParser buildParser() {
|
||||
var parser = ArgParser();
|
||||
parser.addFlag("overwrite",
|
||||
abbr: 'w',
|
||||
negatable: false,
|
||||
defaultsTo: false,
|
||||
help: "Overwrite input files with formatted output.");
|
||||
parser.addFlag("delete-non-existing",
|
||||
abbr: 'd',
|
||||
negatable: true,
|
||||
defaultsTo: true,
|
||||
help: "Remove non-existing test entries.");
|
||||
parser.addFlag("help",
|
||||
abbr: "h",
|
||||
negatable: false,
|
||||
defaultsTo: false,
|
||||
help: "Show help and commands for this tool.");
|
||||
parser.addFlag(
|
||||
"overwrite",
|
||||
abbr: 'w',
|
||||
negatable: false,
|
||||
defaultsTo: false,
|
||||
help: "Overwrite input files with formatted output.",
|
||||
);
|
||||
parser.addFlag(
|
||||
"delete-non-existing",
|
||||
abbr: 'd',
|
||||
negatable: true,
|
||||
defaultsTo: true,
|
||||
help: "Remove non-existing test entries.",
|
||||
);
|
||||
parser.addFlag(
|
||||
"help",
|
||||
abbr: "h",
|
||||
negatable: false,
|
||||
defaultsTo: false,
|
||||
help: "Show help and commands for this tool.",
|
||||
);
|
||||
return parser;
|
||||
}
|
||||
|
||||
@@ -58,19 +64,27 @@ void main(List<String> arguments) {
|
||||
if (!canLint(entry.path)) {
|
||||
return;
|
||||
}
|
||||
normalizeFile(entry.path, overwrite,
|
||||
deleteNonExisting: deleteNonExisting);
|
||||
normalizeFile(
|
||||
entry.path,
|
||||
overwrite,
|
||||
deleteNonExisting: deleteNonExisting,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool normalizeFile(String path, bool writeFile,
|
||||
{required bool deleteNonExisting}) {
|
||||
bool normalizeFile(
|
||||
String path,
|
||||
bool writeFile, {
|
||||
required bool deleteNonExisting,
|
||||
}) {
|
||||
try {
|
||||
var statusFile = StatusFile.read(path);
|
||||
var normalizedStatusFile =
|
||||
normalizeStatusFile(statusFile, deleteNonExisting: deleteNonExisting);
|
||||
var normalizedStatusFile = normalizeStatusFile(
|
||||
statusFile,
|
||||
deleteNonExisting: deleteNonExisting,
|
||||
);
|
||||
if (writeFile) {
|
||||
File(path).writeAsStringSync(normalizedStatusFile.toString());
|
||||
print("Normalized $path");
|
||||
@@ -79,11 +93,15 @@ bool normalizeFile(String path, bool writeFile,
|
||||
}
|
||||
// Check if there are linting errors remaining, such as line comments,
|
||||
// that needs to be handled manually.
|
||||
var lintErrors =
|
||||
lint(normalizedStatusFile, checkForNonExisting: deleteNonExisting);
|
||||
var lintErrors = lint(
|
||||
normalizedStatusFile,
|
||||
checkForNonExisting: deleteNonExisting,
|
||||
);
|
||||
if (lintErrors.isNotEmpty) {
|
||||
print("The normalizer could not remove all linting errors. The following "
|
||||
"has to be removed manually:");
|
||||
print(
|
||||
"The normalizer could not remove all linting errors. The following "
|
||||
"has to be removed manually:",
|
||||
);
|
||||
lintErrors.forEach(print);
|
||||
}
|
||||
} on status_file.SyntaxError catch (error) {
|
||||
|
||||
@@ -36,10 +36,13 @@ import 'package:status_file/expectation.dart';
|
||||
import 'package:status_file/src/expression.dart';
|
||||
|
||||
StatusEntry? filterExpectations(
|
||||
StatusEntry entry, List<Expectation> expectationsToKeep) {
|
||||
StatusEntry entry,
|
||||
List<Expectation> expectationsToKeep,
|
||||
) {
|
||||
List<Expectation> remaining = entry.expectations
|
||||
.where(
|
||||
(Expectation expectation) => expectationsToKeep.contains(expectation))
|
||||
(Expectation expectation) => expectationsToKeep.contains(expectation),
|
||||
)
|
||||
.toList();
|
||||
return remaining.isEmpty
|
||||
? null
|
||||
@@ -128,11 +131,12 @@ String getIssueText(String comment, bool resolveState) {
|
||||
}
|
||||
|
||||
Future<StatusFile> removeNonEssentialEntries(
|
||||
StatusFile statusFile,
|
||||
List<Expectation> expectationsToKeep,
|
||||
bool removeComments,
|
||||
List<String> comments,
|
||||
bool resolveIssueState) async {
|
||||
StatusFile statusFile,
|
||||
List<Expectation> expectationsToKeep,
|
||||
bool removeComments,
|
||||
List<String> comments,
|
||||
bool resolveIssueState,
|
||||
) async {
|
||||
List<StatusSection> sections = <StatusSection>[];
|
||||
for (StatusSection section in statusFile.sections) {
|
||||
bool hasStatusEntries = false;
|
||||
@@ -160,7 +164,8 @@ Future<StatusFile> removeNonEssentialEntries(
|
||||
? "${section.condition}"
|
||||
: "";
|
||||
String issueText = getIssueText(comment, resolveIssueState);
|
||||
String statusLine = "$conditionPrefix\t$testName\t$expectations"
|
||||
String statusLine =
|
||||
"$conditionPrefix\t$testName\t$expectations"
|
||||
"\t$comment\t$issueText";
|
||||
comments.add(statusLine);
|
||||
}
|
||||
@@ -177,8 +182,11 @@ Future<StatusFile> removeNonEssentialEntries(
|
||||
var isDefaultSection = section.condition == Expression.always;
|
||||
if (hasStatusEntries ||
|
||||
(isDefaultSection && section.sectionHeaderComments.isNotEmpty)) {
|
||||
var newSection =
|
||||
StatusSection(section.condition, -1, section.sectionHeaderComments);
|
||||
var newSection = StatusSection(
|
||||
section.condition,
|
||||
-1,
|
||||
section.sectionHeaderComments,
|
||||
);
|
||||
newSection.entries.addAll(entries);
|
||||
sections.add(newSection);
|
||||
}
|
||||
@@ -191,28 +199,46 @@ Future<StatusFile> removeNonEssentialEntries(
|
||||
|
||||
ArgParser buildParser() {
|
||||
var parser = ArgParser();
|
||||
parser.addFlag("overwrite",
|
||||
abbr: 'w',
|
||||
negatable: false,
|
||||
defaultsTo: false,
|
||||
help: "Overwrite input file with output.");
|
||||
parser.addFlag("keep-crashes",
|
||||
abbr: 'c', negatable: false, defaultsTo: false);
|
||||
parser.addFlag("remove-comments",
|
||||
abbr: 'r', negatable: false, defaultsTo: false);
|
||||
parser.addFlag("resolve-issue-states",
|
||||
abbr: 'i', negatable: false, defaultsTo: false);
|
||||
parser.addFlag("help",
|
||||
abbr: "h",
|
||||
negatable: false,
|
||||
defaultsTo: false,
|
||||
help: "Show help and commands for this tool.");
|
||||
parser.addFlag(
|
||||
"overwrite",
|
||||
abbr: 'w',
|
||||
negatable: false,
|
||||
defaultsTo: false,
|
||||
help: "Overwrite input file with output.",
|
||||
);
|
||||
parser.addFlag(
|
||||
"keep-crashes",
|
||||
abbr: 'c',
|
||||
negatable: false,
|
||||
defaultsTo: false,
|
||||
);
|
||||
parser.addFlag(
|
||||
"remove-comments",
|
||||
abbr: 'r',
|
||||
negatable: false,
|
||||
defaultsTo: false,
|
||||
);
|
||||
parser.addFlag(
|
||||
"resolve-issue-states",
|
||||
abbr: 'i',
|
||||
negatable: false,
|
||||
defaultsTo: false,
|
||||
);
|
||||
parser.addFlag(
|
||||
"help",
|
||||
abbr: "h",
|
||||
negatable: false,
|
||||
defaultsTo: false,
|
||||
help: "Show help and commands for this tool.",
|
||||
);
|
||||
return parser;
|
||||
}
|
||||
|
||||
void printHelp(ArgParser parser) {
|
||||
print("Usage: dart pkg/status_file/bin/remove_non_essential_entries.dart"
|
||||
" <path>");
|
||||
print(
|
||||
"Usage: dart pkg/status_file/bin/remove_non_essential_entries.dart"
|
||||
" <path>",
|
||||
);
|
||||
print(parser.usage);
|
||||
}
|
||||
|
||||
@@ -237,7 +263,7 @@ void main(List<String> arguments) async {
|
||||
Expectation.skipByDesign,
|
||||
Expectation.skipSlow,
|
||||
Expectation.slow,
|
||||
Expectation.extraSlow
|
||||
Expectation.extraSlow,
|
||||
];
|
||||
|
||||
if (results["keep-crashes"]) {
|
||||
@@ -255,8 +281,13 @@ void main(List<String> arguments) async {
|
||||
if (resolveGithubIssueState) {
|
||||
await parseIssueFile();
|
||||
}
|
||||
statusFile = await removeNonEssentialEntries(statusFile, expectationsToKeep,
|
||||
removeComments, comments, resolveGithubIssueState);
|
||||
statusFile = await removeNonEssentialEntries(
|
||||
statusFile,
|
||||
expectationsToKeep,
|
||||
removeComments,
|
||||
comments,
|
||||
resolveGithubIssueState,
|
||||
);
|
||||
if (writeFile) {
|
||||
await File(path).writeAsString(statusFile.toString());
|
||||
print("Wrote $path.");
|
||||
|
||||
@@ -165,8 +165,10 @@ class StatusFile {
|
||||
// Comments after the last empty line belong to the next section's header.
|
||||
// The empty line is not added to the section header, because it will be
|
||||
// added to the section's entries.
|
||||
implicitSectionHeaderComments =
|
||||
implicitSectionHeaderComments.sublist(0, lastEmptyLine - 1);
|
||||
implicitSectionHeaderComments = implicitSectionHeaderComments.sublist(
|
||||
0,
|
||||
lastEmptyLine - 1,
|
||||
);
|
||||
entries.add(sectionHeaderComments[lastEmptyLine - 1]);
|
||||
sectionHeaderComments = sectionHeaderComments.sublist(lastEmptyLine);
|
||||
} else {
|
||||
@@ -176,8 +178,11 @@ class StatusFile {
|
||||
|
||||
// The current section whose rules are being parsed. Initialized to an
|
||||
// implicit section that matches everything.
|
||||
StatusSection section =
|
||||
StatusSection(Expression.always, -1, implicitSectionHeaderComments);
|
||||
StatusSection section = StatusSection(
|
||||
Expression.always,
|
||||
-1,
|
||||
implicitSectionHeaderComments,
|
||||
);
|
||||
section.entries.addAll(entries);
|
||||
sections.add(section);
|
||||
|
||||
@@ -223,11 +228,13 @@ class StatusFile {
|
||||
}
|
||||
});
|
||||
if (match[3] == null) {
|
||||
section.entries
|
||||
.add(StatusEntry(path, _lineCount, expectations, null));
|
||||
section.entries.add(
|
||||
StatusEntry(path, _lineCount, expectations, null),
|
||||
);
|
||||
} else {
|
||||
section.entries.add(
|
||||
StatusEntry(path, _lineCount, expectations, Comment(match[3]!)));
|
||||
StatusEntry(path, _lineCount, expectations, Comment(match[3]!)),
|
||||
);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -267,8 +274,13 @@ class StatusFile {
|
||||
|
||||
if (errors.isNotEmpty) {
|
||||
var s = errors.length > 1 ? "s" : "";
|
||||
throw SyntaxError(_shortPath, section.lineNumber,
|
||||
"[ ${section.condition} ]", 'Validation error$s', errors);
|
||||
throw SyntaxError(
|
||||
_shortPath,
|
||||
section.lineNumber,
|
||||
"[ ${section.condition} ]",
|
||||
'Validation error$s',
|
||||
errors,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,8 +34,10 @@ class Expectation {
|
||||
|
||||
/// The test compiled and began executing but then threw an uncaught
|
||||
/// exception or produced the wrong output.
|
||||
static final Expectation runtimeError =
|
||||
Expectation._('RuntimeError', group: fail);
|
||||
static final Expectation runtimeError = Expectation._(
|
||||
'RuntimeError',
|
||||
group: fail,
|
||||
);
|
||||
|
||||
/// The test failed with an error at compile time and did not execute any
|
||||
/// code.
|
||||
@@ -43,66 +45,90 @@ class Expectation {
|
||||
/// * For a VM test, means the VM exited with a "compile error" exit code 254.
|
||||
/// * For an analyzer test, means the analyzer reported a static error.
|
||||
/// * For a dart2js test, means dart2js reported a compile error.
|
||||
static final Expectation compileTimeError =
|
||||
Expectation._('CompileTimeError', group: fail);
|
||||
static final Expectation compileTimeError = Expectation._(
|
||||
'CompileTimeError',
|
||||
group: fail,
|
||||
);
|
||||
|
||||
/// The test was parsed by the spec_parser, and there was a syntax error.
|
||||
static final Expectation syntaxError =
|
||||
Expectation._('SyntaxError', group: fail);
|
||||
static final Expectation syntaxError = Expectation._(
|
||||
'SyntaxError',
|
||||
group: fail,
|
||||
);
|
||||
|
||||
/// The test itself contains a comment with `@runtime-error` in it,
|
||||
/// indicating it should have produced a runtime error when run. But when it
|
||||
/// was run, the test completed without error.
|
||||
static final Expectation missingRuntimeError =
|
||||
Expectation._('MissingRuntimeError', group: fail);
|
||||
static final Expectation missingRuntimeError = Expectation._(
|
||||
'MissingRuntimeError',
|
||||
group: fail,
|
||||
);
|
||||
|
||||
/// The test itself contains a comment with `@syntax-error` in it,
|
||||
/// indicating it should have produced a syntax error when compiled. But when
|
||||
/// it was compiled, no error was reported.
|
||||
static final Expectation missingSyntaxError =
|
||||
Expectation._('MissingSyntaxError', group: fail);
|
||||
static final Expectation missingSyntaxError = Expectation._(
|
||||
'MissingSyntaxError',
|
||||
group: fail,
|
||||
);
|
||||
|
||||
/// The test itself contains a comment with `@compile-error` in it,
|
||||
/// indicating it should have produced an error when compiled. But when it
|
||||
/// was compiled, no error was reported.
|
||||
static final Expectation missingCompileTimeError =
|
||||
Expectation._('MissingCompileTimeError', group: fail);
|
||||
static final Expectation missingCompileTimeError = Expectation._(
|
||||
'MissingCompileTimeError',
|
||||
group: fail,
|
||||
);
|
||||
|
||||
/// When the test is processed by analyzer, a static warning should be
|
||||
/// reported.
|
||||
static final Expectation staticWarning =
|
||||
Expectation._('StaticWarning', group: fail);
|
||||
static final Expectation staticWarning = Expectation._(
|
||||
'StaticWarning',
|
||||
group: fail,
|
||||
);
|
||||
|
||||
/// The test itself contains a comment with `@static-warning` in it,
|
||||
/// indicating analyzer should report a static warning when analyzing it, but
|
||||
/// analysis did not produce any warnings.
|
||||
static final Expectation missingStaticWarning =
|
||||
Expectation._('MissingStaticWarning', group: fail);
|
||||
static final Expectation missingStaticWarning = Expectation._(
|
||||
'MissingStaticWarning',
|
||||
group: fail,
|
||||
);
|
||||
|
||||
/// The stdout or stderr produced by the test was not valid UTF-8 and could
|
||||
/// not be decoded.
|
||||
// TODO(rnystrom): The only test that uses this expectation is the one that
|
||||
// tests that the test runner handles this expectation. Remove it?
|
||||
static final Expectation nonUtf8Error =
|
||||
Expectation._('NonUtf8Output', group: fail);
|
||||
static final Expectation nonUtf8Error = Expectation._(
|
||||
'NonUtf8Output',
|
||||
group: fail,
|
||||
);
|
||||
|
||||
/// The stdout or stderr produced by the test was too long and had to be
|
||||
/// truncated by the test runner.
|
||||
static final Expectation truncatedOutput =
|
||||
Expectation._('TruncatedOutput', group: fail);
|
||||
static final Expectation truncatedOutput = Expectation._(
|
||||
'TruncatedOutput',
|
||||
group: fail,
|
||||
);
|
||||
|
||||
/// The VM exited with the special exit code 252.
|
||||
static final Expectation dartkCrash =
|
||||
Expectation._('DartkCrash', group: crash);
|
||||
static final Expectation dartkCrash = Expectation._(
|
||||
'DartkCrash',
|
||||
group: crash,
|
||||
);
|
||||
|
||||
/// A timeout occurred in a test using the Kernel-based front end.
|
||||
static final Expectation dartkTimeout =
|
||||
Expectation._('DartkTimeout', group: timeout);
|
||||
static final Expectation dartkTimeout = Expectation._(
|
||||
'DartkTimeout',
|
||||
group: timeout,
|
||||
);
|
||||
|
||||
/// A compile error was reported on a test compiled using the Kernel-based
|
||||
/// front end.
|
||||
static final Expectation dartkCompileTimeError =
|
||||
Expectation._('DartkCompileTimeError', group: compileTimeError);
|
||||
static final Expectation dartkCompileTimeError = Expectation._(
|
||||
'DartkCompileTimeError',
|
||||
group: compileTimeError,
|
||||
);
|
||||
|
||||
// "meta expectations"
|
||||
/// A marker applied to a test to indicate that the other non-pass
|
||||
@@ -125,8 +151,11 @@ class Expectation {
|
||||
/// A marker that indicates the test takes a lot longer to complete than most
|
||||
/// tests.
|
||||
/// Tells the test runner to increase the timeout when running it.
|
||||
static final Expectation extraSlow =
|
||||
Expectation._('ExtraSlow', isMeta: true, group: skip);
|
||||
static final Expectation extraSlow = Expectation._(
|
||||
'ExtraSlow',
|
||||
isMeta: true,
|
||||
group: skip,
|
||||
);
|
||||
|
||||
/// Tells the test runner to not attempt to run the test.
|
||||
///
|
||||
@@ -141,16 +170,21 @@ class Expectation {
|
||||
///
|
||||
/// Prefer this over timeout since this avoids wasting CPU resources running
|
||||
/// a test we know won't complete.
|
||||
static final Expectation skipSlow =
|
||||
Expectation._('SkipSlow', isMeta: true, group: skip);
|
||||
static final Expectation skipSlow = Expectation._(
|
||||
'SkipSlow',
|
||||
isMeta: true,
|
||||
group: skip,
|
||||
);
|
||||
|
||||
/// Skips this test because it is not intended to be meaningful for a certain
|
||||
/// reason or on some configuration.
|
||||
///
|
||||
/// For example, tests that use dart:io are SkipByDesign on the browser since
|
||||
/// dart:io isn't supported there.
|
||||
static final Expectation skipByDesign =
|
||||
Expectation._('SkipByDesign', isMeta: true);
|
||||
static final Expectation skipByDesign = Expectation._(
|
||||
'SkipByDesign',
|
||||
isMeta: true,
|
||||
);
|
||||
|
||||
/// Can be returned by the test runner to say the result should be ignored,
|
||||
/// and assumed to meet the expectations, due to an infrastructure failure.
|
||||
@@ -160,8 +194,9 @@ class Expectation {
|
||||
|
||||
/// Used by pkg/front_end/lib/src/fasta/testing, but not used by test.dart.
|
||||
/// Included here so that we can parse .status files that contain it.
|
||||
static final Expectation verificationError =
|
||||
Expectation._('VerificationError');
|
||||
static final Expectation verificationError = Expectation._(
|
||||
'VerificationError',
|
||||
);
|
||||
|
||||
/// Maps case-insensitive names to expectations.
|
||||
static final Map<String, Expectation> _all = Map.fromIterable(<Expectation>[
|
||||
@@ -206,7 +241,7 @@ class Expectation {
|
||||
final bool isOutcome;
|
||||
|
||||
Expectation._(this._name, {this._group, bool isMeta = false})
|
||||
: isOutcome = !isMeta;
|
||||
: isOutcome = !isMeta;
|
||||
|
||||
bool canBeOutcomeOf(Expectation expectation) {
|
||||
Expectation? outcome = this;
|
||||
|
||||
@@ -24,8 +24,9 @@ final String _comparisonToken = "__";
|
||||
/// The procedure is exponential so [expression] should not be too big.
|
||||
Expression toDisjunctiveNormalForm(Expression expression) {
|
||||
var normalizedExpression = expression.normalize();
|
||||
var variableExpression =
|
||||
_comparisonExpressionsToVariableExpressions(normalizedExpression);
|
||||
var variableExpression = _comparisonExpressionsToVariableExpressions(
|
||||
normalizedExpression,
|
||||
);
|
||||
var minTerms = _satisfiableMinTerms(variableExpression);
|
||||
if (minTerms == null) {
|
||||
return T;
|
||||
@@ -101,7 +102,9 @@ LogicExpression _minimizeByComplementation(LogicExpression expression) {
|
||||
return onesInA - onesInB;
|
||||
});
|
||||
var combinedMinSets = _combineMinSets(
|
||||
clauses.map((e) => [LogicExpression.and(e)]).toList(), []);
|
||||
clauses.map((e) => [LogicExpression.and(e)]).toList(),
|
||||
[],
|
||||
);
|
||||
List<List<LogicExpression>> minCover = _findMinCover(combinedMinSets, []);
|
||||
var finalOperands = minCover.map((minSet) => _reduceMinSet(minSet)).toList();
|
||||
return LogicExpression.or(finalOperands).normalize();
|
||||
@@ -172,8 +175,10 @@ class TruthTableEnvironment extends Environment {
|
||||
/// Combines [minSets] recursively as long as possible. Prime implicants (those
|
||||
/// that cannot be reduced further) are kept track of in [primeImplicants]. When
|
||||
/// finished the function returns all combined min sets.
|
||||
List<List<LogicExpression>> _combineMinSets(List<List<LogicExpression>> minSets,
|
||||
List<List<LogicExpression>> primeImplicants) {
|
||||
List<List<LogicExpression>> _combineMinSets(
|
||||
List<List<LogicExpression>> minSets,
|
||||
List<List<LogicExpression>> primeImplicants,
|
||||
) {
|
||||
List<List<LogicExpression>> combined = <List<LogicExpression>>[];
|
||||
var addedInThisIteration = <List<LogicExpression>>{};
|
||||
for (var i = 0; i < minSets.length; i++) {
|
||||
@@ -205,8 +210,10 @@ List<List<LogicExpression>> _combineMinSets(List<List<LogicExpression>> minSets,
|
||||
/// Two min sets can be combined if they only differ by one. We reduce min sets
|
||||
/// and find their difference based on variables.
|
||||
bool _canCombine(List<LogicExpression> a, List<LogicExpression> b) {
|
||||
return _difference(_reduceMinSet(a).operands, _reduceMinSet(b).operands)
|
||||
.length ==
|
||||
return _difference(
|
||||
_reduceMinSet(a).operands,
|
||||
_reduceMinSet(b).operands,
|
||||
).length ==
|
||||
1;
|
||||
}
|
||||
|
||||
@@ -263,8 +270,9 @@ LogicExpression _reduceMinSet(List<LogicExpression> minSet) {
|
||||
/// here. The implicants that cover only a single truth assignment can be
|
||||
/// directly added to [cover].
|
||||
List<List<LogicExpression>> _findMinCover(
|
||||
List<List<LogicExpression>> primaryImplicants,
|
||||
List<List<LogicExpression>> cover) {
|
||||
List<List<LogicExpression>> primaryImplicants,
|
||||
List<List<LogicExpression>> cover,
|
||||
) {
|
||||
var minCover = primaryImplicants.toList()..addAll(cover);
|
||||
if (cover.isEmpty) {
|
||||
var allImplicants = primaryImplicants.toList();
|
||||
@@ -291,8 +299,9 @@ List<List<LogicExpression>> _findMinCover(
|
||||
for (var implicant in primaryImplicants) {
|
||||
var newCover = cover.toList()..add(implicant);
|
||||
if (!_isCover(newCover, primaryImplicants)) {
|
||||
var newPrimaryList =
|
||||
primaryImplicants.where((i) => i != implicant).toList();
|
||||
var newPrimaryList = primaryImplicants
|
||||
.where((i) => i != implicant)
|
||||
.toList();
|
||||
newCover = _findMinCover(newPrimaryList, newCover);
|
||||
}
|
||||
if (newCover.length < minCover.length) {
|
||||
@@ -345,7 +354,9 @@ T? _findFirst<T extends Expression>(T expressionToFind, List<T> expressions) {
|
||||
|
||||
/// Adds [expressionToAdd] to [expressions] if is not present.
|
||||
void _addIfNotPresent(
|
||||
Expression expressionToAdd, List<Expression> expressions) {
|
||||
Expression expressionToAdd,
|
||||
List<Expression> expressions,
|
||||
) {
|
||||
if (_findFirst(expressionToAdd, expressions) == null) {
|
||||
expressions.add(expressionToAdd);
|
||||
}
|
||||
@@ -354,7 +365,8 @@ void _addIfNotPresent(
|
||||
/// Computes all unique min sets, thereby disregarding the order for which they
|
||||
/// were combined.
|
||||
List<List<LogicExpression>> _uniqueMinSets(
|
||||
List<List<LogicExpression>> minSets) {
|
||||
List<List<LogicExpression>> minSets,
|
||||
) {
|
||||
var uniqueMinSets = <List<LogicExpression>>[];
|
||||
for (int i = 0; i < minSets.length; i++) {
|
||||
bool foundEqual = false;
|
||||
@@ -374,7 +386,9 @@ List<List<LogicExpression>> _uniqueMinSets(
|
||||
/// Measures if two min sets are equal by checking that [minSet1] c [minSet2]
|
||||
/// and minSet1.length == minSet2.length.
|
||||
bool _areMinSetsEqual(
|
||||
List<LogicExpression> minSet1, List<LogicExpression> minSet2) {
|
||||
List<LogicExpression> minSet1,
|
||||
List<LogicExpression> minSet2,
|
||||
) {
|
||||
int found = 0;
|
||||
for (var expression in minSet1) {
|
||||
if (_findFirst(expression, minSet2) != null) {
|
||||
@@ -409,18 +423,21 @@ List<Expression> _getVariables(Expression expression) {
|
||||
|
||||
Expression negate(Expression expression, {bool positive = false}) {
|
||||
if (expression is LogicExpression && expression.isOr) {
|
||||
return LogicExpression.and(expression.operands
|
||||
.map((e) => negate(e, positive: !positive))
|
||||
.toList());
|
||||
return LogicExpression.and(
|
||||
expression.operands.map((e) => negate(e, positive: !positive)).toList(),
|
||||
);
|
||||
}
|
||||
if (expression is LogicExpression && expression.isAnd) {
|
||||
return LogicExpression.or(expression.operands
|
||||
.map((e) => negate(e, positive: !positive))
|
||||
.toList());
|
||||
return LogicExpression.or(
|
||||
expression.operands.map((e) => negate(e, positive: !positive)).toList(),
|
||||
);
|
||||
}
|
||||
if (expression is ComparisonExpression) {
|
||||
return ComparisonExpression(
|
||||
expression.left, expression.right, !expression.negate);
|
||||
expression.left,
|
||||
expression.right,
|
||||
!expression.negate,
|
||||
);
|
||||
}
|
||||
if (expression is VariableExpression) {
|
||||
return VariableExpression(expression.variable, negate: !expression.negate);
|
||||
@@ -433,15 +450,17 @@ Expression negate(Expression expression, {bool positive = false}) {
|
||||
Expression _comparisonExpressionsToVariableExpressions(Expression expression) {
|
||||
if (expression is LogicExpression) {
|
||||
return LogicExpression(
|
||||
expression.op,
|
||||
expression.operands
|
||||
.map((exp) => _comparisonExpressionsToVariableExpressions(exp))
|
||||
.toList());
|
||||
expression.op,
|
||||
expression.operands
|
||||
.map((exp) => _comparisonExpressionsToVariableExpressions(exp))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
if (expression is ComparisonExpression) {
|
||||
return VariableExpression(
|
||||
Variable(expression.left.name + _comparisonToken + expression.right),
|
||||
negate: expression.negate);
|
||||
Variable(expression.left.name + _comparisonToken + expression.right),
|
||||
negate: expression.negate,
|
||||
);
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
@@ -449,19 +468,20 @@ Expression _comparisonExpressionsToVariableExpressions(Expression expression) {
|
||||
Expression _recoverComparisonExpressions(Expression expression) {
|
||||
if (expression is LogicExpression) {
|
||||
return LogicExpression(
|
||||
expression.op,
|
||||
expression.operands
|
||||
.map((exp) => _recoverComparisonExpressions(exp))
|
||||
.toList());
|
||||
expression.op,
|
||||
expression.operands
|
||||
.map((exp) => _recoverComparisonExpressions(exp))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
if (expression is VariableExpression &&
|
||||
expression.variable.name.contains(_comparisonToken)) {
|
||||
int tokenIndex = expression.variable.name.indexOf(_comparisonToken);
|
||||
return ComparisonExpression(
|
||||
Variable(expression.variable.name.substring(0, tokenIndex)),
|
||||
expression.variable.name
|
||||
.substring(tokenIndex + _comparisonToken.length),
|
||||
expression.negate);
|
||||
Variable(expression.variable.name.substring(0, tokenIndex)),
|
||||
expression.variable.name.substring(tokenIndex + _comparisonToken.length),
|
||||
expression.negate,
|
||||
);
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
@@ -105,8 +105,10 @@ class Variable {
|
||||
String lookup(Environment environment) {
|
||||
var value = environment.lookUp(name);
|
||||
if (value == null) {
|
||||
throw Exception("Could not find '$name' in environment "
|
||||
"while evaluating status file expression.");
|
||||
throw Exception(
|
||||
"Could not find '$name' in environment "
|
||||
"while evaluating status file expression.",
|
||||
);
|
||||
}
|
||||
|
||||
// Explicitly stringify all values so that things like:
|
||||
@@ -291,8 +293,9 @@ class LogicExpression extends Expression {
|
||||
|
||||
// Recurse into the operands, sort them, and remove duplicates.
|
||||
var normalized = LogicExpression(
|
||||
op, operands.map((operand) => operand.normalize()).toList())
|
||||
.operands;
|
||||
op,
|
||||
operands.map((operand) => operand.normalize()).toList(),
|
||||
).operands;
|
||||
normalized = flatten(normalized);
|
||||
var ordered = SplayTreeSet<Expression>.from(normalized).toList();
|
||||
return LogicExpression(op, ordered);
|
||||
@@ -406,12 +409,14 @@ class _ExpressionParser {
|
||||
// of the form $variable.
|
||||
if (!_scanner.match(_Token.dollar)) {
|
||||
throw FormatException(
|
||||
"Expected \$ in expression, got ${_scanner.current}");
|
||||
"Expected \$ in expression, got ${_scanner.current}",
|
||||
);
|
||||
}
|
||||
|
||||
if (!_scanner.isIdentifier) {
|
||||
throw FormatException(
|
||||
"Expected identifier in expression, got ${_scanner.current}");
|
||||
"Expected identifier in expression, got ${_scanner.current}",
|
||||
);
|
||||
}
|
||||
|
||||
var left = Variable(_scanner.current!);
|
||||
@@ -424,7 +429,8 @@ class _ExpressionParser {
|
||||
|
||||
if (!_scanner.isIdentifier) {
|
||||
throw FormatException(
|
||||
"Expected value in expression, got ${_scanner.current}");
|
||||
"Expected value in expression, got ${_scanner.current}",
|
||||
);
|
||||
}
|
||||
|
||||
var right = _scanner.advance()!;
|
||||
|
||||
@@ -114,8 +114,9 @@ class StatusFile {
|
||||
sections.add(StatusSection(Expression.always, -1));
|
||||
}
|
||||
|
||||
sections.last.entries
|
||||
.add(StatusEntry(path, _lineCount, expectations, issue));
|
||||
sections.last.entries.add(
|
||||
StatusEntry(path, _lineCount, expectations, issue),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -138,8 +139,13 @@ class StatusFile {
|
||||
|
||||
if (errors.isNotEmpty) {
|
||||
var s = errors.length > 1 ? "s" : "";
|
||||
throw SyntaxError(_shortPath, section.lineNumber,
|
||||
"[ ${section.condition} ]", 'Validation error$s', errors);
|
||||
throw SyntaxError(
|
||||
_shortPath,
|
||||
section.lineNumber,
|
||||
"[ ${section.condition} ]",
|
||||
'Validation error$s',
|
||||
errors,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,8 +229,10 @@ class StatusFile {
|
||||
}
|
||||
|
||||
for (var entry in section.entries) {
|
||||
writeText("${entry.path}: ${entry.expectations.join(', ')}",
|
||||
entry.lineNumber);
|
||||
writeText(
|
||||
"${entry.path}: ${entry.expectations.join(', ')}",
|
||||
entry.lineNumber,
|
||||
);
|
||||
}
|
||||
|
||||
needBlankLine = true;
|
||||
|
||||
@@ -25,7 +25,7 @@ bool isNonExistingEntry(Uri statusFileUri, StatusEntry entry) {
|
||||
for (var regexp in [
|
||||
_underscoreTestEnd,
|
||||
_underscoreTestDotDart,
|
||||
_underscoreTestSlash
|
||||
_underscoreTestSlash,
|
||||
]) {
|
||||
var matches = regexp.allMatches(entry.path);
|
||||
if (matches.length == 1) {
|
||||
|
||||
@@ -19,8 +19,11 @@ class LintingError {
|
||||
}
|
||||
|
||||
/// Main function to check a status file for linting errors.
|
||||
List<LintingError> lint(StatusFile file,
|
||||
{bool checkForDisjunctions = false, required bool checkForNonExisting}) {
|
||||
List<LintingError> lint(
|
||||
StatusFile file, {
|
||||
bool checkForDisjunctions = false,
|
||||
required bool checkForNonExisting,
|
||||
}) {
|
||||
var errors = <LintingError>[];
|
||||
for (var section in file.sections) {
|
||||
errors
|
||||
@@ -62,13 +65,16 @@ Iterable<LintingError> lintCommentLinesInSection(StatusSection section) {
|
||||
seenStatusEntry = seenStatusEntry || entry is StatusEntry;
|
||||
if (seenStatusEntry && entry is CommentEntry) {
|
||||
lintingErrors.add(
|
||||
LintingError(entry.lineNumber, "Comment is on a line by itself."));
|
||||
LintingError(entry.lineNumber, "Comment is on a line by itself."),
|
||||
);
|
||||
}
|
||||
}
|
||||
return lintingErrors;
|
||||
}
|
||||
return section.entries.whereType<CommentEntry>().map((entry) =>
|
||||
LintingError(entry.lineNumber, "Comment is on a line by itself."));
|
||||
return section.entries.whereType<CommentEntry>().map(
|
||||
(entry) =>
|
||||
LintingError(entry.lineNumber, "Comment is on a line by itself."),
|
||||
);
|
||||
}
|
||||
|
||||
/// Checks for disjunctions in headers. Disjunctions should be separated out.
|
||||
@@ -91,9 +97,10 @@ Iterable<LintingError> lintDisjunctionsInHeader(StatusSection section) {
|
||||
if (section.condition.toString().contains("||")) {
|
||||
return [
|
||||
LintingError(
|
||||
section.lineNumber,
|
||||
"Expression contains '||'. Please split the expression into multiple "
|
||||
"separate sections.")
|
||||
section.lineNumber,
|
||||
"Expression contains '||'. Please split the expression into multiple "
|
||||
"separate sections.",
|
||||
),
|
||||
];
|
||||
}
|
||||
return [];
|
||||
@@ -111,9 +118,10 @@ Iterable<LintingError> lintAlphabeticalOrderingOfPaths(StatusSection section) {
|
||||
if (witness != null) {
|
||||
return [
|
||||
LintingError(
|
||||
section.lineNumber,
|
||||
"Test paths are not alphabetically ordered in section. "
|
||||
"${witness.first} should come before ${witness.second}.")
|
||||
section.lineNumber,
|
||||
"Test paths are not alphabetically ordered in section. "
|
||||
"${witness.first} should come before ${witness.second}.",
|
||||
),
|
||||
];
|
||||
}
|
||||
return [];
|
||||
@@ -126,7 +134,8 @@ Iterable<LintingError> lintEntryExists(StatusFile file, StatusSection section) {
|
||||
for (var entry in section.entries.whereType<StatusEntry>()) {
|
||||
if (isNonExistingEntry(statusFileUri, entry)) {
|
||||
errors.add(
|
||||
LintingError(entry.lineNumber, "This path doesn't seem to exist."));
|
||||
LintingError(entry.lineNumber, "This path doesn't seem to exist."),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,9 +149,10 @@ Iterable<LintingError> lintNormalizedSection(StatusSection section) {
|
||||
if (nonNormalized != normalized) {
|
||||
return [
|
||||
LintingError(
|
||||
section.lineNumber,
|
||||
"Condition expression should be '$normalized' "
|
||||
"but was '$nonNormalized'.")
|
||||
section.lineNumber,
|
||||
"Condition expression should be '$normalized' "
|
||||
"but was '$nonNormalized'.",
|
||||
),
|
||||
];
|
||||
}
|
||||
return const [];
|
||||
@@ -151,8 +161,9 @@ Iterable<LintingError> lintNormalizedSection(StatusSection section) {
|
||||
/// Checks for duplicate section entries in the body of a section.
|
||||
Iterable<LintingError> lintSectionEntryDuplicates(StatusSection section) {
|
||||
var errors = <LintingError>[];
|
||||
List<StatusEntry> statusEntries =
|
||||
section.entries.whereType<StatusEntry>().toList();
|
||||
List<StatusEntry> statusEntries = section.entries
|
||||
.whereType<StatusEntry>()
|
||||
.toList();
|
||||
for (var i = 0; i < statusEntries.length; i++) {
|
||||
var entry = statusEntries[i];
|
||||
for (var j = i + 1; j < statusEntries.length; j++) {
|
||||
@@ -160,11 +171,14 @@ Iterable<LintingError> lintSectionEntryDuplicates(StatusSection section) {
|
||||
if (entry.path == otherEntry.path &&
|
||||
_findNotEqualWitness(entry.expectations, otherEntry.expectations) ==
|
||||
null) {
|
||||
errors.add(LintingError(
|
||||
errors.add(
|
||||
LintingError(
|
||||
section.lineNumber,
|
||||
"The status entry "
|
||||
"'$entry' is duplicated on lines "
|
||||
"${entry.lineNumber} and ${otherEntry.lineNumber}."));
|
||||
"${entry.lineNumber} and ${otherEntry.lineNumber}.",
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -203,11 +217,12 @@ Iterable<LintingError> lintSectionHeaderOrdering(List<StatusSection> sections) {
|
||||
if (witness != null) {
|
||||
return [
|
||||
LintingError(
|
||||
witness.second!.lineNumber,
|
||||
"Section expressions are not correctly ordered in file. "
|
||||
"'${witness.first!.condition}' on line ${witness.first!.lineNumber} "
|
||||
"should come before '${witness.second!.condition}' at line "
|
||||
"${witness.second!.lineNumber}.")
|
||||
witness.second!.lineNumber,
|
||||
"Section expressions are not correctly ordered in file. "
|
||||
"'${witness.first!.condition}' on line ${witness.first!.lineNumber} "
|
||||
"should come before '${witness.second!.condition}' at line "
|
||||
"${witness.second!.lineNumber}.",
|
||||
),
|
||||
];
|
||||
}
|
||||
return [];
|
||||
@@ -215,7 +230,8 @@ Iterable<LintingError> lintSectionHeaderOrdering(List<StatusSection> sections) {
|
||||
|
||||
/// Checks for duplicate section headers.
|
||||
Iterable<LintingError> lintSectionHeaderDuplicates(
|
||||
List<StatusSection> sections) {
|
||||
List<StatusSection> sections,
|
||||
) {
|
||||
var errors = <LintingError>[];
|
||||
var sorted = sections.toList()
|
||||
..sort((a, b) => a.condition.compareTo(b.condition));
|
||||
@@ -223,11 +239,14 @@ Iterable<LintingError> lintSectionHeaderDuplicates(
|
||||
var section = sorted[i];
|
||||
var previousSection = sorted[i - 1];
|
||||
if (section.condition.compareTo(previousSection.condition) == 0) {
|
||||
errors.add(LintingError(
|
||||
errors.add(
|
||||
LintingError(
|
||||
section.lineNumber,
|
||||
"The condition "
|
||||
"'${section.condition}' is duplicated on lines "
|
||||
"${previousSection.lineNumber} and ${section.lineNumber}."));
|
||||
"${previousSection.lineNumber} and ${section.lineNumber}.",
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
|
||||
@@ -8,8 +8,10 @@ import 'package:status_file/status_file_entries_file_checker.dart';
|
||||
import 'canonical_status_file.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
StatusFile normalizeStatusFile(StatusFile statusFile,
|
||||
{required bool deleteNonExisting}) {
|
||||
StatusFile normalizeStatusFile(
|
||||
StatusFile statusFile, {
|
||||
required bool deleteNonExisting,
|
||||
}) {
|
||||
StatusFile newStatusFile = _sortSectionsAndCombine(statusFile);
|
||||
for (var section in newStatusFile.sections) {
|
||||
if (deleteNonExisting) {
|
||||
@@ -20,11 +22,13 @@ StatusFile normalizeStatusFile(StatusFile statusFile,
|
||||
}
|
||||
|
||||
// Remove any empty sections.
|
||||
newStatusFile.sections.removeWhere((section) =>
|
||||
section.sectionHeaderComments.isEmpty &&
|
||||
(section.entries.isEmpty ||
|
||||
(section.entries.length == 1 &&
|
||||
section.entries.single is EmptyEntry)));
|
||||
newStatusFile.sections.removeWhere(
|
||||
(section) =>
|
||||
section.sectionHeaderComments.isEmpty &&
|
||||
(section.entries.isEmpty ||
|
||||
(section.entries.length == 1 &&
|
||||
section.entries.single is EmptyEntry)),
|
||||
);
|
||||
|
||||
// Remove empty line at the end of the file
|
||||
newStatusFile.sections.last.entries.removeLast();
|
||||
@@ -70,23 +74,30 @@ void _sortEntriesInSection(StatusSection section) {
|
||||
/// Ensure that there is only one empty line to end a section.
|
||||
void _oneLineBetweenSections(StatusSection section) {
|
||||
section.entries.removeWhere((entry) => entry is EmptyEntry);
|
||||
section.entries
|
||||
.add(EmptyEntry(section.lineNumber + section.entries.length + 1));
|
||||
section.entries.add(
|
||||
EmptyEntry(section.lineNumber + section.entries.length + 1),
|
||||
);
|
||||
}
|
||||
|
||||
StatusFile _sortSectionsAndCombine(StatusFile statusFile) {
|
||||
// Create the new status file to be returned.
|
||||
StatusFile oldStatusFile = StatusFile.parse(
|
||||
statusFile.path, LineSplitter.split(statusFile.toString()).toList());
|
||||
statusFile.path,
|
||||
LineSplitter.split(statusFile.toString()).toList(),
|
||||
);
|
||||
List<StatusSection> newSections = [];
|
||||
// Copy over all sections and normalize all the expressions.
|
||||
for (var section in oldStatusFile.sections) {
|
||||
if (section.condition != Expression.always) {
|
||||
if (section.isEmpty()) continue;
|
||||
|
||||
newSections.add(StatusSection(section.condition.normalize(),
|
||||
section.lineNumber, section.sectionHeaderComments)
|
||||
..entries.addAll(section.entries));
|
||||
newSections.add(
|
||||
StatusSection(
|
||||
section.condition.normalize(),
|
||||
section.lineNumber,
|
||||
section.sectionHeaderComments,
|
||||
)..entries.addAll(section.entries),
|
||||
);
|
||||
} else {
|
||||
newSections.add(section);
|
||||
}
|
||||
|
||||
@@ -41,19 +41,26 @@ StatusFile createFromString(String text) {
|
||||
return StatusFile.parse("test", text.split('\n'));
|
||||
}
|
||||
|
||||
void expectError(String text, String expectedError,
|
||||
{bool disjunctions = false}) {
|
||||
void expectError(
|
||||
String text,
|
||||
String expectedError, {
|
||||
bool disjunctions = false,
|
||||
}) {
|
||||
var statusFile = createFromString(text);
|
||||
var errors = lint(statusFile,
|
||||
checkForDisjunctions: disjunctions, checkForNonExisting: false)
|
||||
.toList();
|
||||
var errors = lint(
|
||||
statusFile,
|
||||
checkForDisjunctions: disjunctions,
|
||||
checkForNonExisting: false,
|
||||
).toList();
|
||||
Expect.equals(expectedError, errors.first.toString());
|
||||
}
|
||||
|
||||
void expectNoError(String text, {bool disjunctions = true}) {
|
||||
var errors = lint(createFromString(text),
|
||||
checkForDisjunctions: disjunctions, checkForNonExisting: false)
|
||||
.toList();
|
||||
var errors = lint(
|
||||
createFromString(text),
|
||||
checkForDisjunctions: disjunctions,
|
||||
checkForNonExisting: false,
|
||||
).toList();
|
||||
Expect.listEquals([], errors);
|
||||
}
|
||||
|
||||
@@ -102,12 +109,13 @@ vm/tests2: Timeout # this comment is also valid
|
||||
|
||||
void testCheckForDisjunctions_notAllowedDisjunction() {
|
||||
expectError(
|
||||
r"""[ $mode == debug || $mode == release ]
|
||||
r"""[ $mode == debug || $mode == release ]
|
||||
vm/tests: Skip # this comment is valid
|
||||
""",
|
||||
"Error at line 1: Expression contains '||'. Please split the expression "
|
||||
"into multiple separate sections.",
|
||||
disjunctions: true);
|
||||
"Error at line 1: Expression contains '||'. Please split the expression "
|
||||
"into multiple separate sections.",
|
||||
disjunctions: true,
|
||||
);
|
||||
}
|
||||
|
||||
void testCheckForDisjunctions_shouldBeAllowedInComments() {
|
||||
@@ -119,12 +127,13 @@ vm/tests: Skip # this comment is valid
|
||||
|
||||
void testCheckForAlphabeticalOrderingOfPaths_invalidOrdering() {
|
||||
expectError(
|
||||
r"""[ $mode == debug ]
|
||||
r"""[ $mode == debug ]
|
||||
vm/tests: Skip # this should come after a_test
|
||||
a_test: Pass
|
||||
""",
|
||||
"Error at line 1: Test paths are not alphabetically ordered in "
|
||||
"section. a_test should come before vm/tests.");
|
||||
"Error at line 1: Test paths are not alphabetically ordered in "
|
||||
"section. a_test should come before vm/tests.",
|
||||
);
|
||||
}
|
||||
|
||||
void testCheckForAlphabeticalOrderingOfPaths_okOrdering() {
|
||||
@@ -138,60 +147,66 @@ xyz_test: Skip
|
||||
|
||||
void testCheckForDuplicateEntries_hasDuplicates() {
|
||||
expectError(
|
||||
r"""[ $mode == debug ]
|
||||
r"""[ $mode == debug ]
|
||||
a_test: Pass
|
||||
a_test: Pass
|
||||
bc_test: Pass
|
||||
xyz_test: Skip
|
||||
""",
|
||||
"Error at line 1: The status entry 'a_test: Pass' is duplicated on lines "
|
||||
"2 and 3.");
|
||||
"Error at line 1: The status entry 'a_test: Pass' is duplicated on lines "
|
||||
"2 and 3.",
|
||||
);
|
||||
}
|
||||
|
||||
void testCheckForCorrectOrderingInSections_invalidRuntimeBeforeCompiler() {
|
||||
expectError(
|
||||
r"""[ $runtime == ff && $compiler == dart2js]
|
||||
r"""[ $runtime == ff && $compiler == dart2js]
|
||||
a_test: Pass
|
||||
""",
|
||||
r"Error at line 1: Condition expression should be '$compiler == dart2js "
|
||||
r"&& $runtime == ff' but was '$runtime == ff && $compiler == dart2js'.");
|
||||
r"Error at line 1: Condition expression should be '$compiler == dart2js "
|
||||
r"&& $runtime == ff' but was '$runtime == ff && $compiler == dart2js'.",
|
||||
);
|
||||
}
|
||||
|
||||
void testCheckForCorrectOrderingInSections_invalidRuntimeBeforeMode() {
|
||||
expectError(
|
||||
r"""[ $runtime == ff && $mode == debug ]
|
||||
r"""[ $runtime == ff && $mode == debug ]
|
||||
a_test: Pass
|
||||
""",
|
||||
r"Error at line 1: Condition expression should be '$mode == debug && "
|
||||
r"$runtime == ff' but was '$runtime == ff && $mode == debug'.");
|
||||
r"Error at line 1: Condition expression should be '$mode == debug && "
|
||||
r"$runtime == ff' but was '$runtime == ff && $mode == debug'.",
|
||||
);
|
||||
}
|
||||
|
||||
void testCheckForCorrectOrderingInSections_invalidSystemBeforeMode() {
|
||||
expectError(
|
||||
r"""[ $system == win && $mode == debug ]
|
||||
r"""[ $system == win && $mode == debug ]
|
||||
a_test: Pass
|
||||
""",
|
||||
r"Error at line 1: Condition expression should be '$mode == debug && "
|
||||
r"$system == win' but was '$system == win && $mode == debug'.");
|
||||
r"Error at line 1: Condition expression should be '$mode == debug && "
|
||||
r"$system == win' but was '$system == win && $mode == debug'.",
|
||||
);
|
||||
}
|
||||
|
||||
void testCheckForCorrectOrderingInSections_invalidStrongBeforeKernel() {
|
||||
expectError(
|
||||
r"""[ !$strong && !$kernel ]
|
||||
r"""[ !$strong && !$kernel ]
|
||||
a_test: Pass
|
||||
""",
|
||||
r"Error at line 1: Condition expression should be '!$kernel && !$strong' "
|
||||
r"but was '!$strong && !$kernel'.");
|
||||
r"Error at line 1: Condition expression should be '!$kernel && !$strong' "
|
||||
r"but was '!$strong && !$kernel'.",
|
||||
);
|
||||
}
|
||||
|
||||
void testCheckForCorrectOrderingInSections_invalidOrdering() {
|
||||
expectError(
|
||||
r"""[ $compiler == dart2js && $builder_tag == strong && !$browser ]
|
||||
r"""[ $compiler == dart2js && $builder_tag == strong && !$browser ]
|
||||
a_test: Pass
|
||||
""",
|
||||
r"Error at line 1: Condition expression should be '$builder_tag == "
|
||||
r"strong && $compiler == dart2js && !$browser' but was "
|
||||
r"'$compiler == dart2js && $builder_tag == strong && !$browser'.");
|
||||
r"Error at line 1: Condition expression should be '$builder_tag == "
|
||||
r"strong && $compiler == dart2js && !$browser' but was "
|
||||
r"'$compiler == dart2js && $builder_tag == strong && !$browser'.",
|
||||
);
|
||||
}
|
||||
|
||||
void testCheckForCorrectOrderingInSections_okOrdering() {
|
||||
@@ -202,33 +217,35 @@ a_test: Pass
|
||||
|
||||
void checkLintNormalizedSection_invalidAlphabeticalOrderingVariables() {
|
||||
expectError(
|
||||
r"""[ $runtime == ff ]
|
||||
r"""[ $runtime == ff ]
|
||||
a_test: Pass
|
||||
|
||||
[ $compiler == dart2js ]
|
||||
a_test: Pass
|
||||
""",
|
||||
r"Error at line 1: Section expressions are not correctly ordered in file."
|
||||
r" '$compiler == dart2js' on line 4 should come before '$runtime == ff' "
|
||||
r"at line 1.");
|
||||
r"Error at line 1: Section expressions are not correctly ordered in file."
|
||||
r" '$compiler == dart2js' on line 4 should come before '$runtime == ff' "
|
||||
r"at line 1.",
|
||||
);
|
||||
}
|
||||
|
||||
void checkLintNormalizedSection_invalidAlphabeticalOrderingVariableArguments() {
|
||||
expectError(
|
||||
r"""[ $runtime == ff ]
|
||||
r"""[ $runtime == ff ]
|
||||
a_test: Pass
|
||||
|
||||
[ $runtime == chrome ]
|
||||
a_test: Pass
|
||||
""",
|
||||
r"Error at line 1: Section expressions are not correctly ordered in file."
|
||||
r" '$runtime == chrome' on line 4 should come before '$runtime == ff' at "
|
||||
r"line 1.");
|
||||
r"Error at line 1: Section expressions are not correctly ordered in file."
|
||||
r" '$runtime == chrome' on line 4 should come before '$runtime == ff' at "
|
||||
r"line 1.",
|
||||
);
|
||||
}
|
||||
|
||||
void checkLintNormalizedSection_invalidOrderingWithNotEqual() {
|
||||
expectError(
|
||||
r"""
|
||||
r"""
|
||||
[ $ runtime == chrome ]
|
||||
a_test: Pass
|
||||
|
||||
@@ -238,14 +255,15 @@ a_test: Pass
|
||||
[ $runtime == ff ]
|
||||
a_test: Pass
|
||||
""",
|
||||
r"Error at line 4: Section expressions are not correctly ordered in file."
|
||||
r" '$runtime == ff' on line 7 should come before '$runtime != ff' at "
|
||||
r"line 4.");
|
||||
r"Error at line 4: Section expressions are not correctly ordered in file."
|
||||
r" '$runtime == ff' on line 7 should come before '$runtime != ff' at "
|
||||
r"line 4.",
|
||||
);
|
||||
}
|
||||
|
||||
void checkLintNormalizedSection_invalidOrderingWithNegation() {
|
||||
expectError(
|
||||
r"""
|
||||
r"""
|
||||
[ ! $browser ]
|
||||
a_test: Pass
|
||||
|
||||
@@ -256,8 +274,9 @@ a_test: Pass
|
||||
a_test: Pass
|
||||
|
||||
""",
|
||||
r"Error at line 4: Section expressions are not correctly ordered in file."
|
||||
r" '$checked' on line 7 should come before '!$checked' at line 4.");
|
||||
r"Error at line 4: Section expressions are not correctly ordered in file."
|
||||
r" '$checked' on line 7 should come before '!$checked' at line 4.",
|
||||
);
|
||||
}
|
||||
|
||||
void checkLintNormalizedSection_correctOrdering() {
|
||||
@@ -283,13 +302,14 @@ a_test: Pass
|
||||
|
||||
void checkLintSectionHeaderDuplicates_invalidDuplicateSections() {
|
||||
expectError(
|
||||
r"""
|
||||
r"""
|
||||
[ ! $browser ]
|
||||
a_test: Pass
|
||||
|
||||
[ ! $browser ]
|
||||
a_test: Pass
|
||||
""",
|
||||
r"Error at line 4: The condition '!$browser' is duplicated on lines 1 "
|
||||
r"and 4.");
|
||||
r"Error at line 4: The condition '!$browser' is duplicated on lines 1 "
|
||||
r"and 4.",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -26,10 +26,15 @@ void normalizeCheck() {
|
||||
for (var file in files) {
|
||||
print("------- ${file.path} -------");
|
||||
var statusFile = StatusFile.read(file.path);
|
||||
var statusFileOther = normalizeStatusFile(StatusFile.read(file.path),
|
||||
deleteNonExisting: false);
|
||||
checkSemanticallyEqual(statusFile, statusFileOther,
|
||||
warnOnDuplicateHeader: true);
|
||||
var statusFileOther = normalizeStatusFile(
|
||||
StatusFile.read(file.path),
|
||||
deleteNonExisting: false,
|
||||
);
|
||||
checkSemanticallyEqual(
|
||||
statusFile,
|
||||
statusFileOther,
|
||||
warnOnDuplicateHeader: true,
|
||||
);
|
||||
checkFileHeaderIntact(statusFile, statusFileOther);
|
||||
print("------- ${file.path} -------");
|
||||
}
|
||||
@@ -41,8 +46,11 @@ void sanityCheck() {
|
||||
print("------- ${file.path} -------");
|
||||
var statusFile = StatusFile.read(file.path);
|
||||
var statusFileOther = StatusFile.read(file.path);
|
||||
checkSemanticallyEqual(statusFile, statusFileOther,
|
||||
warnOnDuplicateHeader: true);
|
||||
checkSemanticallyEqual(
|
||||
statusFile,
|
||||
statusFileOther,
|
||||
warnOnDuplicateHeader: true,
|
||||
);
|
||||
checkFileHeaderIntact(statusFile, statusFileOther);
|
||||
print("------- ${file.path} -------");
|
||||
}
|
||||
@@ -50,29 +58,40 @@ void sanityCheck() {
|
||||
|
||||
List<FileSystemEntity> getStatusFiles() {
|
||||
var statusFiles = <FileSystemEntity>[];
|
||||
for (var entry
|
||||
in Directory.fromUri(statusFilePath).listSync(recursive: true)) {
|
||||
for (var entry in Directory.fromUri(
|
||||
statusFilePath,
|
||||
).listSync(recursive: true)) {
|
||||
statusFiles.add(entry);
|
||||
}
|
||||
return statusFiles;
|
||||
}
|
||||
|
||||
void checkSemanticallyEqual(StatusFile original, StatusFile normalized,
|
||||
{bool warnOnDuplicateHeader = false}) {
|
||||
void checkSemanticallyEqual(
|
||||
StatusFile original,
|
||||
StatusFile normalized, {
|
||||
bool warnOnDuplicateHeader = false,
|
||||
}) {
|
||||
var entriesInOriginal = countEntries(original);
|
||||
var entriesInNormalized = countEntries(normalized);
|
||||
if (entriesInOriginal != entriesInNormalized) {
|
||||
print(original);
|
||||
print("==================");
|
||||
print(normalized);
|
||||
throw Exception("The count of entries in original is "
|
||||
"$entriesInOriginal and the count of entries in normalized is "
|
||||
"$entriesInNormalized. Those two numbers are not the same.");
|
||||
throw Exception(
|
||||
"The count of entries in original is "
|
||||
"$entriesInOriginal and the count of entries in normalized is "
|
||||
"$entriesInNormalized. Those two numbers are not the same.",
|
||||
);
|
||||
}
|
||||
for (var section in original.sections) {
|
||||
section.entries.whereType<StatusEntry>().forEach((entry) =>
|
||||
findInStatusFile(normalized, entry, section.condition.normalize(),
|
||||
warnOnDuplicateHeader: warnOnDuplicateHeader));
|
||||
section.entries.whereType<StatusEntry>().forEach(
|
||||
(entry) => findInStatusFile(
|
||||
normalized,
|
||||
entry,
|
||||
section.condition.normalize(),
|
||||
warnOnDuplicateHeader: warnOnDuplicateHeader,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,21 +102,27 @@ int countEntries(StatusFile statusFile) {
|
||||
}
|
||||
|
||||
void findInStatusFile(
|
||||
StatusFile statusFile, StatusEntry entryToFind, Expression condition,
|
||||
{bool warnOnDuplicateHeader = false}) {
|
||||
StatusFile statusFile,
|
||||
StatusEntry entryToFind,
|
||||
Expression condition, {
|
||||
bool warnOnDuplicateHeader = false,
|
||||
}) {
|
||||
int foundEntryPosition = -1;
|
||||
for (var section in statusFile.sections) {
|
||||
if (section.condition.normalize().compareTo(condition) != 0) {
|
||||
continue;
|
||||
}
|
||||
var matchingEntries = section.entries
|
||||
.where((entry) =>
|
||||
entry is StatusEntry &&
|
||||
entry.path.compareTo(entryToFind.path) == 0 &&
|
||||
listEqual(entry.expectations, entryToFind.expectations))
|
||||
.where(
|
||||
(entry) =>
|
||||
entry is StatusEntry &&
|
||||
entry.path.compareTo(entryToFind.path) == 0 &&
|
||||
listEqual(entry.expectations, entryToFind.expectations),
|
||||
)
|
||||
.toList();
|
||||
if (matchingEntries.isEmpty) {
|
||||
var message = "Could not find the entry even though the section "
|
||||
var message =
|
||||
"Could not find the entry even though the section "
|
||||
"header matched on line number ${section.lineNumber}. Sections "
|
||||
"should be unique.";
|
||||
if (warnOnDuplicateHeader) {
|
||||
@@ -106,30 +131,37 @@ void findInStatusFile(
|
||||
throw Exception(message);
|
||||
}
|
||||
} else if (matchingEntries.length == 1 && foundEntryPosition >= 0) {
|
||||
throw Exception("The entry '$entryToFind' on line "
|
||||
"${entryToFind.lineNumber} in section ${section.condition} was "
|
||||
"already found in a previous section on line $foundEntryPosition.");
|
||||
throw Exception(
|
||||
"The entry '$entryToFind' on line "
|
||||
"${entryToFind.lineNumber} in section ${section.condition} was "
|
||||
"already found in a previous section on line $foundEntryPosition.",
|
||||
);
|
||||
} else if (matchingEntries.length == 1) {
|
||||
foundEntryPosition = matchingEntries[0].lineNumber;
|
||||
} else {
|
||||
throw Exception("The entry '$entryToFind' on line "
|
||||
"${entryToFind.lineNumber} in section ${section.condition} on line "
|
||||
"${section.lineNumber} had multiple matches in section.");
|
||||
throw Exception(
|
||||
"The entry '$entryToFind' on line "
|
||||
"${entryToFind.lineNumber} in section ${section.condition} on line "
|
||||
"${section.lineNumber} had multiple matches in section.",
|
||||
);
|
||||
}
|
||||
}
|
||||
if (foundEntryPosition < 0) {
|
||||
throw Exception("Could not find entry '$entryToFind' under the "
|
||||
"condition $condition in the status file.");
|
||||
throw Exception(
|
||||
"Could not find entry '$entryToFind' under the "
|
||||
"condition $condition in the status file.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void checkFileHeaderIntact(StatusFile original, StatusFile normalized) {
|
||||
var originalHeader = original.sections.first.sectionHeaderComments.toString();
|
||||
var normalizedHeader =
|
||||
normalized.sections.first.sectionHeaderComments.toString();
|
||||
var normalizedHeader = normalized.sections.first.sectionHeaderComments
|
||||
.toString();
|
||||
if (originalHeader != normalizedHeader) {
|
||||
throw Exception(
|
||||
"File headers changed.\nExpected:\n$originalHeader\n\nActual:\n$normalizedHeader");
|
||||
"File headers changed.\nExpected:\n$originalHeader\n\nActual:\n$normalizedHeader",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,9 @@ final Uri repoRoot = Platform.script.resolve("../../../");
|
||||
void main() {
|
||||
// Parse every status file in the repository.
|
||||
for (var directory in ["tests", "runtime/tests"]) {
|
||||
for (var entry in Directory.fromUri(repoRoot.resolve(directory))
|
||||
.listSync(recursive: true)) {
|
||||
for (var entry in Directory.fromUri(
|
||||
repoRoot.resolve(directory),
|
||||
).listSync(recursive: true)) {
|
||||
if (!entry.path.endsWith(".status")) continue;
|
||||
try {
|
||||
var statusFile = StatusFile.read(entry.path);
|
||||
|
||||
@@ -16,8 +16,9 @@ final Uri repoRoot = Platform.script.resolve("../../../");
|
||||
void main() {
|
||||
// Parse every status file in the repository.
|
||||
for (var directory in ["tests", "runtime/tests"]) {
|
||||
for (var entry in Directory.fromUri(repoRoot.resolve(directory))
|
||||
.listSync(recursive: true)) {
|
||||
for (var entry in Directory.fromUri(
|
||||
repoRoot.resolve(directory),
|
||||
).listSync(recursive: true)) {
|
||||
if (!entry.path.endsWith(".status")) continue;
|
||||
try {
|
||||
StatusFile.read(entry.path);
|
||||
|
||||
@@ -47,26 +47,32 @@ void testDnf() {
|
||||
|
||||
// Testing dnf and simple minimization (duplicates).
|
||||
shouldDnfTo(r'$a && ($b || $c)', r'$a && $b || $a && $c');
|
||||
shouldDnfTo(r'($a || $b) && ($c || $d)',
|
||||
r'$a && $c || $a && $d || $b && $c || $b && $d');
|
||||
shouldDnfTo(
|
||||
r'($a || $b) && ($c || $d)',
|
||||
r'$a && $c || $a && $d || $b && $c || $b && $d',
|
||||
);
|
||||
|
||||
// Testing minimizing by complementation
|
||||
// The following two examples can be found here:
|
||||
// https://en.wikipedia.org/wiki/Quine%E2%80%93McCluskey_algorithm
|
||||
shouldDnfTo(
|
||||
r"$a && !$b && !$c && !$d || $a && !$b && !$c && $d || "
|
||||
r"$a && !$b && $c && !$d || $a && !$b && $c && $d",
|
||||
r"$a && !$b");
|
||||
r"$a && !$b && !$c && !$d || $a && !$b && !$c && $d || "
|
||||
r"$a && !$b && $c && !$d || $a && !$b && $c && $d",
|
||||
r"$a && !$b",
|
||||
);
|
||||
|
||||
shouldDnfTo(
|
||||
r"!$a && $b && !$c && !$d || $a && !$b && !$c && !$d || "
|
||||
r"$a && !$b && $c && !$d || $a && !$b && $c && $d || $a && $b && !$c && !$d ||"
|
||||
r" $a && $b && $c && $d || $a && !$b && !$c && $d || $a && $b && $c && !$d",
|
||||
r"$a && !$b || $a && $c || $b && !$c && !$d");
|
||||
r"!$a && $b && !$c && !$d || $a && !$b && !$c && !$d || "
|
||||
r"$a && !$b && $c && !$d || $a && !$b && $c && $d || $a && $b && !$c && !$d ||"
|
||||
r" $a && $b && $c && $d || $a && !$b && !$c && $d || $a && $b && $c && !$d",
|
||||
r"$a && !$b || $a && $c || $b && !$c && !$d",
|
||||
);
|
||||
|
||||
// Test that an expression is converted to dnf and minified correctly.
|
||||
shouldDnfTo(r'($a || $b) && ($a || $c)', r'$a || $b && $c');
|
||||
shouldDnfTo(r'(!$a || $b) && ($a || $b)', r'$b');
|
||||
shouldDnfTo(r'($a || $b || $c) && (!$a || !$b)',
|
||||
r'$a && !$b || !$a && $b || !$b && $c');
|
||||
shouldDnfTo(
|
||||
r'($a || $b || $c) && (!$a || !$b)',
|
||||
r'$a && !$b || !$a && $b || !$b && $c',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -36,9 +36,12 @@ void main() {
|
||||
|
||||
void testExpression() {
|
||||
var expression = Expression.parse(
|
||||
r" $mode == debug && ($arch == chromium || $arch == dartc) ");
|
||||
Expect.equals(r"$mode == debug && ($arch == chromium || $arch == dartc)",
|
||||
expression.toString());
|
||||
r" $mode == debug && ($arch == chromium || $arch == dartc) ",
|
||||
);
|
||||
Expect.equals(
|
||||
r"$mode == debug && ($arch == chromium || $arch == dartc)",
|
||||
expression.toString(),
|
||||
);
|
||||
|
||||
// Test BooleanExpression.evaluate().
|
||||
var environment = TestEnvironment({"arch": "dartc", "mode": "debug"});
|
||||
@@ -62,14 +65,20 @@ void testSyntaxError() {
|
||||
}
|
||||
|
||||
void testBoolean() {
|
||||
var expression =
|
||||
Expression.parse(r" $arch == ia32 && $checked || $mode == release ");
|
||||
var expression = Expression.parse(
|
||||
r" $arch == ia32 && $checked || $mode == release ",
|
||||
);
|
||||
Expect.equals(
|
||||
r"$arch == ia32 && $checked || $mode == release", expression.toString());
|
||||
r"$arch == ia32 && $checked || $mode == release",
|
||||
expression.toString(),
|
||||
);
|
||||
|
||||
// Test BooleanExpression.evaluate().
|
||||
var environment =
|
||||
TestEnvironment({"arch": "ia32", "checked": "true", "mode": "debug"});
|
||||
var environment = TestEnvironment({
|
||||
"arch": "ia32",
|
||||
"checked": "true",
|
||||
"mode": "debug",
|
||||
});
|
||||
|
||||
Expect.isTrue(expression.evaluate(environment));
|
||||
environment["mode"] = "release";
|
||||
@@ -85,13 +94,19 @@ void testBoolean() {
|
||||
}
|
||||
|
||||
void testNotBoolean() {
|
||||
var expression =
|
||||
Expression.parse(r" $arch == ia32 && ! $checked || $mode == release ");
|
||||
var expression = Expression.parse(
|
||||
r" $arch == ia32 && ! $checked || $mode == release ",
|
||||
);
|
||||
Expect.equals(
|
||||
r"$arch == ia32 && !$checked || $mode == release", expression.toString());
|
||||
r"$arch == ia32 && !$checked || $mode == release",
|
||||
expression.toString(),
|
||||
);
|
||||
|
||||
var environment =
|
||||
TestEnvironment({"arch": "ia32", "checked": "false", "mode": "debug"});
|
||||
var environment = TestEnvironment({
|
||||
"arch": "ia32",
|
||||
"checked": "false",
|
||||
"mode": "debug",
|
||||
});
|
||||
|
||||
Expect.isTrue(expression.evaluate(environment));
|
||||
environment["mode"] = "release";
|
||||
@@ -108,16 +123,16 @@ void testNotBoolean() {
|
||||
|
||||
void testNotEqual() {
|
||||
// Test the != operator.
|
||||
var expression =
|
||||
Expression.parse(r"$compiler == dart2js && $runtime != safari");
|
||||
var expression = Expression.parse(
|
||||
r"$compiler == dart2js && $runtime != safari",
|
||||
);
|
||||
Expect.equals(
|
||||
r"$compiler == dart2js && $runtime != safari", expression.toString());
|
||||
r"$compiler == dart2js && $runtime != safari",
|
||||
expression.toString(),
|
||||
);
|
||||
|
||||
// Test BooleanExpression.evaluate().
|
||||
var environment = TestEnvironment({
|
||||
"compiler": "none",
|
||||
"runtime": "safari",
|
||||
});
|
||||
var environment = TestEnvironment({"compiler": "none", "runtime": "safari"});
|
||||
|
||||
Expect.isFalse(expression.evaluate(environment));
|
||||
environment["runtime"] = "chrome";
|
||||
@@ -163,8 +178,9 @@ void testNormalize() {
|
||||
|
||||
// Order logic clauses.
|
||||
shouldNormalizeTo(
|
||||
r"$b || ! $b || $b == b || $b && $d || $a || ! $a || $a == a || $a && $c",
|
||||
r"$a == a || $b == b || $a || !$a || $b || !$b || $a && $c || $b && $d");
|
||||
r"$b || ! $b || $b == b || $b && $d || $a || ! $a || $a == a || $a && $c",
|
||||
r"$a == a || $b == b || $a || !$a || $b || !$b || $a && $c || $b && $d",
|
||||
);
|
||||
|
||||
// Recursively normalize.
|
||||
shouldNormalizeTo(r"$c == true || $b && $a", r"$c || $a && $b");
|
||||
|
||||
Reference in New Issue
Block a user