mirror of
https://github.com/dart-lang/sdk
synced 2024-09-20 02:39:27 +00:00
Refactor serialization test files.
BUG= R=sigmund@google.com Review URL: https://codereview.chromium.org/1870133002 .
This commit is contained in:
parent
4080c1b410
commit
1f6c0dd14b
|
@ -14,192 +14,7 @@ import 'package:compiler/src/compiler.dart';
|
|||
import 'package:compiler/src/filenames.dart';
|
||||
import 'memory_compiler.dart';
|
||||
import 'serialization_helper.dart';
|
||||
|
||||
const List<Test> TESTS = const <Test>[
|
||||
const Test(const {
|
||||
'main.dart': 'main() {}'
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': 'main() => print("Hello World");'
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': 'main() => print("Hello World", 0);'
|
||||
},
|
||||
expectedWarningCount: 1,
|
||||
expectedInfoCount: 1),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
main() {
|
||||
String text = "Hello World";
|
||||
print('$text');
|
||||
}'''
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
main() {
|
||||
String text = "Hello World";
|
||||
print('$text', text);
|
||||
}'''
|
||||
},
|
||||
expectedWarningCount: 1,
|
||||
expectedInfoCount: 1),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
main(List<String> arguments) {
|
||||
print(arguments);
|
||||
}'''
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
main(List<String> arguments) {
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
print(arguments[i]);
|
||||
}
|
||||
}'''
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
main(List<String> arguments) {
|
||||
for (String argument in arguments) {
|
||||
print(argument);
|
||||
}
|
||||
}'''
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
class Class {}
|
||||
main() {
|
||||
print(new Class());
|
||||
}'''
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
class Class implements Function {}
|
||||
main() {
|
||||
print(new Class());
|
||||
}'''
|
||||
},
|
||||
expectedWarningCount: 1),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
class Class implements Function {
|
||||
call() {}
|
||||
}
|
||||
main() {
|
||||
print(new Class()());
|
||||
}'''
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
class Class implements Comparable<Class> {
|
||||
int compareTo(Class other) => 0;
|
||||
}
|
||||
main() {
|
||||
print(new Class());
|
||||
}'''
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
class Class implements Comparable<Class, Class> {
|
||||
int compareTo(other) => 0;
|
||||
}
|
||||
main() {
|
||||
print(new Class());
|
||||
}'''
|
||||
},
|
||||
expectedWarningCount: 1),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
class Class implements Comparable<Class> {
|
||||
int compareTo(String other) => 0;
|
||||
}
|
||||
main() {
|
||||
print(new Class().compareTo(null));
|
||||
}'''
|
||||
},
|
||||
expectedWarningCount: 1,
|
||||
expectedInfoCount: 1),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
class Class implements Comparable {
|
||||
bool compareTo(a, b) => true;
|
||||
}
|
||||
main() {
|
||||
print(new Class().compareTo(null, null));
|
||||
}'''
|
||||
},
|
||||
expectedWarningCount: 1,
|
||||
expectedInfoCount: 1),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
import 'dart:math';
|
||||
|
||||
class MyRandom implements Random {
|
||||
int nextInt(int max) {
|
||||
return max.length;
|
||||
}
|
||||
bool nextBool() => true;
|
||||
double nextDouble() => 0.0;
|
||||
}
|
||||
main() {
|
||||
new MyRandom().nextInt(0);
|
||||
}'''
|
||||
},
|
||||
expectedWarningCount: 1,
|
||||
expectedInfoCount: 0),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
import 'dart:math';
|
||||
|
||||
class MyRandom implements Random {
|
||||
int nextInt(int max) {
|
||||
return max.length;
|
||||
}
|
||||
bool nextBool() => true;
|
||||
double nextDouble() => 0.0;
|
||||
}
|
||||
main() {
|
||||
new MyRandom();
|
||||
}'''
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
import 'dart:math';
|
||||
|
||||
class MyRandom implements Random {
|
||||
int nextInt(int max) {
|
||||
return max.length;
|
||||
}
|
||||
bool nextBool() => true;
|
||||
double nextDouble() => 0.0;
|
||||
}
|
||||
main() {
|
||||
// Invocation of `MyRandom.nextInt` is only detected knowing the actual
|
||||
// implementation class for `List` and the world impact of its `shuffle`
|
||||
// method.
|
||||
[].shuffle(new MyRandom());
|
||||
}'''
|
||||
},
|
||||
expectedWarningCount: 1,
|
||||
expectedInfoCount: 0),
|
||||
];
|
||||
import 'serialization_test_data.dart';
|
||||
|
||||
main(List<String> arguments) {
|
||||
asyncTest(() async {
|
||||
|
@ -217,20 +32,6 @@ main(List<String> arguments) {
|
|||
});
|
||||
}
|
||||
|
||||
class Test {
|
||||
final Map sourceFiles;
|
||||
final int expectedErrorCount;
|
||||
final int expectedWarningCount;
|
||||
final int expectedHintCount;
|
||||
final int expectedInfoCount;
|
||||
|
||||
const Test(this.sourceFiles, {
|
||||
this.expectedErrorCount: 0,
|
||||
this.expectedWarningCount: 0,
|
||||
this.expectedHintCount: 0,
|
||||
this.expectedInfoCount: 0});
|
||||
}
|
||||
|
||||
Future analyze(String serializedData, Uri entryPoint, Test test) async {
|
||||
DiagnosticCollector diagnosticCollector = new DiagnosticCollector();
|
||||
await runCompiler(
|
||||
|
|
|
@ -14,7 +14,7 @@ import 'package:compiler/src/filenames.dart';
|
|||
import 'package:compiler/src/serialization/equivalence.dart';
|
||||
import 'memory_compiler.dart';
|
||||
import 'serialization_helper.dart';
|
||||
import 'serialization_test.dart';
|
||||
import 'serialization_test_helper.dart';
|
||||
|
||||
main(List<String> arguments) {
|
||||
asyncTest(() async {
|
||||
|
@ -47,65 +47,5 @@ Future check(
|
|||
deserialize(compilerDeserialized, serializedData);
|
||||
await compilerDeserialized.run(entryPoint);
|
||||
|
||||
checkResolutionImpacts(compilerNormal, compilerDeserialized, verbose: true);
|
||||
checkAllImpacts(compilerNormal, compilerDeserialized, verbose: true);
|
||||
}
|
||||
|
||||
/// Check equivalence of [impact1] and [impact2].
|
||||
void checkImpacts(Element element1, Element element2,
|
||||
ResolutionImpact impact1, ResolutionImpact impact2,
|
||||
{bool verbose: false}) {
|
||||
if (impact1 == null || impact2 == null) return;
|
||||
|
||||
if (verbose) {
|
||||
print('Checking impacts for $element1 vs $element2');
|
||||
}
|
||||
|
||||
testResolutionImpactEquivalence(impact1, impact2, const CheckStrategy());
|
||||
}
|
||||
|
||||
|
||||
/// Check equivalence between all resolution impacts common to [compiler1] and
|
||||
/// [compiler2].
|
||||
void checkResolutionImpacts(
|
||||
Compiler compiler1,
|
||||
Compiler compiler2,
|
||||
{bool verbose: false}) {
|
||||
|
||||
void checkMembers(Element member1, Element member2) {
|
||||
if (member1.isClass && member2.isClass) {
|
||||
ClassElement class1 = member1;
|
||||
ClassElement class2 = member2;
|
||||
class1.forEachLocalMember((m1) {
|
||||
checkMembers(m1, class2.lookupLocalMember(m1.name));
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!compiler1.resolution.hasResolutionImpact(member1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (member2 == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (areElementsEquivalent(member1, member2)) {
|
||||
checkImpacts(
|
||||
member1, member2,
|
||||
compiler1.resolution.getResolutionImpact(member1),
|
||||
compiler2.serialization.deserializer.getResolutionImpact(member2),
|
||||
verbose: verbose);
|
||||
}
|
||||
}
|
||||
|
||||
for (LibraryElement library1 in compiler1.libraryLoader.libraries) {
|
||||
LibraryElement library2 =
|
||||
compiler2.libraryLoader.lookupLibrary(library1.canonicalUri);
|
||||
if (library2 != null) {
|
||||
library1.forEachLocalMember((Element member1) {
|
||||
checkMembers(member1, library2.localLookup(member1.name));
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,9 +27,8 @@ import 'package:compiler/src/universe/class_set.dart';
|
|||
import 'package:compiler/src/universe/use.dart';
|
||||
import 'memory_compiler.dart';
|
||||
import 'serialization_helper.dart';
|
||||
import 'serialization_analysis_test.dart';
|
||||
import 'serialization_impact_test.dart';
|
||||
import 'serialization_test.dart';
|
||||
import 'serialization_test_data.dart';
|
||||
import 'serialization_test_helper.dart';
|
||||
|
||||
main(List<String> arguments) {
|
||||
String filename;
|
||||
|
@ -109,7 +108,7 @@ Future check(
|
|||
await compilerDeserialized.run(entryPoint);
|
||||
compilerDeserialized.world.populate();
|
||||
|
||||
checkResolutionImpacts(
|
||||
checkAllImpacts(
|
||||
compilerNormal, compilerDeserialized,
|
||||
verbose: verbose);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import 'package:compiler/src/serialization/element_serialization.dart';
|
|||
import 'package:compiler/src/serialization/equivalence.dart';
|
||||
import 'package:compiler/src/serialization/json_serializer.dart';
|
||||
import 'package:compiler/src/serialization/serialization.dart';
|
||||
import 'serialization_test_helper.dart';
|
||||
|
||||
main(List<String> arguments) {
|
||||
// Ensure that we can print out constant expressions.
|
||||
|
@ -132,262 +133,6 @@ checkElementProperties(
|
|||
const ElementPropertyEquivalence().visit(element1, element2);
|
||||
}
|
||||
|
||||
/// Check the equivalence of the two lists of elements, [list1] and [list2].
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
checkElementLists(Object object1, Object object2, String property,
|
||||
Iterable<Element> list1, Iterable<Element> list2) {
|
||||
checkListEquivalence(object1, object2, property,
|
||||
list1, list2, checkElementProperties);
|
||||
}
|
||||
|
||||
/// Check equivalence of the two lists, [list1] and [list2], using
|
||||
/// [checkEquivalence] to check the pair-wise equivalence.
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkListEquivalence(
|
||||
Object object1, Object object2, String property,
|
||||
Iterable list1, Iterable list2,
|
||||
void checkEquivalence(o1, o2, property, a, b)) {
|
||||
for (int i = 0; i < list1.length && i < list2.length; i++) {
|
||||
checkEquivalence(
|
||||
object1, object2, property,
|
||||
list1.elementAt(i), list2.elementAt(i));
|
||||
}
|
||||
for (int i = list1.length; i < list2.length; i++) {
|
||||
throw
|
||||
'Missing equivalent for element '
|
||||
'#$i ${list2.elementAt(i)} in `${property}` on $object2.\n'
|
||||
'`${property}` on $object1:\n ${list1.join('\n ')}\n'
|
||||
'`${property}` on $object2:\n ${list2.join('\n ')}';
|
||||
}
|
||||
for (int i = list2.length; i < list1.length; i++) {
|
||||
throw
|
||||
'Missing equivalent for element '
|
||||
'#$i ${list1.elementAt(i)} in `${property}` on $object1.\n'
|
||||
'`${property}` on $object1:\n ${list1.join('\n ')}\n'
|
||||
'`${property}` on $object2:\n ${list2.join('\n ')}';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Computes the set difference between [set1] and [set2] using
|
||||
/// [elementEquivalence] to determine element equivalence.
|
||||
///
|
||||
/// Elements both in [set1] and [set2] are added to [common], elements in [set1]
|
||||
/// but not in [set2] are added to [unfound], and the set of elements in [set2]
|
||||
/// but not in [set1] are returned.
|
||||
Set computeSetDifference(
|
||||
Iterable set1,
|
||||
Iterable set2,
|
||||
List common,
|
||||
List unfound,
|
||||
[bool sameElement(a, b) = equality]) {
|
||||
// TODO(johnniwinther): Avoid the quadratic cost here. Some ideas:
|
||||
// - convert each set to a list and sort it first, then compare by walking
|
||||
// both lists in parallel
|
||||
// - map each element to a canonical object, create a map containing those
|
||||
// mappings, use the mapped sets to compare (then operations like
|
||||
// set.difference would work)
|
||||
Set remaining = set2.toSet();
|
||||
for (var element1 in set1) {
|
||||
bool found = false;
|
||||
for (var element2 in remaining) {
|
||||
if (sameElement(element1, element2)) {
|
||||
found = true;
|
||||
remaining.remove(element2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
common.add(element1);
|
||||
} else {
|
||||
unfound.add(element1);
|
||||
}
|
||||
}
|
||||
return remaining;
|
||||
}
|
||||
|
||||
/// Check equivalence of the two iterables, [set1] and [set1], as sets using
|
||||
/// [elementEquivalence] to compute the pair-wise equivalence.
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkSetEquivalence(
|
||||
var object1,
|
||||
var object2,
|
||||
String property,
|
||||
Iterable set1,
|
||||
Iterable set2,
|
||||
bool sameElement(a, b)) {
|
||||
List common = [];
|
||||
List unfound = [];
|
||||
Set remaining =
|
||||
computeSetDifference(set1, set2, common, unfound, sameElement);
|
||||
if (unfound.isNotEmpty || remaining.isNotEmpty) {
|
||||
String message =
|
||||
"Set mismatch for `$property` on $object1 vs $object2: \n"
|
||||
"Common:\n ${common.join('\n ')}\n"
|
||||
"Unfound:\n ${unfound.join('\n ')}\n"
|
||||
"Extra: \n ${remaining.join('\n ')}";
|
||||
throw message;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Checks the equivalence of the identity (but not properties) of [element1]
|
||||
/// and [element2].
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkElementIdentities(
|
||||
Object object1, Object object2, String property,
|
||||
Element element1, Element element2) {
|
||||
if (identical(element1, element2)) return true;
|
||||
if (element1 == null || element2 == null) {
|
||||
return check(object1, object2, property, element1, element2);
|
||||
} else {
|
||||
return const ElementIdentityEquivalence(const CheckStrategy())
|
||||
.visit(element1, element2);
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks the pair-wise equivalence of the identity (but not properties) of the
|
||||
/// elements in [list] and [list2].
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkElementListIdentities(
|
||||
Object object1, Object object2, String property,
|
||||
Iterable<Element> list1, Iterable<Element> list2) {
|
||||
return checkListEquivalence(
|
||||
object1, object2, property,
|
||||
list1, list2, checkElementIdentities);
|
||||
}
|
||||
|
||||
/// Checks the equivalence of [type1] and [type2].
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkTypes(
|
||||
Object object1, Object object2, String property,
|
||||
DartType type1, DartType type2) {
|
||||
if (identical(type1, type2)) return true;
|
||||
if (type1 == null || type2 == null) {
|
||||
return check(object1, object2, property, type1, type2);
|
||||
} else {
|
||||
return const TypeEquivalence(const CheckStrategy()).visit(type1, type2);
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks the pair-wise equivalence of the types in [list1] and [list2].
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkTypeLists(
|
||||
Object object1, Object object2, String property,
|
||||
List<DartType> list1, List<DartType> list2) {
|
||||
return checkListEquivalence(
|
||||
object1, object2, property, list1, list2, checkTypes);
|
||||
}
|
||||
|
||||
/// Checks the equivalence of [exp1] and [exp2].
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkConstants(
|
||||
Object object1, Object object2, String property,
|
||||
ConstantExpression exp1, ConstantExpression exp2) {
|
||||
if (identical(exp1, exp2)) return true;
|
||||
if (exp1 == null || exp2 == null) {
|
||||
return check(object1, object2, property, exp1, exp2);
|
||||
} else {
|
||||
return const ConstantEquivalence(const CheckStrategy()).visit(exp1, exp2);
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks the pair-wise equivalence of the contants in [list1] and [list2].
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkConstantLists(
|
||||
Object object1, Object object2, String property,
|
||||
List<ConstantExpression> list1,
|
||||
List<ConstantExpression> list2) {
|
||||
return checkListEquivalence(
|
||||
object1, object2, property,
|
||||
list1, list2, checkConstants);
|
||||
}
|
||||
|
||||
|
||||
/// Strategy for checking equivalence.
|
||||
///
|
||||
/// Use this strategy to fail early with contextual information in the event of
|
||||
/// inequivalence.
|
||||
class CheckStrategy implements TestStrategy {
|
||||
const CheckStrategy();
|
||||
|
||||
@override
|
||||
bool test(var object1, var object2, String property, var value1, var value2) {
|
||||
return check(object1, object2, property, value1, value2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool testLists(
|
||||
Object object1, Object object2, String property,
|
||||
List list1, List list2,
|
||||
[bool elementEquivalence(a, b) = equality]) {
|
||||
return checkListEquivalence(
|
||||
object1, object2, property, list1, list2,
|
||||
(o1, o2, p, v1, v2) {
|
||||
if (!elementEquivalence(v1, v2)) {
|
||||
throw "$o1.$p = '${v1}' <> "
|
||||
"$o2.$p = '${v2}'";
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
bool testSets(
|
||||
var object1, var object2, String property,
|
||||
Iterable set1, Iterable set2,
|
||||
[bool elementEquivalence(a, b) = equality]) {
|
||||
return checkSetEquivalence(
|
||||
object1, object2,property, set1, set2, elementEquivalence);
|
||||
}
|
||||
|
||||
@override
|
||||
bool testElements(
|
||||
Object object1, Object object2, String property,
|
||||
Element element1, Element element2) {
|
||||
return checkElementIdentities(
|
||||
object1, object2, property, element1, element2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool testTypes(
|
||||
Object object1, Object object2, String property,
|
||||
DartType type1, DartType type2) {
|
||||
return checkTypes(object1, object2, property, type1, type2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool testConstants(
|
||||
Object object1, Object object2, String property,
|
||||
ConstantExpression exp1, ConstantExpression exp2) {
|
||||
return checkConstants(object1, object2, property, exp1, exp2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool testTypeLists(
|
||||
Object object1, Object object2, String property,
|
||||
List<DartType> list1, List<DartType> list2) {
|
||||
return checkTypeLists(object1, object2, property, list1, list2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool testConstantLists(
|
||||
Object object1, Object object2, String property,
|
||||
List<ConstantExpression> list1,
|
||||
List<ConstantExpression> list2) {
|
||||
return checkConstantLists(object1, object2, property, list1, list2);
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks the equivalence of [constructor1] and [constructor2].
|
||||
void constantConstructorEquivalence(ConstantConstructor constructor1,
|
||||
ConstantConstructor constructor2) {
|
||||
|
@ -477,14 +222,13 @@ class ConstantConstructorEquivalence
|
|||
}
|
||||
}
|
||||
|
||||
/// Check that the values [property] of [object1] and [object2], [value1] and
|
||||
/// [value2] respectively, are equal and throw otherwise.
|
||||
bool check(var object1, var object2, String property, var value1, value2) {
|
||||
if (value1 != value2) {
|
||||
throw "$object1.$property = '${value1}' <> "
|
||||
"$object2.$property = '${value2}'";
|
||||
}
|
||||
return true;
|
||||
/// Check the equivalence of the two lists of elements, [list1] and [list2].
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
checkElementLists(Object object1, Object object2, String property,
|
||||
Iterable<Element> list1, Iterable<Element> list2) {
|
||||
checkListEquivalence(object1, object2, property,
|
||||
list1, list2, checkElementProperties);
|
||||
}
|
||||
|
||||
/// Visitor that checks for equivalence of [Element] properties.
|
||||
|
|
205
tests/compiler/dart2js/serialization_test_data.dart
Normal file
205
tests/compiler/dart2js/serialization_test_data.dart
Normal file
|
@ -0,0 +1,205 @@
|
|||
// Copyright (c) 2016, 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 dart2js.serialization_test_data;
|
||||
|
||||
const List<Test> TESTS = const <Test>[
|
||||
const Test(const {
|
||||
'main.dart': 'main() {}'
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': 'main() => print("Hello World");'
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': 'main() => print("Hello World", 0);'
|
||||
},
|
||||
expectedWarningCount: 1,
|
||||
expectedInfoCount: 1),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
main() {
|
||||
String text = "Hello World";
|
||||
print('$text');
|
||||
}'''
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
main() {
|
||||
String text = "Hello World";
|
||||
print('$text', text);
|
||||
}'''
|
||||
},
|
||||
expectedWarningCount: 1,
|
||||
expectedInfoCount: 1),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
main(List<String> arguments) {
|
||||
print(arguments);
|
||||
}'''
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
main(List<String> arguments) {
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
print(arguments[i]);
|
||||
}
|
||||
}'''
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
main(List<String> arguments) {
|
||||
for (String argument in arguments) {
|
||||
print(argument);
|
||||
}
|
||||
}'''
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
class Class {}
|
||||
main() {
|
||||
print(new Class());
|
||||
}'''
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
class Class implements Function {}
|
||||
main() {
|
||||
print(new Class());
|
||||
}'''
|
||||
},
|
||||
expectedWarningCount: 1),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
class Class implements Function {
|
||||
call() {}
|
||||
}
|
||||
main() {
|
||||
print(new Class()());
|
||||
}'''
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
class Class implements Comparable<Class> {
|
||||
int compareTo(Class other) => 0;
|
||||
}
|
||||
main() {
|
||||
print(new Class());
|
||||
}'''
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
class Class implements Comparable<Class, Class> {
|
||||
int compareTo(other) => 0;
|
||||
}
|
||||
main() {
|
||||
print(new Class());
|
||||
}'''
|
||||
},
|
||||
expectedWarningCount: 1),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
class Class implements Comparable<Class> {
|
||||
int compareTo(String other) => 0;
|
||||
}
|
||||
main() {
|
||||
print(new Class().compareTo(null));
|
||||
}'''
|
||||
},
|
||||
expectedWarningCount: 1,
|
||||
expectedInfoCount: 1),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
class Class implements Comparable {
|
||||
bool compareTo(a, b) => true;
|
||||
}
|
||||
main() {
|
||||
print(new Class().compareTo(null, null));
|
||||
}'''
|
||||
},
|
||||
expectedWarningCount: 1,
|
||||
expectedInfoCount: 1),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
import 'dart:math';
|
||||
|
||||
class MyRandom implements Random {
|
||||
int nextInt(int max) {
|
||||
return max.length;
|
||||
}
|
||||
bool nextBool() => true;
|
||||
double nextDouble() => 0.0;
|
||||
}
|
||||
main() {
|
||||
new MyRandom().nextInt(0);
|
||||
}'''
|
||||
},
|
||||
expectedWarningCount: 1,
|
||||
expectedInfoCount: 0),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
import 'dart:math';
|
||||
|
||||
class MyRandom implements Random {
|
||||
int nextInt(int max) {
|
||||
return max.length;
|
||||
}
|
||||
bool nextBool() => true;
|
||||
double nextDouble() => 0.0;
|
||||
}
|
||||
main() {
|
||||
new MyRandom();
|
||||
}'''
|
||||
}),
|
||||
|
||||
const Test(const {
|
||||
'main.dart': r'''
|
||||
import 'dart:math';
|
||||
|
||||
class MyRandom implements Random {
|
||||
int nextInt(int max) {
|
||||
return max.length;
|
||||
}
|
||||
bool nextBool() => true;
|
||||
double nextDouble() => 0.0;
|
||||
}
|
||||
main() {
|
||||
// Invocation of `MyRandom.nextInt` is only detected knowing the actual
|
||||
// implementation class for `List` and the world impact of its `shuffle`
|
||||
// method.
|
||||
[].shuffle(new MyRandom());
|
||||
}'''
|
||||
},
|
||||
expectedWarningCount: 1,
|
||||
expectedInfoCount: 0),
|
||||
];
|
||||
|
||||
class Test {
|
||||
final Map sourceFiles;
|
||||
final int expectedErrorCount;
|
||||
final int expectedWarningCount;
|
||||
final int expectedHintCount;
|
||||
final int expectedInfoCount;
|
||||
|
||||
const Test(this.sourceFiles, {
|
||||
this.expectedErrorCount: 0,
|
||||
this.expectedWarningCount: 0,
|
||||
this.expectedHintCount: 0,
|
||||
this.expectedInfoCount: 0});
|
||||
}
|
365
tests/compiler/dart2js/serialization_test_helper.dart
Normal file
365
tests/compiler/dart2js/serialization_test_helper.dart
Normal file
|
@ -0,0 +1,365 @@
|
|||
// Copyright (c) 2016, 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 dart2js.serialization_test_helper;
|
||||
|
||||
import 'dart:io';
|
||||
import 'memory_compiler.dart';
|
||||
import 'package:async_helper/async_helper.dart';
|
||||
import 'package:compiler/src/common/resolution.dart';
|
||||
import 'package:compiler/src/commandline_options.dart';
|
||||
import 'package:compiler/src/constants/constructors.dart';
|
||||
import 'package:compiler/src/constants/expressions.dart';
|
||||
import 'package:compiler/src/dart_types.dart';
|
||||
import 'package:compiler/src/compiler.dart';
|
||||
import 'package:compiler/src/diagnostics/invariant.dart';
|
||||
import 'package:compiler/src/elements/elements.dart';
|
||||
import 'package:compiler/src/elements/visitor.dart';
|
||||
import 'package:compiler/src/ordered_typeset.dart';
|
||||
import 'package:compiler/src/serialization/element_serialization.dart';
|
||||
import 'package:compiler/src/serialization/equivalence.dart';
|
||||
import 'package:compiler/src/serialization/json_serializer.dart';
|
||||
import 'package:compiler/src/serialization/serialization.dart';
|
||||
|
||||
|
||||
/// Strategy for checking equivalence.
|
||||
///
|
||||
/// Use this strategy to fail early with contextual information in the event of
|
||||
/// inequivalence.
|
||||
class CheckStrategy implements TestStrategy {
|
||||
const CheckStrategy();
|
||||
|
||||
@override
|
||||
bool test(var object1, var object2, String property, var value1, var value2,
|
||||
[bool equivalence(a, b) = equality]) {
|
||||
return check(object1, object2, property, value1, value2, equivalence);
|
||||
}
|
||||
|
||||
@override
|
||||
bool testLists(
|
||||
Object object1, Object object2, String property,
|
||||
List list1, List list2,
|
||||
[bool elementEquivalence(a, b) = equality]) {
|
||||
return checkListEquivalence(
|
||||
object1, object2, property, list1, list2,
|
||||
(o1, o2, p, v1, v2) {
|
||||
if (!elementEquivalence(v1, v2)) {
|
||||
throw "$o1.$p = '${v1}' <> "
|
||||
"$o2.$p = '${v2}'";
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
bool testSets(
|
||||
var object1, var object2, String property,
|
||||
Iterable set1, Iterable set2,
|
||||
[bool elementEquivalence(a, b) = equality]) {
|
||||
return checkSetEquivalence(
|
||||
object1, object2,property, set1, set2, elementEquivalence);
|
||||
}
|
||||
|
||||
@override
|
||||
bool testElements(
|
||||
Object object1, Object object2, String property,
|
||||
Element element1, Element element2) {
|
||||
return checkElementIdentities(
|
||||
object1, object2, property, element1, element2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool testTypes(
|
||||
Object object1, Object object2, String property,
|
||||
DartType type1, DartType type2) {
|
||||
return checkTypes(object1, object2, property, type1, type2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool testConstants(
|
||||
Object object1, Object object2, String property,
|
||||
ConstantExpression exp1, ConstantExpression exp2) {
|
||||
return checkConstants(object1, object2, property, exp1, exp2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool testTypeLists(
|
||||
Object object1, Object object2, String property,
|
||||
List<DartType> list1, List<DartType> list2) {
|
||||
return checkTypeLists(object1, object2, property, list1, list2);
|
||||
}
|
||||
|
||||
@override
|
||||
bool testConstantLists(
|
||||
Object object1, Object object2, String property,
|
||||
List<ConstantExpression> list1,
|
||||
List<ConstantExpression> list2) {
|
||||
return checkConstantLists(object1, object2, property, list1, list2);
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that the values [property] of [object1] and [object2], [value1] and
|
||||
/// [value2] respectively, are equal and throw otherwise.
|
||||
bool check(var object1, var object2, String property, var value1, var value2,
|
||||
[bool equivalence(a, b) = equality]) {
|
||||
if (!equivalence(value1, value2)) {
|
||||
throw "property='$property' "
|
||||
"object1=$object1 (${object1.runtimeType}), value='${value1}' <> "
|
||||
"object2=$object2 (${object2.runtimeType}), value='${value2}'";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Check equivalence of the two lists, [list1] and [list2], using
|
||||
/// [checkEquivalence] to check the pair-wise equivalence.
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkListEquivalence(
|
||||
Object object1, Object object2, String property,
|
||||
Iterable list1, Iterable list2,
|
||||
void checkEquivalence(o1, o2, property, a, b)) {
|
||||
for (int i = 0; i < list1.length && i < list2.length; i++) {
|
||||
checkEquivalence(
|
||||
object1, object2, property,
|
||||
list1.elementAt(i), list2.elementAt(i));
|
||||
}
|
||||
for (int i = list1.length; i < list2.length; i++) {
|
||||
throw
|
||||
'Missing equivalent for element '
|
||||
'#$i ${list2.elementAt(i)} in `${property}` on $object2.\n'
|
||||
'`${property}` on $object1:\n ${list1.join('\n ')}\n'
|
||||
'`${property}` on $object2:\n ${list2.join('\n ')}';
|
||||
}
|
||||
for (int i = list2.length; i < list1.length; i++) {
|
||||
throw
|
||||
'Missing equivalent for element '
|
||||
'#$i ${list1.elementAt(i)} in `${property}` on $object1.\n'
|
||||
'`${property}` on $object1:\n ${list1.join('\n ')}\n'
|
||||
'`${property}` on $object2:\n ${list2.join('\n ')}';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Computes the set difference between [set1] and [set2] using
|
||||
/// [elementEquivalence] to determine element equivalence.
|
||||
///
|
||||
/// Elements both in [set1] and [set2] are added to [common], elements in [set1]
|
||||
/// but not in [set2] are added to [unfound], and the set of elements in [set2]
|
||||
/// but not in [set1] are returned.
|
||||
Set computeSetDifference(
|
||||
Iterable set1,
|
||||
Iterable set2,
|
||||
List common,
|
||||
List unfound,
|
||||
[bool sameElement(a, b) = equality]) {
|
||||
// TODO(johnniwinther): Avoid the quadratic cost here. Some ideas:
|
||||
// - convert each set to a list and sort it first, then compare by walking
|
||||
// both lists in parallel
|
||||
// - map each element to a canonical object, create a map containing those
|
||||
// mappings, use the mapped sets to compare (then operations like
|
||||
// set.difference would work)
|
||||
Set remaining = set2.toSet();
|
||||
for (var element1 in set1) {
|
||||
bool found = false;
|
||||
for (var element2 in remaining) {
|
||||
if (sameElement(element1, element2)) {
|
||||
found = true;
|
||||
remaining.remove(element2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
common.add(element1);
|
||||
} else {
|
||||
unfound.add(element1);
|
||||
}
|
||||
}
|
||||
return remaining;
|
||||
}
|
||||
|
||||
/// Check equivalence of the two iterables, [set1] and [set1], as sets using
|
||||
/// [elementEquivalence] to compute the pair-wise equivalence.
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkSetEquivalence(
|
||||
var object1,
|
||||
var object2,
|
||||
String property,
|
||||
Iterable set1,
|
||||
Iterable set2,
|
||||
bool sameElement(a, b)) {
|
||||
List common = [];
|
||||
List unfound = [];
|
||||
Set remaining =
|
||||
computeSetDifference(set1, set2, common, unfound, sameElement);
|
||||
if (unfound.isNotEmpty || remaining.isNotEmpty) {
|
||||
String message =
|
||||
"Set mismatch for `$property` on $object1 vs $object2: \n"
|
||||
"Common:\n ${common.join('\n ')}\n"
|
||||
"Unfound:\n ${unfound.join('\n ')}\n"
|
||||
"Extra: \n ${remaining.join('\n ')}";
|
||||
throw message;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Checks the equivalence of the identity (but not properties) of [element1]
|
||||
/// and [element2].
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkElementIdentities(
|
||||
Object object1, Object object2, String property,
|
||||
Element element1, Element element2) {
|
||||
if (identical(element1, element2)) return true;
|
||||
if (element1 == null || element2 == null) {
|
||||
return check(object1, object2, property, element1, element2);
|
||||
} else {
|
||||
return const ElementIdentityEquivalence(const CheckStrategy())
|
||||
.visit(element1, element2);
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks the pair-wise equivalence of the identity (but not properties) of the
|
||||
/// elements in [list] and [list2].
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkElementListIdentities(
|
||||
Object object1, Object object2, String property,
|
||||
Iterable<Element> list1, Iterable<Element> list2) {
|
||||
return checkListEquivalence(
|
||||
object1, object2, property,
|
||||
list1, list2, checkElementIdentities);
|
||||
}
|
||||
|
||||
/// Checks the equivalence of [type1] and [type2].
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkTypes(
|
||||
Object object1, Object object2, String property,
|
||||
DartType type1, DartType type2) {
|
||||
if (identical(type1, type2)) return true;
|
||||
if (type1 == null || type2 == null) {
|
||||
return check(object1, object2, property, type1, type2);
|
||||
} else {
|
||||
return const TypeEquivalence(const CheckStrategy()).visit(type1, type2);
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks the pair-wise equivalence of the types in [list1] and [list2].
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkTypeLists(
|
||||
Object object1, Object object2, String property,
|
||||
List<DartType> list1, List<DartType> list2) {
|
||||
return checkListEquivalence(
|
||||
object1, object2, property, list1, list2, checkTypes);
|
||||
}
|
||||
|
||||
/// Checks the equivalence of [exp1] and [exp2].
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkConstants(
|
||||
Object object1, Object object2, String property,
|
||||
ConstantExpression exp1, ConstantExpression exp2) {
|
||||
if (identical(exp1, exp2)) return true;
|
||||
if (exp1 == null || exp2 == null) {
|
||||
return check(object1, object2, property, exp1, exp2);
|
||||
} else {
|
||||
return const ConstantEquivalence(const CheckStrategy()).visit(exp1, exp2);
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks the pair-wise equivalence of the contants in [list1] and [list2].
|
||||
///
|
||||
/// Uses [object1], [object2] and [property] to provide context for failures.
|
||||
bool checkConstantLists(
|
||||
Object object1, Object object2, String property,
|
||||
List<ConstantExpression> list1,
|
||||
List<ConstantExpression> list2) {
|
||||
return checkListEquivalence(
|
||||
object1, object2, property,
|
||||
list1, list2, checkConstants);
|
||||
}
|
||||
|
||||
|
||||
/// Check member property equivalence between all members common to [compiler1]
|
||||
/// and [compiler2].
|
||||
void checkLoadedLibraryMembers(
|
||||
Compiler compiler1,
|
||||
Compiler compiler2,
|
||||
bool hasProperty(Element member1),
|
||||
void checkMemberProperties(Compiler compiler1, Element member1,
|
||||
Compiler compiler2, Element member2,
|
||||
{bool verbose}),
|
||||
{bool verbose: false}) {
|
||||
|
||||
void checkMembers(Element member1, Element member2) {
|
||||
if (member1.isClass && member2.isClass) {
|
||||
ClassElement class1 = member1;
|
||||
ClassElement class2 = member2;
|
||||
class1.forEachLocalMember((m1) {
|
||||
checkMembers(m1, class2.lookupLocalMember(m1.name));
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasProperty(member1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (member2 == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (areElementsEquivalent(member1, member2)) {
|
||||
checkMemberProperties(
|
||||
compiler1, member1,
|
||||
compiler2, member2,
|
||||
verbose: verbose);
|
||||
}
|
||||
}
|
||||
|
||||
for (LibraryElement library1 in compiler1.libraryLoader.libraries) {
|
||||
LibraryElement library2 =
|
||||
compiler2.libraryLoader.lookupLibrary(library1.canonicalUri);
|
||||
if (library2 != null) {
|
||||
library1.forEachLocalMember((Element member1) {
|
||||
checkMembers(member1, library2.localLookup(member1.name));
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Check equivalence of all resolution impacts.
|
||||
void checkAllImpacts(
|
||||
Compiler compiler1,
|
||||
Compiler compiler2,
|
||||
{bool verbose: false}) {
|
||||
checkLoadedLibraryMembers(
|
||||
compiler1,
|
||||
compiler2,
|
||||
(Element member1) {
|
||||
return compiler1.resolution.hasResolutionImpact(member1);
|
||||
},
|
||||
checkImpacts,
|
||||
verbose: true);
|
||||
}
|
||||
|
||||
/// Check equivalence of resolution impact for [member1] and [member2].
|
||||
void checkImpacts(Compiler compiler1, Element member1,
|
||||
Compiler compiler2, Element member2,
|
||||
{bool verbose: false}) {
|
||||
ResolutionImpact impact1 = compiler1.resolution.getResolutionImpact(member1);
|
||||
ResolutionImpact impact2 =
|
||||
compiler2.serialization.deserializer.getResolutionImpact(member2);
|
||||
|
||||
if (impact1 == null || impact2 == null) return;
|
||||
|
||||
if (verbose) {
|
||||
print('Checking impacts for $member1 vs $member2');
|
||||
}
|
||||
|
||||
testResolutionImpactEquivalence(impact1, impact2, const CheckStrategy());
|
||||
}
|
Loading…
Reference in a new issue