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

Side by Side Diff: tests/standalone/packages_file_test.dart

Issue 1993643002: Add test of some package-config configurations. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Fix type Created 4 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 | « no previous file | no next file » | 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) 2016, 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 import "dart:async";
6 import "dart:io";
7 import "dart:isolate";
8 import "dart:convert" show JSON;
9 import "package:path/path.dart" as p;
10 import "package:expect/expect.dart";
11 import "package:async_helper/async_helper.dart";
12
13 main() async {
14 asyncStart();
15
16 for (var test in [testDirect]) {
floitsch 2016/05/18 13:36:32 As long as there is just one, I would just rename
17 await test("file: no resolution", (run, dir) async {
18 // Expect everything to be null.
19 await run(dir.resolve("main.dart"), {"foo.x": null});
floitsch 2016/05/18 13:36:32 This ping-pong is too complicated. Just add a tok
Lasse Reichstein Nielsen 2016/05/18 14:01:16 And I haven't even gotten started on nested calls
20 }, files: {"main": testMain});
21
22 await test("http: no resolution", (run, dir) async {
23 // An HTTP script with no ".packages" file assumes a "packages" dir.
24 await run(dir.resolve("main.dart"), {
25 // "foo": null,
26 "foo/": dir.resolve("packages/foo/"),
27 "foo/bar": dir.resolve("packages/foo/bar"),
28 "foo.x": null,
29 });
30 }, http: {"main": testMain});
31
32 for (var scheme in ["file", "http"]) {
33 {
34 var files = {"main": testMain, "packages": fooPackage};
35 await test("$scheme: implicit packages dir", (run, dir) async {
36 // Expect implicitly detected package dir.
37 await run(dir.resolve("main.dart"), {
38 "iroot": dir.resolve("packages/"),
39 // "foo": null,
40 "foo/": dir.resolve("packages/foo/"),
41 "foo/bar": dir.resolve("packages/foo/bar"),
42 });
43 }, files: scheme == "file" ? files : null,
44 http: scheme == "http" ? files : null);
45 }
46
47 {
48 var files = {"sub": {"main": testMain, "packages": fooPackage},
49 ".packages": ""};
50 await test("$scheme: implicit packages dir 2", (run, dir) async {
51 // Expect implicitly detected package dir.
52 await run(dir.resolve("sub/main.dart"), {
53 "iroot": dir.resolve("sub/packages/"),
54 // "foo": null,
55 "foo/": dir.resolve("sub/packages/foo/"),
56 "foo/bar": dir.resolve("sub/packages/foo/bar"),
57 });
58 }, files: scheme == "file" ? files : null,
59 http: scheme == "http" ? files : null);
60 }
61
62 {
63 var files = {"main": testMain,
64 ".packages": "foo:pkgs/foo/",
65 "pkgs": fooPackage};
66 await test("$scheme: implicit .packages file", (run, dir) async {
67 // Expect implicitly detected .package file.
68 await run(dir.resolve("main.dart"), {
69 "iconf": dir.resolve(".packages"),
70 // "foo": null,
71 "foo/": dir.resolve("pkgs/foo/"),
72 "foo/bar": dir.resolve("pkgs/foo/bar"),
73 });
74 }, files: scheme == "file" ? files : null,
75 http: scheme == "http" ? files : null);
76 }
77
78 {
79 var files = {"main": testMain,
80 ".packages": "foo:packages/foo/",
81 "packages": fooPackage,
82 "pkgs": fooPackage};
83 await test("$scheme: explicit package root, no slash", (run, dir) async {
floitsch 2016/05/18 13:36:32 long line.
84 await run(dir.resolve("main.dart"), {
85 "proot": dir.resolve("pkgs/"),
86 "iroot": dir.resolve("pkgs/"),
87 // "foo": null,
88 "foo/": dir.resolve("pkgs/foo/"),
89 "foo/bar": dir.resolve("pkgs/foo/bar"),
90 }, root: dir.resolve("pkgs"));
91 }, files: scheme == "file" ? files : null,
92 http: scheme == "http" ? files : null);
93
94 await test("$scheme: explicit package root, slash", (run, dir) async {
95 await run(dir.resolve("main.dart"), {
96 "proot": dir.resolve("pkgs/"),
97 "iroot": dir.resolve("pkgs/"),
98 // "foo": null,
99 "foo/": dir.resolve("pkgs/foo/"),
100 "foo/bar": dir.resolve("pkgs/foo/bar"),
101 }, root: dir.resolve("pkgs/"));
102 }, files: scheme == "file" ? files : null,
103 http: scheme == "http" ? files : null);
104 }
105
106 {
107 var files = {"main": testMain,
108 ".packages": "foo:packages/foo/",
109 "packages": fooPackage,
110 ".pkgs": "foo:pkgs/foo/",
111 "pkgs": fooPackage};
112 await test("$scheme: explicit package config file", (run, dir) async {
113 await run(dir.resolve("main.dart"), {
114 "pconf": dir.resolve(".pkgs"),
115 "iconf": dir.resolve(".pkgs"),
116 // "foo": null,
117 "foo/": dir.resolve("pkgs/foo/"),
118 "foo/bar": dir.resolve("pkgs/foo/bar"),
119 }, config: dir.resolve(".pkgs"));
120 }, files: scheme == "file" ? files : null,
121 http: scheme == "http" ? files : null);
122 }
123
124 {
125 var files = {"main": testMain,
126 ".packages": "foo:packages/foo/",
127 "packages": fooPackage,
128 "pkgs": fooPackage};
129 await test("$scheme: explicit data: config file", (run, dir) async {
130 var dataUri = new UriData.fromString(
131 "foo:${dir.resolve("pkgs/foo/")}").uri;
132 await run(dir.resolve("main.dart"), {
133 "pconf": dataUri,
134 "iconf": dataUri,
135 // "foo": null,
136 "foo/": dir.resolve("pkgs/foo/"),
137 "foo/bar": dir.resolve("pkgs/foo/bar"),
138 }, config: dataUri);
139 }, files: scheme == "file" ? files : null,
140 http: scheme == "http" ? files : null);
141 }
142 }
143
144 {
145 // With a file: URI, the lookup checks for a .packages file in superdirs.
146 var files = {"sub": { "main": testMain },
147 ".packages": "foo:pkgs/foo/",
148 "pkgs": fooPackage};
149 await test("file: implicit .packages file in ..", (run, dir) async {
150 // Expect implicitly detected .package file.
151 await run(dir.resolve("sub/main.dart"), {
152 "iconf": dir.resolve(".packages"),
153 // "foo": null,
154 "foo/": dir.resolve("pkgs/foo/"),
155 "foo/bar": dir.resolve("pkgs/foo/bar"),
156 });
157 }, files: files);
158 }
159
160 {
161 // With a non-file: URI, the lookup assumes a packges/ dir.
162 var files = {"sub": { "main": testMain },
163 ".packages": "foo:pkgs/foo/",
164 "pkgs": fooPackage};
165 await test("http: implicit packages dir", (run, dir) async {
166 // Expect implicitly detected .package file.
167 await run(dir.resolve("sub/main.dart"), {
168 "iroot": dir.resolve("sub/packages/"),
169 // "foo": null,
170 "foo/": dir.resolve("sub/packages/foo/"),
171 "foo/bar": dir.resolve("sub/packages/foo/bar"),
172 "foo.x": null,
173 });
174 }, http: files);
175 }
176 }
177
178
179 if (failingTests.isNotEmpty) {
180 print("Errors found in tests:\n ${failingTests.join("\n ")}\n");
181 exit(255);
182 }
183 asyncEnd();
184 }
185
186 // ---------------------------------------------------------
187 // Helper fnuctionality.
floitsch 2016/05/18 13:36:32 functionality
188
189 var failingTests = new Set();
190
191 Future testDirect(name, Function test, {Map files, Map http}) async {
192 var tmpDir;
193 var https;
194 if (files != null) tmpDir = createFiles(files);
195 if (http != null) https = await startServer(http);
196 runTest(main, expectations, {Uri root, Uri config}) async {
floitsch 2016/05/18 13:36:32 Please keep one line before and after nested funct
197 var output = await runDart(main, root: root, config: config);
198 // These expectations are default. If not overridden the value will be
199 // expected to be null. That is, you can't avoid testing the actual
200 // value of these, you can only change what value to expect.
201 // For values not included here (commented out), the result is not tested
202 // unless a value (maybe null) is provided.
203 var expects = {
204 "pconf": null,
205 "proot": null,
206 "iconf": null,
207 "iconf": null,
208 // "foo": null,
209 "foo/": null,
210 "foo/bar": null,
211 "foo.x": "qux",
212 }..addAll(expectations);
213 match(JSON.decode(output), expects, name);
214 }
215 // Call test with 1-3 parameters depending on which setups were made.
216 try {
217 if (https == null) {
218 if (files == null) {
219 await test(runTest); // Data-schemes only, no files or http available.
220 } else {
221 await test(runTest, tmpDir.uri);
222 }
223 } else if (files == null) {
224 await test(runTest, serverUri(https));
225 } else {
226 await test(runTest, tmpDir.uri, serverUri(https));
floitsch 2016/05/18 13:36:32 You don't seem to use this case.
Lasse Reichstein Nielsen 2016/05/18 14:01:16 Yet :) I need to have cases where the script is fi
227 }
228 } catch (e) {
229 print("ERROR in $name: $e");
floitsch 2016/05/18 13:36:32 I would rethrow.
Lasse Reichstein Nielsen 2016/05/18 14:01:16 Whoops, left over debug print.
230 } finally {
231 if (https != null) await https.close();
232 if (tmpDir != null) tmpDir.deleteSync(recursive: true);
233 }
234 }
235
236
237
238 /// Test that the output of running testMain matches the expectations.
239 ///
240 /// The output is a string which is parse as a JSON literal.
241 /// The resulting map is always mapping strings to strings, or possibly `null`.
242 /// The expectations can have non-string values other than null,
243 /// they are `toString`'ed before being compared (so the caller can use a URI
244 /// or a File/Directory directly as an expectation).
245 void match(Map actuals, Map expectations, String name) {
246 for (var key in expectations.keys) {
247 var expectation = expectations[key];
248 var actual = actuals[key];
249 if (expectation?.toString() != actual) {
250 print("ERROR: $name: $key: Expected: <$expectation> Found: <$actual>");
251 failingTests.add(name);
252 }
253 }
254 }
255
256 /// Script that prints the current state and the result of resolving
257 /// a few package URIs. This script will be invoked in different settings,
258 /// and the result will be parsed and compared to the expectations.
259 const String testMain = r"""
260 import "dart:convert" show JSON;
261 import "dart:io" show Platform, Directory;
262 import "dart:isolate" show Isolate;
263 import "package:foo/foo.dart" deferred as foo;
264 main(_) async {
265 String platformRoot = await Platform.packageRoot;
266 String platformConfig = await Platform.packageConfig;
267 Directory cwd = Directory.current;
268 Uri script = Platform.script;
269 Uri isolateRoot = await Isolate.packageRoot;
270 Uri isolateConfig = await Isolate.packageConfig;
271 Uri base = Uri.base;
272 Uri res1 = await Isolate.resolvePackageUri(Uri.parse("package:foo"));
273 Uri res2 = await Isolate.resolvePackageUri(Uri.parse("package:foo/"));
274 Uri res3 = await Isolate.resolvePackageUri(Uri.parse("package:foo/bar"));
275 String fooX = await foo
276 .loadLibrary()
277 .timeout(const Duration(seconds: 1))
278 .then((_) => foo.x, onError: (_) => null);
279 print(JSON.encode({
280 "cwd": cwd.path,
281 "base": base?.toString(),
282 "script": script?.toString(),
283 "proot": platformRoot,
284 "pconf": platformConfig,
285 "iroot" : isolateRoot?.toString(),
286 "iconf" : isolateConfig?.toString(),
287 "foo": res1?.toString(),
floitsch 2016/05/18 13:36:32 No need for "?.". Null supports 'toString' too.
Lasse Reichstein Nielsen 2016/05/18 14:01:16 But that would make at the string "null", not the
floitsch 2016/05/19 12:19:23 right.
288 "foo/": res2?.toString(),
289 "foo/bar": res3?.toString(),
290 "foo.x": fooX?.toString(),
291 }));
292 }
293 """;
294
295 /// Script that spawns a new Isolate using Isolate.spawnUri.
296 ///
297 /// Takes URI of target isolate, package config and package root as
298 /// command line arguments. Any further arguments are forwarded to the
299 /// spawned isolate.
300 const String spawnUriMain = r"""
301 import "dart:isolate";
302 main(args) async {
303 Uri target = Uri.parse(args[0]);
304 Uri conf = args.length > 1 && args[1].isNotEmpty ? Uri.parse(args[1]) : null;
305 Uri root = args.length > 2 && args[2].isNotEmpty ? Uri.parse(args[2]) : null;
306 var restArgs = args.skip(3).toList();
307 var isolate = await Isolate.spawnUri(target, restArgs,
308 packageRoot: root, packageConfig: conf, paused: true);
309 // Wait for isolate to exit before exiting the main isolate.
310 var done = new RawReceivePort();
311 done.handler = (_) { done.close(); };
312 isolate.addExitHandler(done.sendPort);
313 isolate.resume(isolate.pauseCapability);
314 }
315 """;
316
317 /// Script that spawns a new Isolate using Isolate.spawn.
318 const String spawnMain = r"""
319 import "dart:isolate";
320 import "testmain.dart" as test;
321 main() async {
322 var isolate = await Isolate.spawn(test.main, [], paused: true);
323 // Wait for isolate to exit before exiting the main isolate.
324 var done = new RawReceivePort();
325 done.handler = (_) { done.close(); };
326 isolate.addExitHandler(done.sendPort);
327 isolate.resume(isolate.pauseCapability);
328 }
329 """;
330
331 /// A package directory containing only one package, "foo", with one file.
332 const Map fooPackage = const { "foo": const { "foo": "var x = 'qux';" }};
333
334 /// Runs the Dart executable with the provided parameters.
335 ///
336 /// Optionally sets CWD before running the script.
337 /// Captures and returns the output.
338 Future<String> runDart(Uri script,
339 {Uri root, Uri config, List<String> scriptArgs}) async {
340 var executable = Platform.executable;
341 var args = [];
342 if (root != null) args..add("-p")..add(root.toString());
343 if (config != null) args..add("--packages=$config");
344 args.add(script.toString());
345 args.addAll(scriptArgs ?? []);
346 return Process.run(executable, args).then((results) {
347 if (results.exitCode != 0) {
348 throw results.stderr;
349 }
350 return results.stdout;
351 });
352 }
353
354 /// Creates a temporary directory and a number of files and subdirectories.
355 ///
356 /// The [content] is the content of the directory itself. The map keys are
357 /// names and the values are either strings that represent Dart file contents
358 /// or maps that represent subdirectories.
359 /// Subdirectories may include a package directory. If [packageDir]
360 /// is provided, a `.packages` file is created for the content of that
361 /// directory.
362 Directory createFiles(Map content,
363 [String packageDir]) {
364 Directory createDir(Directory base, String name) {
floitsch 2016/05/18 13:36:32 New lines before and after nested functions.
365 Directory newDir = new Directory(p.join(base.path, name));
366 newDir.createSync();
367 return newDir;
368 }
369 void createTextFile(Directory base, String name, String content) {
370 File newFile = new File(p.join(base.path, name));
371 newFile.writeAsStringSync(content);
372 }
373 void create(Directory dir, Map map) {
374 for (var name in map.keys) {
375 var content = map[name];
376 if (content is String) {
377 // If the name starts with "." it's a .packages file, otherwise it's
378 // a dart file. Those are the only files we care about in this test.
379 createTextFile(dir,
380 name.startsWith(".") ? name : name + ".dart",
381 content);
382 } else {
383 var subdir = createDir(dir, name);
384 create(subdir, content);
385 }
386 }
387 }
388 var tempDir = Directory.systemTemp.createTempSync("pftest-${tmpDirCounter++}-" );
floitsch 2016/05/18 13:36:32 long line.
389 create(tempDir, content);
390 if (packageDir != null) {
391 Map packages = content[packageDir];
392 var entries =
393 packages.keys.map((key) => "$key:$packageDir/$key").join("\n");
394 createTextFile(tempDir, ".packages", entries);
395 }
396 return tempDir;
397 }
398
399 // Counter used to avoid reusing temporary directory names.
400 int tmpDirCounter = 0;
401
402 Future<HttpServer> startServer(Map files) async {
403 return (await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 0))
404 ..forEach((request) {
405 var result = files;
406 onFailure: {
407 for (var part in request.uri.pathSegments) {
408 if (part.endsWith(".dart")) {
409 part = part.substring(0, part.length - 5);
410 }
411 if (result is Map) {
412 result = result[part];
413 } else {
414 break onFailure;
415 }
416 }
417 if (result is String) {
418 request.response..write(result)
419 ..close();
420 return;
421 }
422 }
423 request.response..statusCode = HttpStatus.NOT_FOUND
424 ..close();
425 });
426 }
427
428 Uri serverUri(HttpServer server) =>
429 new Uri(scheme: "http",
430 host: server.address.address,
431 port: server.port,
432 path: "/");
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698