Index: tests/compiler/dart2js/serialization_model_test.dart |
diff --git a/tests/compiler/dart2js/serialization_model_test.dart b/tests/compiler/dart2js/serialization_model_test.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b8cef2598d326be53a929cdd3678255d785ef0e2 |
--- /dev/null |
+++ b/tests/compiler/dart2js/serialization_model_test.dart |
@@ -0,0 +1,224 @@ |
+// Copyright (c) 2015, 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_model_test; |
+ |
+import 'dart:async'; |
+import 'dart:io'; |
+import 'package:async_helper/async_helper.dart'; |
+import 'package:expect/expect.dart'; |
+import 'package:compiler/src/commandline_options.dart'; |
+import 'package:compiler/src/common/backend_api.dart'; |
+import 'package:compiler/src/common/names.dart'; |
+import 'package:compiler/src/common/resolution.dart'; |
+import 'package:compiler/src/compiler.dart'; |
+import 'package:compiler/src/dart_types.dart'; |
+import 'package:compiler/src/elements/elements.dart'; |
+import 'package:compiler/src/filenames.dart'; |
+import 'package:compiler/src/serialization/element_serialization.dart'; |
+import 'package:compiler/src/serialization/impact_serialization.dart'; |
+import 'package:compiler/src/serialization/json_serializer.dart'; |
+import 'package:compiler/src/serialization/serialization.dart'; |
+import 'package:compiler/src/serialization/equivalence.dart'; |
+import 'package:compiler/src/serialization/task.dart'; |
+import 'package:compiler/src/universe/world_impact.dart'; |
+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'; |
+ |
+main(List<String> arguments) { |
+ String filename; |
+ for (String arg in arguments) { |
+ if (!arg.startsWith('-')) { |
+ filename = arg; |
+ } |
+ } |
+ bool verbose = arguments.contains('-v'); |
+ |
+ asyncTest(() async { |
+ print('------------------------------------------------------------------'); |
+ print('serialize dart:core'); |
+ print('------------------------------------------------------------------'); |
+ String serializedData; |
+ File file = new File('out.data'); |
+ if (arguments.contains('-l')) { |
+ if (file.existsSync()) { |
+ print('Loading data from $file'); |
+ serializedData = file.readAsStringSync(); |
+ } |
+ } |
+ if (serializedData == null) { |
+ serializedData = await serializeDartCore(); |
+ if (arguments.contains('-s')) { |
+ print('Saving data to $file'); |
+ file.writeAsStringSync(serializedData); |
+ } |
+ } |
+ if (filename != null) { |
+ Uri entryPoint = Uri.base.resolve(nativeToUriPath(filename)); |
+ await check(serializedData, entryPoint); |
+ } else { |
+ Uri entryPoint = Uri.parse('memory:main.dart'); |
+ for (Test test in TESTS) { |
+ if (test.sourceFiles['main.dart'] |
+ .contains('main(List<String> arguments)')) { |
+ // TODO(johnniwinther): Check this test. |
+ continue; |
+ } |
+ print('=============================================================='); |
+ print(test.sourceFiles); |
+ await check( |
+ serializedData, |
+ entryPoint, |
+ sourceFiles: test.sourceFiles, |
+ verbose: verbose); |
+ } |
+ } |
+ }); |
+} |
+ |
+Future check( |
+ String serializedData, |
+ Uri entryPoint, |
+ {Map<String, String> sourceFiles: const <String, String>{}, |
+ bool verbose: false}) async { |
+ |
+ print('------------------------------------------------------------------'); |
+ print('compile normal'); |
+ print('------------------------------------------------------------------'); |
+ Compiler compilerNormal = compilerFor( |
+ memorySourceFiles: sourceFiles, |
+ options: [Flags.analyzeOnly]); |
+ compilerNormal.resolution.retainCachesForTesting = true; |
+ await compilerNormal.run(entryPoint); |
+ compilerNormal.world.populate(); |
+ |
+ print('------------------------------------------------------------------'); |
+ print('compile deserialized'); |
+ print('------------------------------------------------------------------'); |
+ Compiler compilerDeserialized = compilerFor( |
+ memorySourceFiles: sourceFiles, |
+ options: [Flags.analyzeOnly]); |
+ compilerDeserialized.resolution.retainCachesForTesting = true; |
+ deserialize(compilerDeserialized, serializedData); |
+ await compilerDeserialized.run(entryPoint); |
+ compilerDeserialized.world.populate(); |
+ |
+ checkResolutionImpacts( |
+ compilerNormal, compilerDeserialized, |
+ verbose: verbose); |
+ |
+ checkSets( |
+ compilerNormal.resolverWorld.directlyInstantiatedClasses, |
+ compilerDeserialized.resolverWorld.directlyInstantiatedClasses, |
+ "Directly instantiated classes mismatch", |
+ areElementsEquivalent, |
+ verbose: verbose); |
+ |
+ checkSets( |
+ compilerNormal.resolverWorld.instantiatedTypes, |
+ compilerDeserialized.resolverWorld.instantiatedTypes, |
+ "Instantiated types mismatch", |
+ areTypesEquivalent, |
+ // TODO(johnniwinther): Ensure that all instantiated types are tracked. |
+ failOnUnfound: false, |
+ verbose: verbose); |
+ |
+ checkSets( |
+ compilerNormal.resolverWorld.isChecks, |
+ compilerDeserialized.resolverWorld.isChecks, |
+ "Is-check mismatch", |
+ areTypesEquivalent, |
+ verbose: verbose); |
+ |
+ checkSets( |
+ compilerNormal.enqueuer.resolution.processedElements, |
+ compilerDeserialized.enqueuer.resolution.processedElements, |
+ "Processed element mismatch", |
+ areElementsEquivalent, |
+ verbose: verbose); |
+ |
+ checkClassHierarchyNodes( |
+ compilerNormal.world.getClassHierarchyNode( |
+ compilerNormal.coreClasses.objectClass), |
+ compilerDeserialized.world.getClassHierarchyNode( |
+ compilerDeserialized.coreClasses.objectClass), |
+ verbose: verbose); |
+} |
+ |
+void checkClassHierarchyNodes( |
+ ClassHierarchyNode a, ClassHierarchyNode b, |
+ {bool verbose: false}) { |
+ if (verbose) { |
+ print('Checking $a vs $b'); |
+ } |
+ Expect.isTrue( |
+ areElementsEquivalent(a.cls, b.cls), |
+ "Element identity mismatch for ${a.cls} vs ${b.cls}."); |
+ Expect.equals( |
+ a.isDirectlyInstantiated, |
+ b.isDirectlyInstantiated, |
+ "Value mismatch for 'isDirectlyInstantiated' for ${a.cls} vs ${b.cls}."); |
+ Expect.equals( |
+ a.isIndirectlyInstantiated, |
+ b.isIndirectlyInstantiated, |
+ "Value mismatch for 'isIndirectlyInstantiated' " |
+ "for ${a.cls} vs ${b.cls}."); |
+ // TODO(johnniwinther): Enforce a canonical and stable order on direct |
+ // subclasses. |
+ for (ClassHierarchyNode child in a.directSubclasses) { |
+ bool found = false; |
+ for (ClassHierarchyNode other in b.directSubclasses) { |
+ if (areElementsEquivalent(child.cls, other.cls)) { |
+ checkClassHierarchyNodes(child, other, |
+ verbose: verbose); |
+ found = true; |
+ break; |
+ } |
+ } |
+ if (!found) { |
+ Expect.isFalse( |
+ child.isInstantiated, 'Missing subclass ${child.cls} of ${a.cls}'); |
+ } |
+ } |
+} |
+ |
+void checkSets( |
+ Iterable set1, |
+ Iterable set2, |
+ String messagePrefix, |
+ bool areEquivalent(a, b), |
+ {bool failOnUnfound: true, |
+ bool verbose: false}) { |
+ List common = []; |
+ List unfound = []; |
+ Set remaining = computeSetDifference( |
+ set1, set2, common, unfound, areEquivalent); |
+ StringBuffer sb = new StringBuffer(); |
+ sb.write("$messagePrefix:"); |
+ if (verbose) { |
+ sb.write("\n Common:\n ${common.join('\n ')}"); |
+ } |
+ if (unfound.isNotEmpty || verbose) { |
+ sb.write("\n Unfound:\n ${unfound.join('\n ')}"); |
+ } |
+ if (remaining.isNotEmpty || verbose) { |
+ sb.write("\n Extra: \n ${remaining.join('\n ')}"); |
+ } |
+ String message = sb.toString(); |
+ if (unfound.isNotEmpty || remaining.isNotEmpty) { |
+ |
+ if (failOnUnfound || remaining.isNotEmpty) { |
+ Expect.fail(message); |
+ } else { |
+ print(message); |
+ } |
+ } else if (verbose) { |
+ print(message); |
+ } |
+} |