Version 2.15.0-162.0.dev
Merge commit 'b846a20e2637d54757251f7f42bc9ad423632cea' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 036e134..e61db67 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -388,6 +388,17 @@
`dart pub get/upgrade/downgrade/add/remove` that will result in the `example/`
folder dependencies to be updated after operating in the current directory.
+## 2.14.3 - 2021-09-30
+
+This is a patch release that fixes:
+
+- a code completion performance regression [flutter/flutter-intellij#5761][].
+- debug information emitted by the Dart VM [#47289][].
+
+[flutter/flutter-intellij#5761]:
+ https://github.com/flutter/flutter-intellij/issues/5761
+[#47289]: https://github.com/dart-lang/sdk/issues/47289
+
## 2.14.2 - 2021-09-16
This is a patch release that fixes:
diff --git a/pkg/test_runner/bin/compare_results.dart b/pkg/test_runner/bin/compare_results.dart
new file mode 100755
index 0000000..39eb614
--- /dev/null
+++ b/pkg/test_runner/bin/compare_results.dart
@@ -0,0 +1,331 @@
+#!/usr/bin/env dart
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// 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.
+
+// Compare the old and new test results and list tests that pass the filters.
+// The output contains additional details in the verbose mode. There is a human
+// readable mode that explains the results and how they changed.
+
+// @dart = 2.9
+
+import 'dart:collection';
+import 'dart:io';
+
+import 'package:args/args.dart';
+import 'package:test_runner/bot_results.dart';
+
+class Event {
+ final Result before;
+ final Result after;
+
+ Event(this.before, this.after);
+
+ bool get isNew => before == null;
+ bool get isNewPassing => before == null && after.matches;
+ bool get isNewFailing => before == null && !after.matches;
+ bool get changed => !unchanged;
+ bool get unchanged =>
+ before != null &&
+ before.outcome == after.outcome &&
+ before.expectation == after.expectation;
+ bool get remainedPassing => before.matches && after.matches;
+ bool get remainedFailing => !before.matches && !after.matches;
+ bool get flaked => after.flaked;
+ bool get fixed => !before.matches && after.matches;
+ bool get broke => before.matches && !after.matches;
+
+ String get description {
+ if (isNewPassing) {
+ return "is new and succeeded";
+ } else if (isNewFailing) {
+ return "is new and failed";
+ } else if (remainedPassing) {
+ return "succeeded again";
+ } else if (remainedFailing) {
+ return "failed again";
+ } else if (fixed) {
+ return "was fixed";
+ } else if (broke) {
+ return "broke";
+ } else {
+ throw Exception("Unreachable");
+ }
+ }
+}
+
+class Options {
+ Options(this._options);
+
+ final ArgResults _options;
+
+ bool get changed => _options["changed"] as bool;
+ int get count => _options["count"] is String
+ ? int.parse(_options["count"] as String)
+ : null;
+ String get flakinessData => _options["flakiness-data"] as String;
+ bool get help => _options["help"] as bool;
+ bool get human => _options["human"] as bool;
+ bool get judgement => _options["judgement"] as bool;
+ String get logs => _options["logs"] as String;
+ bool get logsOnly => _options["logs-only"] as bool;
+ Iterable<String> get statusFilter => ["passing", "flaky", "failing"]
+ .where((option) => _options[option] as bool);
+ bool get unchanged => _options["unchanged"] as bool;
+ bool get verbose => _options["verbose"] as bool;
+ List<String> get rest => _options.rest;
+}
+
+bool firstSection = true;
+
+bool search(
+ String description,
+ String searchForStatus,
+ List<Event> events,
+ Options options,
+ Map<String, Map<String, dynamic>> logs,
+ List<String> logSection) {
+ var judgement = false;
+ var beganSection = false;
+ var count = options.count;
+ final configurations =
+ events.map((event) => event.after.configuration).toSet();
+ for (final event in events) {
+ if (searchForStatus == "passing" &&
+ (event.after.flaked || !event.after.matches)) {
+ continue;
+ }
+ if (searchForStatus == "flaky" && !event.after.flaked) {
+ continue;
+ }
+ if (searchForStatus == "failing" &&
+ (event.after.flaked || event.after.matches)) {
+ continue;
+ }
+ if (options.unchanged && !event.unchanged) continue;
+ if (options.changed && !event.changed) continue;
+ if (!beganSection) {
+ if (options.human && !options.logsOnly) {
+ if (!firstSection) {
+ print("");
+ }
+ firstSection = false;
+ print("$description\n");
+ }
+ }
+ beganSection = true;
+ final before = event.before;
+ final after = event.after;
+ // The --flaky option is used to get a list of tests to deflake within a
+ // single named configuration. Therefore we can't right now always emit
+ // the configuration name, so only do it if there's more than one in the
+ // results being compared (that won't happen during deflaking.
+ final name =
+ configurations.length == 1 ? event.after.name : event.after.key;
+ if (!after.flaked && !after.matches) {
+ judgement = true;
+ }
+ if (count != null) {
+ if (--count <= 0) {
+ if (options.human) {
+ print("(And more)");
+ }
+ break;
+ }
+ }
+ String output;
+ if (options.verbose) {
+ if (options.human) {
+ final expect = after.matches ? "" : ", expected ${after.expectation}";
+ if (before == null || before.outcome == after.outcome) {
+ output = "$name ${event.description} "
+ "(${event.after.outcome}$expect)";
+ } else {
+ output = "$name ${event.description} "
+ "(${event.before?.outcome} -> ${event.after.outcome}$expect)";
+ }
+ } else {
+ output = "$name ${before?.outcome} ${after.outcome} "
+ "${before?.expectation} ${after.expectation} "
+ "${before?.matches} ${after.matches} "
+ "${before?.flaked} ${after.flaked}";
+ }
+ } else {
+ output = name;
+ }
+ final log = logs[event.after.key];
+ final bar = '=' * (output.length + 2);
+ if (log != null) {
+ logSection?.add("\n\n/$bar\\\n| $output |\n\\$bar/\n\n${log["log"]}");
+ }
+ if (!options.logsOnly) {
+ print(output);
+ }
+ }
+
+ return judgement;
+}
+
+main(List<String> args) async {
+ final parser = ArgParser();
+ parser.addFlag("changed",
+ abbr: 'c',
+ negatable: false,
+ help: "Show only tests that changed results.");
+ parser.addOption("count",
+ abbr: "C",
+ help: "Upper limit on how many tests to report in each section");
+ parser.addFlag("failing",
+ abbr: 'f', negatable: false, help: "Show failing tests.");
+ parser.addOption("flakiness-data",
+ abbr: 'd', help: "File containing flakiness data");
+ parser.addFlag("judgement",
+ abbr: 'j',
+ negatable: false,
+ help: "Exit 1 only if any of the filtered results failed.");
+ parser.addFlag("flaky",
+ abbr: 'F', negatable: false, help: "Show flaky tests.");
+ parser.addFlag("help", help: "Show the program usage.", negatable: false);
+ parser.addFlag("human", abbr: "h", negatable: false);
+ parser.addFlag("passing",
+ abbr: 'p', negatable: false, help: "Show passing tests.");
+ parser.addFlag("unchanged",
+ abbr: 'u',
+ negatable: false,
+ help: "Show only tests with unchanged results.");
+ parser.addFlag("verbose",
+ abbr: "v",
+ help: "Show the old and new result for each test",
+ negatable: false);
+ parser.addOption("logs",
+ abbr: "l", help: "Path to file holding logs of failing and flaky tests.");
+ parser.addFlag("logs-only",
+ help: "Only print logs of failing and flaky tests, no other output",
+ negatable: false);
+
+ final options = Options(parser.parse(args));
+ if (options.help) {
+ print("""
+Usage: compare_results.dart [OPTION]... BEFORE AFTER
+Compare the old and new test results and list tests that pass the filters.
+All tests are listed if no filters are given.
+
+The options are as follows:
+
+${parser.usage}""");
+ return;
+ }
+
+ if (options.changed && options.unchanged) {
+ print(
+ "error: The options --changed and --unchanged are mutually exclusive");
+ exitCode = 2;
+ return;
+ }
+
+ final parameters = options.rest;
+ if (parameters.length != 2) {
+ print("error: Expected two parameters "
+ "(results before, results after)");
+ exitCode = 2;
+ return;
+ }
+
+ // Load the input and the flakiness data if specified.
+ final before = await loadResultsMap(parameters[0]);
+ final after = await loadResultsMap(parameters[1]);
+ final logs = options.logs == null
+ ? <String, Map<String, dynamic>>{}
+ : await loadResultsMap(options.logs);
+ final flakinessData = options.flakinessData != null
+ ? await loadResultsMap(options.flakinessData)
+ : <String, Map<String, dynamic>>{};
+
+ // The names of every test that has a data point in the new data set.
+ final names = SplayTreeSet<String>.from(after.keys);
+
+ final events = <Event>[];
+ for (final name in names) {
+ final mapBefore = before[name];
+ final mapAfter = after[name];
+ final resultBefore = mapBefore != null
+ ? Result.fromMap(mapBefore, flakinessData[name])
+ : null;
+ final resultAfter = Result.fromMap(mapAfter, flakinessData[name]);
+ final event = Event(resultBefore, resultAfter);
+ events.add(event);
+ }
+
+ final filterDescriptions = {
+ "passing": {
+ "unchanged": "continued to pass",
+ "changed": "began passing",
+ null: "passed",
+ },
+ "flaky": {
+ "unchanged": "are known to flake but didn't",
+ "changed": "flaked",
+ null: "are known to flake",
+ },
+ "failing": {
+ "unchanged": "continued to fail",
+ "changed": "began failing",
+ null: "failed",
+ },
+ "any": {
+ "unchanged": "had the same result",
+ "changed": "changed result",
+ null: "ran",
+ },
+ };
+
+ final searchForStatuses = options.statusFilter;
+
+ // Report tests matching the filters.
+ final logSection = <String>[];
+ var judgement = false;
+ for (final searchForStatus
+ in searchForStatuses.isNotEmpty ? searchForStatuses : <String>["any"]) {
+ final searchForChanged = options.unchanged
+ ? "unchanged"
+ : options.changed
+ ? "changed"
+ : null;
+ final aboutStatus = filterDescriptions[searchForStatus][searchForChanged];
+ final sectionHeader = "The following tests $aboutStatus:";
+ final logSectionArg =
+ searchForStatus == "failing" || searchForStatus == "flaky"
+ ? logSection
+ : null;
+ final possibleJudgement = search(
+ sectionHeader, searchForStatus, events, options, logs, logSectionArg);
+ if (searchForStatus == null || searchForStatus == "failing") {
+ judgement = possibleJudgement;
+ }
+ }
+
+ if (logSection.isNotEmpty) {
+ print(logSection.join());
+ }
+ // Exit 1 only if --judgement and any test failed.
+ if (options.judgement) {
+ if (options.human && !options.logsOnly && !firstSection) {
+ print("");
+ }
+ var oldNew = options.unchanged
+ ? "old "
+ : options.changed
+ ? "new "
+ : "";
+ if (judgement) {
+ if (options.human && !options.logsOnly) {
+ print("There were ${oldNew}test failures.");
+ }
+ exitCode = 1;
+ } else {
+ if (options.human && !options.logsOnly) {
+ print("No ${oldNew}test failures were found.");
+ }
+ }
+ }
+}
diff --git a/pkg/test_runner/test/compare_results/compare_results_test.dart b/pkg/test_runner/test/compare_results/compare_results_test.dart
new file mode 100644
index 0000000..414ac6f
--- /dev/null
+++ b/pkg/test_runner/test/compare_results/compare_results_test.dart
@@ -0,0 +1,205 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// 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.
+
+// Test that compare results works as expected.
+
+// @dart = 2.9
+
+import 'package:expect/expect.dart';
+import 'package:test_runner/bot_results.dart';
+import '../../bin/compare_results.dart';
+
+void main() {
+ testEvent();
+}
+
+void testEvent() {
+ var passingResult = _result();
+ var sameResult = Event(passingResult, passingResult);
+ _expectEvent(sameResult,
+ isNew: false,
+ isNewPassing: false,
+ isNewFailing: false,
+ changed: false,
+ unchanged: true,
+ remainedPassing: true,
+ remainedFailing: false,
+ fixed: false,
+ broke: false,
+ description: 'succeeded again');
+
+ var failingResult =
+ _result(matches: false, outcome: 'Fail', previousOutcome: 'Fail');
+ var sameFailingResult = Event(failingResult, failingResult);
+ _expectEvent(sameFailingResult,
+ isNew: false,
+ isNewPassing: false,
+ isNewFailing: false,
+ changed: false,
+ unchanged: true,
+ remainedPassing: false,
+ remainedFailing: true,
+ fixed: false,
+ broke: false,
+ description: 'failed again');
+
+ var regression = Event(passingResult, failingResult);
+ _expectEvent(regression,
+ isNew: false,
+ isNewPassing: false,
+ isNewFailing: false,
+ changed: true,
+ unchanged: false,
+ remainedPassing: false,
+ remainedFailing: false,
+ fixed: false,
+ broke: true,
+ description: 'broke');
+
+ var differentFailingResult =
+ _result(matches: false, outcome: 'Error', previousOutcome: 'Error');
+ var differentFailure = Event(failingResult, differentFailingResult);
+ _expectEvent(differentFailure,
+ isNew: false,
+ isNewPassing: false,
+ isNewFailing: false,
+ changed: true,
+ unchanged: false,
+ remainedPassing: false,
+ remainedFailing: true,
+ fixed: false,
+ broke: false,
+ description: 'failed again');
+
+ var fixed = Event(failingResult, passingResult);
+ _expectEvent(fixed,
+ isNew: false,
+ isNewPassing: false,
+ isNewFailing: false,
+ changed: true,
+ unchanged: false,
+ remainedPassing: false,
+ remainedFailing: false,
+ fixed: true,
+ broke: false,
+ description: 'was fixed');
+
+ var newPass = Event(null, passingResult);
+ _expectEvent(newPass,
+ isNew: true,
+ isNewPassing: true,
+ isNewFailing: false,
+ changed: true,
+ unchanged: false,
+ description: 'is new and succeeded');
+
+ var newFailure = Event(null, failingResult);
+ _expectEvent(newFailure,
+ isNew: true,
+ isNewPassing: false,
+ isNewFailing: true,
+ changed: true,
+ unchanged: false,
+ description: 'is new and failed');
+
+ var flakyResult = _result(flaked: true);
+ var becameFlaky = Event(passingResult, flakyResult);
+ _expectEvent(becameFlaky, flaked: true);
+
+ var noLongerFlaky = Event(flakyResult, passingResult);
+ _expectEvent(noLongerFlaky, flaked: false);
+
+ var failingExpectedToFailResult = _result(
+ matches: true,
+ outcome: 'Fail',
+ previousOutcome: 'Fail',
+ expectation: 'Fail');
+ var nowMeetingExpectation = Event(failingResult, failingExpectedToFailResult);
+ _expectEvent(nowMeetingExpectation,
+ changed: true,
+ unchanged: false,
+ remainedPassing: false,
+ remainedFailing: false,
+ broke: false,
+ description: 'was fixed');
+
+ var passingExpectedToFailResult = _result(
+ matches: false,
+ outcome: 'Pass',
+ previousOutcome: 'Pass',
+ expectation: 'Fail');
+ var noLongerMeetingExpectation =
+ Event(passingResult, passingExpectedToFailResult);
+ _expectEvent(noLongerMeetingExpectation,
+ changed: true,
+ unchanged: false,
+ remainedPassing: false,
+ remainedFailing: false,
+ broke: true,
+ description: 'broke');
+}
+
+void _expectEvent(Event actual,
+ {bool isNew,
+ bool isNewPassing,
+ bool isNewFailing,
+ bool changed,
+ bool unchanged,
+ bool remainedPassing,
+ bool remainedFailing,
+ bool flaked,
+ bool fixed,
+ bool broke,
+ String description}) {
+ if (isNew != null) {
+ Expect.equals(isNew, actual.isNew, 'isNew mismatch');
+ }
+ if (isNewPassing != null) {
+ Expect.equals(isNewPassing, actual.isNewPassing, 'isNewPassing mismatch');
+ }
+ if (isNewFailing != null) {
+ Expect.equals(isNewFailing, actual.isNewFailing, 'isNewFailing mismatch');
+ }
+ if (changed != null) {
+ Expect.equals(changed, actual.changed, 'changed mismatch');
+ }
+ if (unchanged != null) {
+ Expect.equals(unchanged, actual.unchanged, 'unchanged mismatch');
+ }
+ if (remainedPassing != null) {
+ Expect.equals(
+ remainedPassing, actual.remainedPassing, 'remainedPassing mismatch');
+ }
+ if (remainedFailing != null) {
+ Expect.equals(
+ remainedFailing, actual.remainedFailing, 'remainedFailing mismatch');
+ }
+ if (flaked != null) {
+ Expect.equals(flaked, actual.flaked, 'flaked mismatch');
+ }
+ if (fixed != null) {
+ Expect.equals(fixed, actual.fixed, 'fixed mismatch');
+ }
+ if (broke != null) {
+ Expect.equals(broke, actual.broke, 'broke mismatch');
+ }
+ if (description != null) {
+ Expect.equals(description, actual.description, 'description mismatch');
+ }
+}
+
+Result _result(
+ {String configuration = 'config',
+ String expectation = 'Pass',
+ bool matches = true,
+ String name = 'test1',
+ String outcome = 'Pass',
+ bool changed = false,
+ String commitHash = 'abcdabcd',
+ bool flaked = false,
+ bool isFlaky = false,
+ String previousOutcome = 'Pass'}) {
+ return Result(configuration, name, outcome, expectation, matches, changed,
+ commitHash, isFlaky, previousOutcome, flaked);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 23ba9f3..25ca929 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 15
PATCH 0
-PRERELEASE 161
+PRERELEASE 162
PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/compare_results.dart b/tools/bots/compare_results.dart
index 9edd0f8..bcf9abe52 100755
--- a/tools/bots/compare_results.dart
+++ b/tools/bots/compare_results.dart
@@ -9,299 +9,8 @@
// @dart = 2.9
-import 'dart:collection';
-import 'dart:io';
+import '../../pkg/test_runner/bin/compare_results.dart' as compareResults;
-import 'package:args/args.dart';
-import 'package:test_runner/bot_results.dart';
-
-class Event {
- final Result before;
- final Result after;
-
- Event(this.before, this.after);
-
- bool get isNew => before == null;
- bool get isNewPassing => before == null && after.matches;
- bool get isNewFailing => before == null && !after.matches;
- bool get changed => !unchanged;
- bool get unchanged => before != null && before.outcome == after.outcome;
- bool get remainedPassing => before.matches && after.matches;
- bool get remainedFailing => !before.matches && !after.matches;
- bool get flaked => after.flaked;
- bool get fixed => !before.matches && after.matches;
- bool get broke => before.matches && !after.matches;
-
- String get description {
- if (isNewPassing) {
- return "is new and succeeded";
- } else if (isNewFailing) {
- return "is new and failed";
- } else if (remainedPassing) {
- return "succeeded again";
- } else if (remainedFailing) {
- return "failed again";
- } else if (fixed) {
- return "was fixed";
- } else if (broke) {
- return "broke";
- } else {
- throw new Exception("Unreachable");
- }
- }
-}
-
-bool firstSection = true;
-
-bool search(
- String description,
- String searchForStatus,
- List<Event> events,
- ArgResults options,
- Map<String, Map<String, dynamic>> logs,
- List<String> logSection) {
- bool judgement = false;
- bool beganSection = false;
- int count = options["count"] != null ? int.parse(options["count"]) : null;
- final configurations =
- events.map((event) => event.after.configuration).toSet();
- for (final event in events) {
- if (searchForStatus == "passing" &&
- (event.after.flaked || !event.after.matches)) {
- continue;
- }
- if (searchForStatus == "flaky" && !event.after.flaked) {
- continue;
- }
- if (searchForStatus == "failing" &&
- (event.after.flaked || event.after.matches)) {
- continue;
- }
- if (options["unchanged"] && !event.unchanged) continue;
- if (options["changed"] && !event.changed) continue;
- if (!beganSection) {
- if (options["human"] && !options["logs-only"]) {
- if (!firstSection) {
- print("");
- }
- firstSection = false;
- print("$description\n");
- }
- }
- beganSection = true;
- final before = event.before;
- final after = event.after;
- // The --flaky option is used to get a list of tests to deflake within a
- // single named configuration. Therefore we can't right now always emit
- // the configuration name, so only do it if there's more than one in the
- // results being compared (that won't happen during deflaking.
- final name =
- configurations.length == 1 ? event.after.name : event.after.key;
- if (!after.flaked && !after.matches) {
- judgement = true;
- }
- if (count != null) {
- if (--count <= 0) {
- if (options["human"]) {
- print("(And more)");
- }
- break;
- }
- }
- String output;
- if (options["verbose"]) {
- if (options["human"]) {
- String expect = after.matches ? "" : ", expected ${after.expectation}";
- if (before == null || before.outcome == after.outcome) {
- output = "$name ${event.description} "
- "(${event.after.outcome}${expect})";
- } else {
- output = "$name ${event.description} "
- "(${event.before?.outcome} -> ${event.after.outcome}${expect})";
- }
- } else {
- output = "$name ${before?.outcome} ${after.outcome} "
- "${before?.expectation} ${after.expectation} "
- "${before?.matches} ${after.matches} "
- "${before?.flaked} ${after.flaked}";
- }
- } else {
- output = name;
- }
- final log = logs[event.after.key];
- final bar = '=' * (output.length + 2);
- if (log != null) {
- logSection?.add("\n\n/$bar\\\n| $output |\n\\$bar/\n\n${log["log"]}");
- }
- if (!options["logs-only"]) {
- print(output);
- }
- }
-
- return judgement;
-}
-
-main(List<String> args) async {
- final parser = new ArgParser();
- parser.addFlag("changed",
- abbr: 'c',
- negatable: false,
- help: "Show only tests that changed results.");
- parser.addOption("count",
- abbr: "C",
- help: "Upper limit on how many tests to report in each section");
- parser.addFlag("failing",
- abbr: 'f', negatable: false, help: "Show failing tests.");
- parser.addOption("flakiness-data",
- abbr: 'd', help: "File containing flakiness data");
- parser.addFlag("judgement",
- abbr: 'j',
- negatable: false,
- help: "Exit 1 only if any of the filtered results failed.");
- parser.addFlag("flaky",
- abbr: 'F', negatable: false, help: "Show flaky tests.");
- parser.addFlag("help", help: "Show the program usage.", negatable: false);
- parser.addFlag("human", abbr: "h", negatable: false);
- parser.addFlag("passing",
- abbr: 'p', negatable: false, help: "Show passing tests.");
- parser.addFlag("unchanged",
- abbr: 'u',
- negatable: false,
- help: "Show only tests with unchanged results.");
- parser.addFlag("verbose",
- abbr: "v",
- help: "Show the old and new result for each test",
- negatable: false);
- parser.addOption("logs",
- abbr: "l", help: "Path to file holding logs of failing and flaky tests.");
- parser.addFlag("logs-only",
- help: "Only print logs of failing and flaky tests, no other output",
- negatable: false);
-
- final options = parser.parse(args);
- if (options["help"]) {
- print("""
-Usage: compare_results.dart [OPTION]... BEFORE AFTER
-Compare the old and new test results and list tests that pass the filters.
-All tests are listed if no filters are given.
-
-The options are as follows:
-
-${parser.usage}""");
- return;
- }
-
- if (options["changed"] && options["unchanged"]) {
- print(
- "error: The options --changed and --unchanged are mutually exclusive");
- exitCode = 2;
- return;
- }
-
- final parameters = options.rest;
- if (parameters.length != 2) {
- print("error: Expected two parameters "
- "(results before, results after)");
- exitCode = 2;
- return;
- }
-
- // Load the input and the flakiness data if specified.
- final before = await loadResultsMap(parameters[0]);
- final after = await loadResultsMap(parameters[1]);
- final logs = options['logs'] == null
- ? <String, Map<String, dynamic>>{}
- : await loadResultsMap(options['logs']);
- final flakinessData = options["flakiness-data"] != null
- ? await loadResultsMap(options["flakiness-data"])
- : <String, Map<String, dynamic>>{};
-
- // The names of every test that has a data point in the new data set.
- final names = new SplayTreeSet<String>.from(after.keys);
-
- final events = <Event>[];
- for (final name in names) {
- final mapBefore = before[name];
- final mapAfter = after[name];
- final resultBefore = mapBefore != null
- ? new Result.fromMap(mapBefore, flakinessData[name])
- : null;
- final resultAfter = new Result.fromMap(mapAfter, flakinessData[name]);
- final event = new Event(resultBefore, resultAfter);
- events.add(event);
- }
-
- final filterDescriptions = {
- "passing": {
- "unchanged": "continued to pass",
- "changed": "began passing",
- null: "passed",
- },
- "flaky": {
- "unchanged": "are known to flake but didn't",
- "changed": "flaked",
- null: "are known to flake",
- },
- "failing": {
- "unchanged": "continued to fail",
- "changed": "began failing",
- null: "failed",
- },
- "any": {
- "unchanged": "had the same result",
- "changed": "changed result",
- null: "ran",
- },
- };
-
- final searchForStatuses =
- ["passing", "flaky", "failing"].where((option) => options[option]);
-
- // Report tests matching the filters.
- final logSection = <String>[];
- bool judgement = false;
- for (final searchForStatus
- in searchForStatuses.isNotEmpty ? searchForStatuses : <String>["any"]) {
- final searchForChanged = options["unchanged"]
- ? "unchanged"
- : options["changed"]
- ? "changed"
- : null;
- final aboutStatus = filterDescriptions[searchForStatus][searchForChanged];
- final sectionHeader = "The following tests $aboutStatus:";
- final logSectionArg =
- searchForStatus == "failing" || searchForStatus == "flaky"
- ? logSection
- : null;
- bool possibleJudgement = search(
- sectionHeader, searchForStatus, events, options, logs, logSectionArg);
- if ((searchForStatus == null || searchForStatus == "failing")) {
- judgement = possibleJudgement;
- }
- }
-
- if (logSection.isNotEmpty) {
- print(logSection.join());
- }
- // Exit 1 only if --judgement and any test failed.
- if (options["judgement"]) {
- if (options["human"] && !options["logs-only"] && !firstSection) {
- print("");
- }
- String oldNew = options["unchanged"]
- ? "old "
- : options["changed"]
- ? "new "
- : "";
- if (judgement) {
- if (options["human"] && !options["logs-only"]) {
- print("There were ${oldNew}test failures.");
- }
- exitCode = 1;
- } else {
- if (options["human"] && !options["logs-only"]) {
- print("No ${oldNew}test failures were found.");
- }
- }
- }
+main(List<String> args) {
+ compareResults.main(args);
}
diff --git a/tools/bots/extend_results.dart b/tools/bots/extend_results.dart
index 7dc7743..4ab1d2c 100644
--- a/tools/bots/extend_results.dart
+++ b/tools/bots/extend_results.dart
@@ -56,9 +56,12 @@
}
if (priorResult != null) {
result['previous_result'] = priorResult['result'];
+ result['changed'] = !(result['result'] == result['previous_result'] &&
+ result['flaky'] == result['previous_flaky'] &&
+ result['expected'] == priorResult['expected']);
+ } else {
+ result['changed'] = true;
}
- result['changed'] = (result['result'] != result['previous_result'] ||
- result['flaky'] != result['previous_flaky']);
}
final sink = new File(newResultsPath).openWrite();
final sorted = results.keys.toList()..sort();