Skip to content

Commit 82f657d

Browse files
johnniwinthercommit-bot@chromium.org
authored andcommitted
[cfe] Support error testing in annotated tests
Change-Id: I545ded4d82147f22efc80f4ed8ee833cd75a9be7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/109963 Reviewed-by: Dan Rubel <[email protected]> Commit-Queue: Johnni Winther <[email protected]>
1 parent b9828b5 commit 82f657d

File tree

7 files changed

+109
-10
lines changed

7 files changed

+109
-10
lines changed

pkg/front_end/lib/src/testing/features.dart

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'id_testing.dart';
77
/// Utility class for annotated testing representing a set of features.
88
class Features {
99
Map<String, Object> _features = {};
10+
Set<String> _unsorted = new Set<String>();
1011

1112
/// Mark the feature [key] as existing. If [value] is provided, the feature
1213
/// [key] is set to have this value.
@@ -22,6 +23,12 @@ class Features {
2223
}
2324
}
2425

26+
/// Marks list values of [key] as unsorted. This prevents the [getText]
27+
/// representation from automatically sorting the values.
28+
void markAsUnsorted(String key) {
29+
_unsorted.add(key);
30+
}
31+
2532
/// Returns `true` if feature [key] exists.
2633
bool containsKey(String key) {
2734
return _features.containsKey(key);
@@ -63,7 +70,11 @@ class Features {
6370
}
6471
sb.write(name);
6572
if (value is List<String>) {
66-
value = '[${(value..sort()).join(',')}]';
73+
if (_unsorted.contains(name)) {
74+
value = '[${value.join(',')}]';
75+
} else {
76+
value = '[${(value..sort()).join(',')}]';
77+
}
6778
}
6879
if (value != '') {
6980
sb.write('=');

pkg/front_end/lib/src/testing/id_testing_helper.dart

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,19 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'package:front_end/src/api_prototype/compiler_options.dart'
6-
show CompilerOptions;
6+
show CompilerOptions, DiagnosticMessage;
77
import 'package:front_end/src/api_prototype/experimental_flags.dart'
88
show ExperimentalFlag;
9-
import 'package:front_end/src/testing/id_extractor.dart' show DataExtractor;
9+
import 'package:front_end/src/api_prototype/terminal_color_support.dart'
10+
show printDiagnosticMessage;
11+
import 'package:front_end/src/fasta/messages.dart' show FormattedMessage;
12+
import 'package:front_end/src/fasta/severity.dart' show Severity;
1013
import 'package:kernel/ast.dart';
1114
import '../kernel_generator_impl.dart' show CompilerResult;
1215
import 'compiler_common.dart' show compileScript, toTestUri;
13-
import 'id.dart' show ActualData, ClassId, Id, IdValue, MemberId, NodeId;
16+
import 'id.dart'
17+
show ActualData, ClassId, Id, IdKind, IdValue, MemberId, NodeId;
18+
import 'id_extractor.dart' show DataExtractor;
1419
import 'id_testing.dart'
1520
show
1621
CompiledData,
@@ -74,6 +79,18 @@ abstract class DataComputer<T> {
7479
Map<Id, ActualData<T>> actualMap,
7580
{bool verbose}) {}
7681

82+
/// Returns `true` if this data computer supports tests with compile-time
83+
/// errors.
84+
///
85+
/// Unsuccessful compilation might leave the compiler in an inconsistent
86+
/// state, so this testing feature is opt-in.
87+
bool get supportsErrors => false;
88+
89+
/// Returns data corresponding to [error].
90+
T computeErrorData(
91+
CompilerResult compiler, Id id, List<FormattedMessage> errors) =>
92+
null;
93+
7794
/// Returns the [DataInterpreter] used to check the actual data with the
7895
/// expected data.
7996
DataInterpreter<T> get dataValidator;
@@ -201,16 +218,54 @@ Future<bool> runTestForConfig<T>(
201218
testData.expectedMaps[config.marker];
202219
Iterable<Id> globalIds = memberAnnotations.globalData.keys;
203220
CompilerOptions options = new CompilerOptions();
221+
List<FormattedMessage> errors = [];
222+
options.onDiagnostic = (DiagnosticMessage message) {
223+
if (message is FormattedMessage && message.severity == Severity.error) {
224+
errors.add(message);
225+
}
226+
printDiagnosticMessage(message, print);
227+
};
204228
options.debugDump = printCode;
205229
options.experimentalFlags.addAll(config.experimentalFlags);
206230
CompilerResult compilerResult = await compileScript(
207231
testData.memorySourceFiles,
208232
options: options,
209233
retainDataForTesting: true);
234+
210235
Component component = compilerResult.component;
211236
Map<Uri, Map<Id, ActualData<T>>> actualMaps = <Uri, Map<Id, ActualData<T>>>{};
212237
Map<Id, ActualData<T>> globalData = <Id, ActualData<T>>{};
213238

239+
Map<Id, ActualData<T>> actualMapForUri(Uri uri) {
240+
return actualMaps.putIfAbsent(uri, () => <Id, ActualData<T>>{});
241+
}
242+
243+
if (errors.isNotEmpty) {
244+
if (!dataComputer.supportsErrors) {
245+
onFailure("Compilation with compile-time errors not supported for this "
246+
"testing setup.");
247+
}
248+
249+
Map<Uri, Map<int, List<FormattedMessage>>> errorMap = {};
250+
for (FormattedMessage error in errors) {
251+
Map<int, List<FormattedMessage>> map =
252+
errorMap.putIfAbsent(error.uri, () => {});
253+
List<FormattedMessage> list = map.putIfAbsent(error.charOffset, () => []);
254+
list.add(error);
255+
}
256+
257+
errorMap.forEach((Uri uri, Map<int, List<FormattedMessage>> map) {
258+
map.forEach((int offset, List<DiagnosticMessage> list) {
259+
NodeId id = new NodeId(offset, IdKind.error);
260+
T data = dataComputer.computeErrorData(compilerResult, id, list);
261+
if (data != null) {
262+
Map<Id, ActualData<T>> actualMap = actualMapForUri(uri);
263+
actualMap[id] = new ActualData<T>(id, data, uri, offset, list);
264+
}
265+
});
266+
});
267+
}
268+
214269
Map<Id, ActualData<T>> actualMapFor(TreeNode node) {
215270
Uri uri = node is Library ? node.fileUri : node.location.file;
216271
return actualMaps.putIfAbsent(uri, () => <Id, ActualData<T>>{});

pkg/front_end/test/extensions/extensions_test.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,14 @@ class ExtensionsDataExtractor extends CfeDataExtractor<Features> {
141141
for (FormalParameterBuilder parameter in memberBuilder.formals) {
142142
features.addElement(Tags.builderParameters, parameter.name);
143143
}
144+
features.markAsUnsorted(Tags.builderParameters);
144145
}
145146
if (memberBuilder.typeVariables != null) {
146147
for (TypeVariableBuilder typeVariable in memberBuilder.typeVariables) {
147148
features.addElement(Tags.builderTypeParameters,
148149
typeVariableBuilderToText(typeVariable));
149150
}
151+
features.markAsUnsorted(Tags.builderTypeParameters);
150152
}
151153
}
152154
features[Tags.memberName] = getMemberName(member);
@@ -155,10 +157,12 @@ class ExtensionsDataExtractor extends CfeDataExtractor<Features> {
155157
in member.function.positionalParameters) {
156158
features.addElement(Tags.memberParameters, parameter.name);
157159
}
160+
features.markAsUnsorted(Tags.memberParameters);
158161
for (TypeParameter typeParameter in member.function.typeParameters) {
159162
features.addElement(
160163
Tags.memberTypeParameters, typeParameterToText(typeParameter));
161164
}
165+
features.markAsUnsorted(Tags.memberTypeParameters);
162166
}
163167
return features;
164168
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/*cfe.library: file=main.dart*/
6+
7+
/*cfe.member: main:main*/
8+
main() {
9+
// ignore: undefined_function
10+
/*error: Method not found: 'foo'.*/ foo();
11+
}

pkg/front_end/test/id_testing/id_testing_test.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'dart:io' show Directory, Platform;
6+
import 'package:front_end/src/fasta/messages.dart' show FormattedMessage;
67
import 'package:front_end/src/testing/id.dart' show ActualData, Id;
78
import 'package:front_end/src/testing/id_testing.dart'
89
show DataInterpreter, StringDataInterpreter, runTests;
@@ -60,6 +61,14 @@ class IdTestingDataComputer extends DataComputer<String> {
6061
.computeForLibrary(library);
6162
}
6263

64+
@override
65+
bool get supportsErrors => true;
66+
67+
String computeErrorData(
68+
CompilerResult compiler, Id id, List<FormattedMessage> errors) {
69+
return errors.map((m) => m.message).join(',');
70+
}
71+
6372
@override
6473
DataInterpreter<String> get dataValidator => const StringDataInterpreter();
6574
}

tests/compiler/dart2js/equivalence/id_equivalence_helper.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ Future<CompiledData<T>> computeData<T>(Uri entryPoint,
158158
if (skipFailedCompilations) return null;
159159
Expect.isTrue(
160160
dataComputer.supportsErrors,
161-
"Compilation with compile-time error not supported for this "
161+
"Compilation with compile-time errors not supported for this "
162162
"testing setup.");
163163
}
164164
if (printCode) {
@@ -175,10 +175,6 @@ Future<CompiledData<T>> computeData<T>(Uri entryPoint,
175175
return actualMaps.putIfAbsent(uri, () => <Id, ActualData<T>>{});
176176
}
177177

178-
dynamic closedWorld = testFrontend
179-
? compiler.resolutionWorldBuilder.closedWorldForTesting
180-
: compiler.backendClosedWorldForTesting;
181-
ElementEnvironment elementEnvironment = closedWorld?.elementEnvironment;
182178
Map<Uri, Map<int, List<CollectedMessage>>> errors = {};
183179
for (CollectedMessage error in diagnosticCollector.errors) {
184180
Map<int, List<CollectedMessage>> map =
@@ -200,9 +196,13 @@ Future<CompiledData<T>> computeData<T>(Uri entryPoint,
200196

201197
if (!result.isSuccess) {
202198
return new Dart2jsCompiledData<T>(
203-
compiler, elementEnvironment, entryPoint, actualMaps, globalData);
199+
compiler, null, entryPoint, actualMaps, globalData);
204200
}
205201

202+
dynamic closedWorld = testFrontend
203+
? compiler.resolutionWorldBuilder.closedWorldForTesting
204+
: compiler.backendClosedWorldForTesting;
205+
ElementEnvironment elementEnvironment = closedWorld?.elementEnvironment;
206206
CommonElements commonElements = closedWorld.commonElements;
207207

208208
Map<Id, ActualData<T>> actualMapFor(Entity entity) {

tests/compiler/dart2js/equivalence/id_testing_test.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@ class IdTestingDataComputer extends DataComputer<String> {
6464
.computeForLibrary(node);
6565
}
6666

67+
@override
68+
bool get supportsErrors => true;
69+
70+
@override
71+
String computeErrorData(
72+
Compiler compiler, Id id, List<CollectedMessage> errors) {
73+
return errors.map((c) => c.message.message).join(',');
74+
}
75+
6776
@override
6877
bool get testFrontend => true;
6978

0 commit comments

Comments
 (0)