Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(320)

Side by Side Diff: pkg/front_end/test/fasta/shaker_test.dart

Issue 2893493004: First step for modular output in fasta. (Closed)
Patch Set: cl comments Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pkg/front_end/test/fasta/shaker.status ('k') | pkg/front_end/test/fasta/testing.json » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2017, 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.md file.
4
5 /// Tests basic functionality of the API tree-shaker.
6 ///
7 /// Each input file is built and tree-shaken, then we check that the set of
8 /// libraries, classes, and members that are retained match those declared in an
9 /// expectations file.
10 ///
11 /// Input files may contain markers to turn on flags that configure this
12 /// runner. Currently only the following marker is recognized:
13 /// @@SHOW_CORE_LIBRARIES@@ - whether to check for retained information from
14 /// the core libraries. By default this runner only checks for members of
15 /// pkg/front_end/testcases/shaker/lib/lib.dart.
16 library fasta.test.shaker_test;
17
18 import 'dart:async' show Future;
19 import 'dart:convert' show JSON;
20 import 'dart:io' show File;
21
22 export 'package:testing/testing.dart' show Chain, runMe;
23 import 'package:front_end/physical_file_system.dart';
24 import 'package:front_end/src/fasta/dill/dill_target.dart' show DillTarget;
25 import 'package:front_end/src/fasta/errors.dart' show InputError;
26 import 'package:front_end/src/fasta/kernel/kernel_target.dart'
27 show KernelTarget;
28 import 'package:front_end/src/fasta/kernel/verifier.dart' show verifyProgram;
29 import 'package:front_end/src/fasta/testing/kernel_chain.dart' show runDiff;
30 import 'package:front_end/src/fasta/testing/patched_sdk_location.dart';
31 import 'package:front_end/src/fasta/ticker.dart' show Ticker;
32 import 'package:front_end/src/fasta/translate_uri.dart' show TranslateUri;
33 import 'package:front_end/src/fasta/util/relativize.dart' show relativizeUri;
34 import 'package:kernel/ast.dart' show Program;
35 import 'package:kernel/kernel.dart' show loadProgramFromBytes;
36 import 'package:testing/testing.dart'
37 show Chain, ChainContext, ExpectationSet, Result, Step, TestDescription;
38 import 'testing/suite.dart';
39
40 main(List<String> arguments) => runMe(arguments, createContext, "testing.json");
41
42 Future<TreeShakerContext> createContext(
43 Chain suite, Map<String, String> environment) {
44 return TreeShakerContext.create(environment);
45 }
46
47 /// Context used to run the tree-shaking test suite.
48 class TreeShakerContext extends ChainContext {
49 final TranslateUri uriTranslator;
50 final Uri outlineUri;
51 final List<Step> steps;
52 final List<int> outlineBytes;
53
54 final ExpectationSet expectationSet =
55 new ExpectationSet.fromJsonList(JSON.decode(EXPECTATIONS));
56
57 TreeShakerContext(this.outlineUri, this.uriTranslator, this.outlineBytes,
58 bool updateExpectations)
59 : steps = <Step>[
60 const BuildProgram(),
61 new CheckShaker(updateExpectations: updateExpectations),
62 ];
63
64 Program loadPlatformOutline() {
65 // Note: we rebuild the platform outline on every test because the compiler
66 // currently mutates the in-memory representation of the program without
67 // cloning it.
68 return loadProgramFromBytes(outlineBytes);
69 }
70
71 static create(Map<String, String> environment) async {
72 environment[ENABLE_FULL_COMPILE] = "";
73 environment[AST_KIND_INDEX] = "${AstKind.Kernel.index}";
74 bool updateExpectations = environment["updateExpectations"] == "true";
75 Uri sdk = await computePatchedSdk();
76 Uri outlineUri = sdk.resolve('outline.dill');
77 Uri packages = Uri.base.resolve(".packages");
78 TranslateUri uriTranslator =
79 await TranslateUri.parse(PhysicalFileSystem.instance, packages);
80 List<int> outlineBytes = new File.fromUri(outlineUri).readAsBytesSync();
81 return new TreeShakerContext(
82 outlineUri, uriTranslator, outlineBytes, updateExpectations);
83 }
84 }
85
86 /// Step that extracts the test-specific options and builds the program without
87 /// applying tree-shaking.
88 class BuildProgram
89 extends Step<TestDescription, _IntermediateData, TreeShakerContext> {
90 const BuildProgram();
91 String get name => "build program";
92 Future<Result<_IntermediateData>> run(
93 TestDescription description, TreeShakerContext context) async {
94 try {
95 var platformOutline = context.loadPlatformOutline();
96 platformOutline.unbindCanonicalNames();
97 var dillTarget =
98 new DillTarget(new Ticker(isVerbose: false), context.uriTranslator);
99 dillTarget.loader.appendLibraries(platformOutline);
100 var sourceTarget = new KernelTarget(PhysicalFileSystem.instance,
101 dillTarget, context.uriTranslator, false);
102 await dillTarget.buildOutlines();
103
104 var inputUri = description.uri;
105
106 /// We treat the lib.dart library as a special dependency that was
107 /// previously built. To do so, we build it and append it back to the
108 /// dillTarget before building the actual test.
109 var libUri = inputUri.resolve('lib/lib.dart');
110 sourceTarget.read(libUri);
111 dillTarget.loader.appendLibraries(
112 await sourceTarget.buildOutlines(), (uri) => uri == libUri);
113
114 /// This new KernelTarget contains only sources from the test without
115 /// lib.dart.
116 sourceTarget = new KernelTarget(PhysicalFileSystem.instance, dillTarget,
117 context.uriTranslator, false);
118
119 await dillTarget.buildOutlines();
120 sourceTarget.read(inputUri);
121 var contents = new File.fromUri(inputUri).readAsStringSync();
122 var showCoreLibraries = contents.contains("@@SHOW_CORE_LIBRARIES@@");
123
124 await sourceTarget.buildOutlines();
125 // Note: We run the tree-shaker as a separate step on this suite to be
126 // able to specify what libraries to tree shake (by default only the code
127 // in the dillTarget gets tree-shaken). We could apply the tree-shaker
128 // twice, but that seems unnecessary.
129 var program = await sourceTarget.buildProgram(trimDependencies: true);
130 return pass(new _IntermediateData(inputUri, program, showCoreLibraries));
131 } on InputError catch (e, s) {
132 return fail(null, e.error, s);
133 }
134 }
135 }
136
137 /// Intermediate result from the testing chain.
138 class _IntermediateData {
139 /// The input URI provided to the test.
140 final Uri uri;
141
142 /// Program built by [BuildProgram].
143 final Program program;
144
145 /// Whether the output should include tree-shaking information about the core
146 /// libraries. This is specified in a comment on individual test files where
147 /// we believe that information is relevant.
148 final bool showCoreLibraries;
149
150 _IntermediateData(this.uri, this.program, this.showCoreLibraries);
151 }
152
153 /// A step that runs the tree-shaker and checks againt an expectation file for
154 /// the list of members and classes that should be preserved by the tree-shaker.
155 class CheckShaker extends Step<_IntermediateData, String, ChainContext> {
156 final bool updateExpectations;
157 const CheckShaker({this.updateExpectations: false});
158
159 String get name => "match shaker expectation";
160
161 /// Tree-shake dart:* libraries and the library under [_specialLibraryPath].
162 bool _isTreeShaken(Uri uri) =>
163 uri.isScheme('dart') ||
164 Uri.base.resolveUri(uri).path.endsWith(_specialLibraryPath);
165
166 Future<Result<String>> run(
167 _IntermediateData data, ChainContext context) async {
168 String actualResult;
169 var entryUri = data.program.libraries
170 .firstWhere((l) => !l.importUri.isScheme('dart'))
171 .importUri;
172
173 var program = data.program;
174
175 var errors = verifyProgram(program, isOutline: false);
176 if (!errors.isEmpty) {
177 return new Result<String>(
178 null, context.expectationSet["VerificationError"], errors, null);
179 }
180
181 // Build a text representation of what we expect to be retained.
182 var buffer = new StringBuffer();
183 buffer.writeln('DO NOT EDIT -- this file is autogenerated ---');
184 buffer.writeln('Tree-shaker preserved the following:');
185 for (var library in program.libraries) {
186 var importUri = library.importUri;
187 if (!_isTreeShaken(importUri)) continue;
188 if (importUri.isScheme('dart') && !data.showCoreLibraries) continue;
189 String uri = relativizeUri(library.importUri);
190 buffer.writeln('\nlibrary $uri:');
191 for (var member in library.members) {
192 buffer.writeln(' - member ${member.name}');
193 }
194 for (var typedef_ in library.typedefs) {
195 buffer.writeln(' - typedef ${typedef_.name}');
196 }
197 for (var cls in library.classes) {
198 buffer.writeln(' - class ${cls.name}');
199 for (var member in cls.members) {
200 var name = '${member.name}';
201 if (name == "") {
202 buffer.writeln(' - (default constructor)');
203 } else {
204 buffer.writeln(' - $name');
205 }
206 }
207 }
208 }
209
210 actualResult = "$buffer";
211
212 // Compare against expectations using the text representation.
213 File expectedFile = new File("${entryUri.toFilePath()}.shaker");
214 if (await expectedFile.exists()) {
215 String expected = await expectedFile.readAsString();
216 if (expected.trim() != actualResult.trim()) {
217 if (!updateExpectations) {
218 String diff = await runDiff(expectedFile.uri, actualResult);
219 return fail(
220 null, "$entryUri doesn't match ${expectedFile.uri}\n$diff");
221 }
222 } else {
223 return pass(actualResult);
224 }
225 }
226 if (updateExpectations) {
227 expectedFile.writeAsStringSync(actualResult);
228 return pass(actualResult);
229 } else {
230 return fail(
231 actualResult,
232 """
233 Please create file ${expectedFile.path} with this content:
234 $buffer""");
235 }
236 }
237 }
238
239 /// A special library used only to test the shaker. The suite above will
240 /// tree-shake the contents of this library.
241 const _specialLibraryPath = 'pkg/front_end/testcases/shaker/lib/lib.dart';
OLDNEW
« no previous file with comments | « pkg/front_end/test/fasta/shaker.status ('k') | pkg/front_end/test/fasta/testing.json » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698