Start building incremental test suite

Change-Id: I38e969e494c671982ec2cba96d2657a836dd0d49
Reviewed-on: https://dart-review.googlesource.com/24122
Commit-Queue: Peter von der Ahé <ahe@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Peter von der Ahé 2017-12-01 13:03:16 +00:00 committed by commit-bot@chromium.org
parent a6d422957d
commit 632bba54b9
5 changed files with 281 additions and 0 deletions

View file

@ -0,0 +1,77 @@
// 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.
library fasta.test.incremental_expectations;
import "dart:convert" show JsonDecoder, JsonEncoder;
const JsonEncoder json = const JsonEncoder.withIndent(" ");
List<IncrementalExpectation> extractJsonExpectations(String source) {
return new List<IncrementalExpectation>.from(source
.split("\n")
.where((l) => l.startsWith("<<<< ") || l.startsWith("==== "))
.map((l) => l.substring("<<<< ".length))
.map((l) => new IncrementalExpectation.fromJson(l)));
}
class IncrementalExpectation {
final List<String> messages;
final bool commitChangesShouldFail;
final bool hasCompileTimeError;
const IncrementalExpectation(this.messages,
{this.commitChangesShouldFail: false, this.hasCompileTimeError: false});
factory IncrementalExpectation.fromJson(String json) {
var data = const JsonDecoder().convert(json);
if (data is String) {
data = <String>[data];
}
if (data is List) {
return new IncrementalExpectation(data);
}
return new IncrementalExpectation(extractMessages(data),
commitChangesShouldFail: extractCommitChangesShouldFail(data),
hasCompileTimeError: extractHasCompileTimeError(data));
}
toJson() {
if (!commitChangesShouldFail && !hasCompileTimeError) {
return messages.length == 1 ? messages.first : messages;
}
Map<String, dynamic> result = <String, dynamic>{
"messages": messages,
};
if (commitChangesShouldFail) {
result['commitChangesShouldFail'] = 1;
}
if (hasCompileTimeError) {
result['hasCompileTimeError'] = 1;
}
return result;
}
String toString() {
return """
IncrementalExpectation(
${json.convert(messages)},
commitChangesShouldFail: $commitChangesShouldFail,
hasCompileTimeError: $hasCompileTimeError)""";
}
static List<String> extractMessages(Map<String, dynamic> json) {
return new List<String>.from(json["messages"]);
}
static bool extractCommitChangesShouldFail(Map<String, dynamic> json) {
return json["commitChangesShouldFail"] == 1;
}
static bool extractHasCompileTimeError(Map<String, dynamic> json) {
return json["hasCompileTimeError"] == 1;
}
}

View file

@ -0,0 +1,87 @@
// 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.md file.
library fasta.test.incremental_source_files;
/// Expand a file with diffs in common merge conflict format into a [List] that
/// can be passed to [expandUpdates].
///
/// For example:
/// first
/// <<<<
/// v1
/// ====
/// v2
/// ====
/// v3
/// >>>>
/// last
///
/// Would be expanded to something equivalent to:
///
/// ["first\n", ["v1\n", "v2\n", "v3\n"], "last\n"]
List expandDiff(String text) {
List result = [new StringBuffer()];
bool inDiff = false;
for (String line in splitLines(text)) {
if (inDiff) {
if (line.startsWith("====")) {
result.last.add(new StringBuffer());
} else if (line.startsWith(">>>>")) {
inDiff = false;
result.add(new StringBuffer());
} else {
result.last.last.write(line);
}
} else if (line.startsWith("<<<<")) {
inDiff = true;
result.add(<StringBuffer>[new StringBuffer()]);
} else {
result.last.write(line);
}
}
return result;
}
/// Returns [updates] expanded to full compilation units/source files.
///
/// [updates] is a convenient way to write updates/patches to a single source
/// file without repeating common parts.
///
/// For example:
/// ["head ", ["v1", "v2"], " tail"]
/// expands to:
/// ["head v1 tail", "head v2 tail"]
List<String> expandUpdates(List updates) {
int outputCount = updates.firstWhere((e) => e is Iterable).length;
List<StringBuffer> result = new List<StringBuffer>(outputCount);
for (int i = 0; i < outputCount; i++) {
result[i] = new StringBuffer();
}
for (var chunk in updates) {
if (chunk is Iterable) {
int segmentCount = 0;
for (var segment in chunk) {
result[segmentCount++].write(segment);
}
if (segmentCount != outputCount) {
throw new ArgumentError("Expected ${outputCount} segments, "
"but found ${segmentCount} in $chunk");
}
} else {
for (StringBuffer buffer in result) {
buffer.write(chunk);
}
}
}
return result.map((e) => '$e').toList();
}
/// Split [text] into lines preserving trailing newlines (unlike
/// String.split("\n"). Also, if [text] is empty, return an empty list (unlike
/// String.split("\n")).
List<String> splitLines(String text) {
return text.split(new RegExp('^', multiLine: true));
}

View file

@ -0,0 +1,99 @@
// 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.md file.
library fasta.test.incremental_test;
import "dart:async" show Future;
import "dart:convert" show JsonEncoder;
import "dart:io" show File;
import "package:testing/testing.dart"
show Chain, ChainContext, Result, Step, TestDescription, runMe;
import "package:yaml/yaml.dart" show YamlMap, loadYamlNode;
import "incremental_expectations.dart"
show IncrementalExpectation, extractJsonExpectations;
import "incremental_source_files.dart" show expandDiff, expandUpdates;
const JsonEncoder json = const JsonEncoder.withIndent(" ");
class Context extends ChainContext {
final List<Step> steps = const <Step>[
const ReadTest(),
];
const Context();
}
class ReadTest extends Step<TestDescription, TestCase, Context> {
const ReadTest();
String get name => "read test";
Future<Result<TestCase>> run(
TestDescription description, Context context) async {
Uri uri = description.uri;
String contents = await new File.fromUri(uri).readAsString();
Map<String, List<String>> sources = <String, List<String>>{};
List<IncrementalExpectation> expectations;
bool firstPatch = true;
YamlMap map = loadYamlNode(contents, sourceUrl: uri);
map.forEach((_fileName, _contents) {
String fileName = _fileName; // Strong mode hurray!
String contents = _contents; // Strong mode hurray!
if (fileName.endsWith(".patch")) {
if (firstPatch) {
expectations = extractJsonExpectations(contents);
}
sources[fileName] = expandUpdates(expandDiff(contents));
firstPatch = false;
} else {
sources[fileName] = <String>[contents];
}
});
return new TestCase(sources, expectations).validate(this);
}
}
class TestCase {
final Map<String, List<String>> sources;
final List<IncrementalExpectation> expectations;
const TestCase(this.sources, this.expectations);
String toString() {
return "TestCase(${json.convert(sources)}, ${json.convert(expectations)})";
}
Result<TestCase> validate(Step<dynamic, TestCase, ChainContext> step) {
print(this);
if (sources == null) {
return step.fail(this, "No sources.");
}
if (expectations == null || expectations.isEmpty) {
return step.fail(this, "No expectations.");
}
for (String name in sources.keys) {
List<String> versions = sources[name];
if (versions.length != 1 && versions.length != expectations.length) {
return step.fail(
this,
"Found ${versions.length} versions of $name,"
" but expected 1 or ${expectations.length}.");
}
}
return step.pass(this);
}
}
Future<Context> createContext(Chain suite, Map<String, String> environment) {
return new Future<Context>.value(const Context());
}
main([List<String> arguments = const []]) =>
runMe(arguments, createContext, "../../testing.json");

View file

@ -0,0 +1,5 @@
# 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.md file.
# Status file for the test suite ../test/fasta/incremental_test.dart.

View file

@ -123,6 +123,19 @@
]
},
{
"name": "incremental",
"kind": "Chain",
"source": "test/fasta/incremental_test.dart",
"path": "testcases/",
"status": "testcases/incremental.status",
"pattern": [
"\\.incremental\\.yaml$"
],
"exclude": [
]
},
{
"name": "sdk",
"kind": "Chain",