blob: 954b1c52d8f3ccbf653b2fe1ff42e87b16328674 [file] [log] [blame]
// Copyright (c) 2017, 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.
/// [Configuration] holds information about a specific configuration, parsed
/// from a JSON result.log file.
/// TODO(mkroghj): Needs a shared package to keep information in sync with
/// test.py.
class Configuration {
final String mode;
final String arch;
final String compiler;
final String runtime;
final bool checked;
final bool strong;
final bool hostChecked;
final bool minified;
final bool csp;
final bool fasta;
final String system;
final List<String> vmOptions;
final bool useSdk;
final String builderTag;
final bool fastStartup;
final int timeout;
final bool dart2JsWithKernel;
final bool dart2JsOldFrontend;
final bool enableAsserts;
final bool hotReload;
final bool hotReloadRollback;
final bool noPreviewDart2;
final List<String> selectors;
Configuration(
this.mode,
this.arch,
this.compiler,
this.runtime,
this.checked,
this.strong,
this.hostChecked,
this.minified,
this.csp,
this.fasta,
this.system,
this.vmOptions,
this.useSdk,
this.builderTag,
this.fastStartup,
this.timeout,
this.dart2JsWithKernel,
this.dart2JsOldFrontend,
this.enableAsserts,
this.hotReload,
this.hotReloadRollback,
this.noPreviewDart2,
this.selectors);
static Configuration getFromJson(dynamic json) {
var isStrong = !(json["no_preview_dart_2"] ?? false);
return new Configuration(
json["mode"],
json["arch"],
json["compiler"],
json["runtime"],
json["checked"],
isStrong,
json["host_checked"],
json["minified"],
json["csp"],
json["fasta"],
json["system"],
json["vm_options"].cast<String>(),
json["use_sdk"],
json["builder_tag"],
json["fast_startup"],
json["timeout"],
json["dart2js_with_kernel"] ?? false,
json["dart2js_old_frontend"] ?? false,
json["enable_asserts"] ?? false,
json["hot_reload"] ?? false,
json["hot_reload_rollback"] ?? false,
!isStrong,
json["selectors"].cast<String>() ?? <String>[]);
}
/// Returns the arguments needed for running test.py with the arguments
/// corresponding to this configuration.
List<String> toArgs({includeSelectors: true}) {
var args = [
_stringToArg("mode", mode),
_stringToArg("arch", arch),
_stringToArg("compiler", compiler),
_stringToArg("runtime", runtime),
_boolToArg("checked", checked),
_boolToArg("strong", strong),
_boolToArg("host-checked", hostChecked),
_boolToArg("minified", minified),
_boolToArg("csp", csp),
// We don't create a --fasta arg because fasta is synthesized variable.
_stringToArg("system", system),
_listToArg("vm-options", vmOptions),
_boolToArg("use-sdk", useSdk),
_stringToArg("builder-tag", builderTag),
_boolToArg("fast-startup", fastStartup),
_boolToArg("dart2js-with-kernel", dart2JsWithKernel),
_boolToArg("dart2js-old-frontend", dart2JsOldFrontend),
_boolToArg("enable-asserts", enableAsserts),
_boolToArg("hot-reload", hotReload),
_boolToArg("hot-reload-rollback", hotReloadRollback),
_boolToArg("no-preview-dart-2", noPreviewDart2)
].where((x) => x != null).toList();
if (includeSelectors && selectors != null && selectors.length > 0) {
args.addAll(selectors);
}
return args;
}
String toCsvString() {
return "$mode;$arch;$compiler;$runtime;$checked;$strong;$hostChecked;"
"$minified;$csp;$fasta;$system;$vmOptions;$useSdk;$builderTag;$fastStartup;"
"$dart2JsWithKernel;$dart2JsOldFrontend;$enableAsserts;$hotReload;"
"$hotReloadRollback;$noPreviewDart2;$selectors";
}
String _stringToArg(String name, String value) {
if (value == null || value.length == 0) {
return null;
}
return "--$name=$value";
}
String _boolToArg(String name, bool value) {
return value == true ? "--$name" : null;
}
String _listToArg(String name, List<String> strings) {
if (strings == null || strings.length == 0) {
return null;
}
return "--$name=${strings.join(',')}";
}
}
/// [Result] contains the [result] of executing a single test on a specified
/// [configuration].
class Result {
// Not final since we have to update it when combining test results.
String configuration;
final String name;
final String result;
final bool flaky;
final bool negative;
final List<String> testExpectations;
final List<Command> commands;
Result(this.configuration, this.name, this.result, this.flaky, this.negative,
this.testExpectations, this.commands);
static Result getFromJson(dynamic json) {
var commands =
json["commands"].map<Command>((x) => Command.getFromJson(x)).toList();
var testExpectations = json["test_expectation"].cast<String>();
return new Result(json["configuration"], json["name"], json["result"],
json["flaky"], json["negative"], testExpectations, commands);
}
}
/// [Command] used to get a result for a test.
class Command {
final String name;
final int exitCode;
final bool timeout;
final int duration;
Command(this.name, this.exitCode, this.timeout, this.duration);
static Command getFromJson(dynamic json) {
return new Command(
json["name"], json["exitCode"], json["timeout"], json["duration"]);
}
}
/// [TestResult] is a collection of configurations and test results,
/// corresponding to the information found in a result.log json file.
class TestResult {
final dynamic jsonObject;
TestResult() : jsonObject = null {
_configurations = {};
_results = [];
}
TestResult.fromJson(this.jsonObject);
Map<String, Configuration> _configurations;
Map<String, Configuration> get configurations {
if (_configurations != null) {
return _configurations;
}
_configurations = {};
this.jsonObject["configurations"].forEach((key, value) {
_configurations[key] = Configuration.getFromJson(value);
});
return _configurations;
}
List<Result> _results;
List<Result> get results {
return _results ??= this
.jsonObject["results"]
.map<Result>((x) => Result.getFromJson(x))
.toList();
}
/// Combines multiple test-results into a single test-result, potentially by
/// giving new names to later configurations.
void combineWith(Iterable<TestResult> results) {
results.forEach((tr) {
Map<String, String> translatedConfigurations = {};
for (var confKey in tr.configurations.keys) {
var newKey = _findExistingConfiguration(
tr.configurations[confKey], this.configurations);
newKey ??= "conf${this.configurations.length + 1}";
translatedConfigurations[confKey] = newKey;
this.configurations[newKey] = tr.configurations[confKey];
}
this.results.addAll(tr.results.map((res) {
res.configuration = translatedConfigurations[res.configuration];
return res;
}));
});
}
/// Finds an existing configuration based on the arguments passed to test.py.
String _findExistingConfiguration(Configuration configurationToFind,
Map<String, Configuration> existingConfigurations) {
String thisArgs = configurationToFind.toArgs().join();
for (var confKey in existingConfigurations.keys) {
String confArgs = existingConfigurations[confKey].toArgs().join();
if (confArgs == thisArgs) {
return confKey;
}
}
return null;
}
}