OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, 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 library pubspec_test; | |
6 | |
7 import 'dart:async'; | |
8 | |
9 import 'package:pub_semver/pub_semver.dart'; | |
10 import 'package:unittest/unittest.dart'; | |
11 | |
12 import '../lib/src/package.dart'; | |
13 import '../lib/src/pubspec.dart'; | |
14 import '../lib/src/source.dart'; | |
15 import '../lib/src/source/path.dart'; | |
16 import '../lib/src/source_registry.dart'; | |
17 import 'test_pub.dart'; | |
18 | |
19 class MockSource extends Source { | |
20 final String name = "mock"; | |
21 | |
22 Future<Pubspec> doDescribe(PackageId id) => throw new UnsupportedError( | |
23 "Cannot describe mock packages."); | |
24 | |
25 Future get(PackageId id, String symlink) => throw new UnsupportedError( | |
26 "Cannot get a mock package."); | |
27 | |
28 Future<String> getDirectory(PackageId id) => throw new UnsupportedError( | |
29 "Cannot get the directory for mock packages."); | |
30 | |
31 dynamic parseDescription(String filePath, description, | |
32 {bool fromLockFile: false}) { | |
33 if (description != 'ok') throw new FormatException('Bad'); | |
34 return description; | |
35 } | |
36 | |
37 bool descriptionsEqual(description1, description2) => | |
38 description1 == description2; | |
39 | |
40 String packageName(description) => 'foo'; | |
41 } | |
42 | |
43 main() { | |
44 initConfig(); | |
45 group('parse()', () { | |
46 var sources = new SourceRegistry(); | |
47 sources.register(new MockSource()); | |
48 sources.register(new PathSource()); | |
49 | |
50 var throwsPubspecException = | |
51 throwsA(new isInstanceOf<PubspecException>('PubspecException')); | |
52 | |
53 expectPubspecException(String contents, fn(Pubspec pubspec), | |
54 [String expectedContains]) { | |
55 var expectation = throwsPubspecException; | |
56 if (expectedContains != null) { | |
57 expectation = throwsA(allOf( | |
58 new isInstanceOf<PubspecException>('PubspecException'), | |
59 predicate((error) => error.message.contains(expectedContains)))); | |
60 } | |
61 | |
62 var pubspec = new Pubspec.parse(contents, sources); | |
63 expect(() => fn(pubspec), expectation); | |
64 } | |
65 | |
66 test("doesn't eagerly throw an error for an invalid field", () { | |
67 // Shouldn't throw an error. | |
68 new Pubspec.parse('version: not a semver', sources); | |
69 }); | |
70 | |
71 test("eagerly throws an error if the pubspec name doesn't match the " | |
72 "expected name", () { | |
73 expect(() => new Pubspec.parse("name: foo", sources, expectedName: 'bar'), | |
74 throwsPubspecException); | |
75 }); | |
76 | |
77 test("eagerly throws an error if the pubspec doesn't have a name and an " | |
78 "expected name is passed", () { | |
79 expect(() => new Pubspec.parse("{}", sources, expectedName: 'bar'), | |
80 throwsPubspecException); | |
81 }); | |
82 | |
83 test("allows a version constraint for dependencies", () { | |
84 var pubspec = new Pubspec.parse(''' | |
85 dependencies: | |
86 foo: | |
87 mock: ok | |
88 version: ">=1.2.3 <3.4.5" | |
89 ''', sources); | |
90 | |
91 var foo = pubspec.dependencies[0]; | |
92 expect(foo.name, equals('foo')); | |
93 expect(foo.constraint.allows(new Version(1, 2, 3)), isTrue); | |
94 expect(foo.constraint.allows(new Version(1, 2, 5)), isTrue); | |
95 expect(foo.constraint.allows(new Version(3, 4, 5)), isFalse); | |
96 }); | |
97 | |
98 test("allows an empty dependencies map", () { | |
99 var pubspec = new Pubspec.parse(''' | |
100 dependencies: | |
101 ''', sources); | |
102 | |
103 expect(pubspec.dependencies, isEmpty); | |
104 }); | |
105 | |
106 test("allows a version constraint for dev dependencies", () { | |
107 var pubspec = new Pubspec.parse(''' | |
108 dev_dependencies: | |
109 foo: | |
110 mock: ok | |
111 version: ">=1.2.3 <3.4.5" | |
112 ''', sources); | |
113 | |
114 var foo = pubspec.devDependencies[0]; | |
115 expect(foo.name, equals('foo')); | |
116 expect(foo.constraint.allows(new Version(1, 2, 3)), isTrue); | |
117 expect(foo.constraint.allows(new Version(1, 2, 5)), isTrue); | |
118 expect(foo.constraint.allows(new Version(3, 4, 5)), isFalse); | |
119 }); | |
120 | |
121 test("allows an empty dev dependencies map", () { | |
122 var pubspec = new Pubspec.parse(''' | |
123 dev_dependencies: | |
124 ''', sources); | |
125 | |
126 expect(pubspec.devDependencies, isEmpty); | |
127 }); | |
128 | |
129 test("allows a version constraint for dependency overrides", () { | |
130 var pubspec = new Pubspec.parse(''' | |
131 dependency_overrides: | |
132 foo: | |
133 mock: ok | |
134 version: ">=1.2.3 <3.4.5" | |
135 ''', sources); | |
136 | |
137 var foo = pubspec.dependencyOverrides[0]; | |
138 expect(foo.name, equals('foo')); | |
139 expect(foo.constraint.allows(new Version(1, 2, 3)), isTrue); | |
140 expect(foo.constraint.allows(new Version(1, 2, 5)), isTrue); | |
141 expect(foo.constraint.allows(new Version(3, 4, 5)), isFalse); | |
142 }); | |
143 | |
144 test("allows an empty dependency overrides map", () { | |
145 var pubspec = new Pubspec.parse(''' | |
146 dependency_overrides: | |
147 ''', sources); | |
148 | |
149 expect(pubspec.dependencyOverrides, isEmpty); | |
150 }); | |
151 | |
152 test("allows an unknown source", () { | |
153 var pubspec = new Pubspec.parse(''' | |
154 dependencies: | |
155 foo: | |
156 unknown: blah | |
157 ''', sources); | |
158 | |
159 var foo = pubspec.dependencies[0]; | |
160 expect(foo.name, equals('foo')); | |
161 expect(foo.source, equals('unknown')); | |
162 }); | |
163 | |
164 test("throws if a package is in dependencies and dev_dependencies", () { | |
165 expectPubspecException(''' | |
166 dependencies: | |
167 foo: | |
168 mock: ok | |
169 dev_dependencies: | |
170 foo: | |
171 mock: ok | |
172 ''', (pubspec) { | |
173 // This check only triggers if both [dependencies] and [devDependencies] | |
174 // are accessed. | |
175 pubspec.dependencies; | |
176 pubspec.devDependencies; | |
177 }); | |
178 }); | |
179 | |
180 test("throws if it dependes on itself", () { | |
181 expectPubspecException(''' | |
182 name: myapp | |
183 dependencies: | |
184 myapp: | |
185 mock: ok | |
186 ''', (pubspec) => pubspec.dependencies); | |
187 }); | |
188 | |
189 test("throws if it has a dev dependency on itself", () { | |
190 expectPubspecException(''' | |
191 name: myapp | |
192 dev_dependencies: | |
193 myapp: | |
194 mock: ok | |
195 ''', (pubspec) => pubspec.devDependencies); | |
196 }); | |
197 | |
198 test("throws if it has an override on itself", () { | |
199 expectPubspecException(''' | |
200 name: myapp | |
201 dependency_overrides: | |
202 myapp: | |
203 mock: ok | |
204 ''', (pubspec) => pubspec.dependencyOverrides); | |
205 }); | |
206 | |
207 test("throws if the description isn't valid", () { | |
208 expectPubspecException(''' | |
209 dependencies: | |
210 foo: | |
211 mock: bad | |
212 ''', (pubspec) => pubspec.dependencies); | |
213 }); | |
214 | |
215 test("throws if dependency version is not a string", () { | |
216 expectPubspecException(''' | |
217 dependencies: | |
218 foo: | |
219 mock: ok | |
220 version: 1.2 | |
221 ''', (pubspec) => pubspec.dependencies); | |
222 }); | |
223 | |
224 test("throws if version is not a version constraint", () { | |
225 expectPubspecException(''' | |
226 dependencies: | |
227 foo: | |
228 mock: ok | |
229 version: not constraint | |
230 ''', (pubspec) => pubspec.dependencies); | |
231 }); | |
232 | |
233 test("throws if 'name' is not a string", () { | |
234 expectPubspecException('name: [not, a, string]', | |
235 (pubspec) => pubspec.name); | |
236 }); | |
237 | |
238 test("throws if version is not a string", () { | |
239 expectPubspecException('version: [2, 0, 0]', | |
240 (pubspec) => pubspec.version, | |
241 '"version" field must be a string'); | |
242 }); | |
243 | |
244 test("throws if version is malformed (looking like a double)", () { | |
245 expectPubspecException('version: 2.1', | |
246 (pubspec) => pubspec.version, | |
247 '"version" field must have three numeric components: major, minor, ' | |
248 'and patch. Instead of "2.1", consider "2.1.0"'); | |
249 }); | |
250 | |
251 test("throws if version is malformed (looking like an int)", () { | |
252 expectPubspecException('version: 2', | |
253 (pubspec) => pubspec.version, | |
254 '"version" field must have three numeric components: major, minor, ' | |
255 'and patch. Instead of "2", consider "2.0.0"'); | |
256 }); | |
257 | |
258 test("throws if version is not a version", () { | |
259 expectPubspecException('version: not version', | |
260 (pubspec) => pubspec.version); | |
261 }); | |
262 | |
263 test("throws if transformers isn't a list", () { | |
264 expectPubspecException('transformers: "not list"', | |
265 (pubspec) => pubspec.transformers, | |
266 '"transformers" field must be a list'); | |
267 }); | |
268 | |
269 test("throws if a transformer isn't a string or map", () { | |
270 expectPubspecException('transformers: [12]', | |
271 (pubspec) => pubspec.transformers, | |
272 'A transformer must be a string or map.'); | |
273 }); | |
274 | |
275 test("throws if a transformer's configuration isn't a map", () { | |
276 expectPubspecException('transformers: [{pkg: 12}]', | |
277 (pubspec) => pubspec.transformers, | |
278 "A transformer's configuration must be a map."); | |
279 }); | |
280 | |
281 test("throws if a transformer's configuration contains an unknown " | |
282 "reserved key at the top level", () { | |
283 expectPubspecException(''' | |
284 name: pkg | |
285 transformers: [{pkg: {\$key: "value"}}]''', | |
286 (pubspec) => pubspec.transformers, | |
287 'Invalid transformer config: Unknown reserved field.'); | |
288 }); | |
289 | |
290 test("doesn't throw if a transformer's configuration contains a " | |
291 "non-top-level key beginning with a dollar sign", () { | |
292 var pubspec = new Pubspec.parse(''' | |
293 name: pkg | |
294 transformers: | |
295 - pkg: {outer: {\$inner: value}} | |
296 ''', sources); | |
297 | |
298 var pkg = pubspec.transformers[0].single; | |
299 expect(pkg.configuration["outer"]["\$inner"], equals("value")); | |
300 }); | |
301 | |
302 test("throws if the \$include value is not a string or list", () { | |
303 expectPubspecException(''' | |
304 name: pkg | |
305 transformers: | |
306 - pkg: {\$include: 123}''', | |
307 (pubspec) => pubspec.transformers, | |
308 'Invalid transformer config: "\$include" field must be a string or ' | |
309 'list.'); | |
310 }); | |
311 | |
312 test("throws if the \$include list contains a non-string", () { | |
313 expectPubspecException(''' | |
314 name: pkg | |
315 transformers: | |
316 - pkg: {\$include: ["ok", 123, "alright", null]}''', | |
317 (pubspec) => pubspec.transformers, | |
318 'Invalid transformer config: "\$include" field may contain only ' | |
319 'strings.'); | |
320 }); | |
321 | |
322 test("throws if the \$exclude value is not a string or list", () { | |
323 expectPubspecException(''' | |
324 name: pkg | |
325 transformers: | |
326 - pkg: {\$exclude: 123}''', | |
327 (pubspec) => pubspec.transformers, | |
328 'Invalid transformer config: "\$exclude" field must be a string or ' | |
329 'list.'); | |
330 }); | |
331 | |
332 test("throws if the \$exclude list contains a non-string", () { | |
333 expectPubspecException(''' | |
334 name: pkg | |
335 transformers: | |
336 - pkg: {\$exclude: ["ok", 123, "alright", null]}''', | |
337 (pubspec) => pubspec.transformers, | |
338 'Invalid transformer config: "\$exclude" field may contain only ' | |
339 'strings.'); | |
340 }); | |
341 | |
342 test("throws if a transformer is not from a dependency", () { | |
343 expectPubspecException(''' | |
344 name: pkg | |
345 transformers: [foo] | |
346 ''', | |
347 (pubspec) => pubspec.transformers, | |
348 '"foo" is not a dependency.'); | |
349 }); | |
350 | |
351 test("allows a transformer from a normal dependency", () { | |
352 var pubspec = new Pubspec.parse(''' | |
353 name: pkg | |
354 dependencies: | |
355 foo: | |
356 mock: ok | |
357 transformers: | |
358 - foo''', sources); | |
359 | |
360 expect(pubspec.transformers[0].single.id.package, equals("foo")); | |
361 }); | |
362 | |
363 test("allows a transformer from a dev dependency", () { | |
364 var pubspec = new Pubspec.parse(''' | |
365 name: pkg | |
366 dev_dependencies: | |
367 foo: | |
368 mock: ok | |
369 transformers: | |
370 - foo''', sources); | |
371 | |
372 expect(pubspec.transformers[0].single.id.package, equals("foo")); | |
373 }); | |
374 | |
375 test("allows a transformer from a dependency override", () { | |
376 var pubspec = new Pubspec.parse(''' | |
377 name: pkg | |
378 dependency_overrides: | |
379 foo: | |
380 mock: ok | |
381 transformers: | |
382 - foo''', sources); | |
383 | |
384 expect(pubspec.transformers[0].single.id.package, equals("foo")); | |
385 }); | |
386 | |
387 test("allows comment-only files", () { | |
388 var pubspec = new Pubspec.parse(''' | |
389 # No external dependencies yet | |
390 # Including for completeness | |
391 # ...and hoping the spec expands to include details about author, version, etc | |
392 # See http://www.dartlang.org/docs/pub-package-manager/ for details | |
393 ''', sources); | |
394 expect(pubspec.version, equals(Version.none)); | |
395 expect(pubspec.dependencies, isEmpty); | |
396 }); | |
397 | |
398 test("throws a useful error for unresolvable path dependencies", () { | |
399 expectPubspecException(''' | |
400 name: pkg | |
401 dependencies: | |
402 from_path: {path: non_local_path} | |
403 ''', (pubspec) => pubspec.dependencies, | |
404 '"non_local_path" is a relative path, but this isn\'t a local ' | |
405 'pubspec.'); | |
406 }); | |
407 | |
408 group("environment", () { | |
409 test("defaults to any SDK constraint if environment is omitted", () { | |
410 var pubspec = new Pubspec.parse('', sources); | |
411 expect(pubspec.environment.sdkVersion, equals(VersionConstraint.any)); | |
412 }); | |
413 | |
414 test("allows an empty environment map", () { | |
415 var pubspec = new Pubspec.parse(''' | |
416 environment: | |
417 ''', sources); | |
418 expect(pubspec.environment.sdkVersion, equals(VersionConstraint.any)); | |
419 }); | |
420 | |
421 test("throws if the environment value isn't a map", () { | |
422 expectPubspecException('environment: []', | |
423 (pubspec) => pubspec.environment); | |
424 }); | |
425 | |
426 test("allows a version constraint for the sdk", () { | |
427 var pubspec = new Pubspec.parse(''' | |
428 environment: | |
429 sdk: ">=1.2.3 <2.3.4" | |
430 ''', sources); | |
431 expect(pubspec.environment.sdkVersion, | |
432 equals(new VersionConstraint.parse(">=1.2.3 <2.3.4"))); | |
433 }); | |
434 | |
435 test("throws if the sdk isn't a string", () { | |
436 expectPubspecException('environment: {sdk: []}', | |
437 (pubspec) => pubspec.environment); | |
438 expectPubspecException('environment: {sdk: 1.0}', | |
439 (pubspec) => pubspec.environment); | |
440 }); | |
441 | |
442 test("throws if the sdk isn't a valid version constraint", () { | |
443 expectPubspecException('environment: {sdk: "oopies"}', | |
444 (pubspec) => pubspec.environment); | |
445 }); | |
446 }); | |
447 | |
448 group("publishTo", () { | |
449 test("defaults to null if omitted", () { | |
450 var pubspec = new Pubspec.parse('', sources); | |
451 expect(pubspec.publishTo, isNull); | |
452 }); | |
453 | |
454 test("throws if not a string", () { | |
455 expectPubspecException('publish_to: 123', | |
456 (pubspec) => pubspec.publishTo); | |
457 }); | |
458 | |
459 test("allows a URL", () { | |
460 var pubspec = new Pubspec.parse(''' | |
461 publish_to: http://example.com | |
462 ''', sources); | |
463 expect(pubspec.publishTo, equals("http://example.com")); | |
464 }); | |
465 | |
466 test("allows none", () { | |
467 var pubspec = new Pubspec.parse(''' | |
468 publish_to: none | |
469 ''', sources); | |
470 expect(pubspec.publishTo, equals("none")); | |
471 }); | |
472 | |
473 test("throws on other strings", () { | |
474 expectPubspecException('publish_to: http://bad.url:not-port', | |
475 (pubspec) => pubspec.publishTo); | |
476 }); | |
477 }); | |
478 | |
479 group("executables", () { | |
480 test("defaults to an empty map if omitted", () { | |
481 var pubspec = new Pubspec.parse('', sources); | |
482 expect(pubspec.executables, isEmpty); | |
483 }); | |
484 | |
485 test("allows simple names for keys and most characters in values", () { | |
486 var pubspec = new Pubspec.parse(''' | |
487 executables: | |
488 abcDEF-123_: "abc DEF-123._" | |
489 ''', sources); | |
490 expect(pubspec.executables['abcDEF-123_'], equals('abc DEF-123._')); | |
491 }); | |
492 | |
493 test("throws if not a map", () { | |
494 expectPubspecException('executables: not map', | |
495 (pubspec) => pubspec.executables); | |
496 }); | |
497 | |
498 test("throws if key is not a string", () { | |
499 expectPubspecException('executables: {123: value}', | |
500 (pubspec) => pubspec.executables); | |
501 }); | |
502 | |
503 test("throws if a key isn't a simple name", () { | |
504 expectPubspecException('executables: {funny/name: ok}', | |
505 (pubspec) => pubspec.executables); | |
506 }); | |
507 | |
508 test("throws if a value is not a string", () { | |
509 expectPubspecException('executables: {command: 123}', | |
510 (pubspec) => pubspec.executables); | |
511 }); | |
512 | |
513 test("throws if a value contains a path separator", () { | |
514 expectPubspecException('executables: {command: funny_name/part}', | |
515 (pubspec) => pubspec.executables); | |
516 }); | |
517 | |
518 test("throws if a value contains a windows path separator", () { | |
519 expectPubspecException(r'executables: {command: funny_name\part}', | |
520 (pubspec) => pubspec.executables); | |
521 }); | |
522 | |
523 test("uses the key if the value is null", () { | |
524 var pubspec = new Pubspec.parse(''' | |
525 executables: | |
526 command: | |
527 ''', sources); | |
528 expect(pubspec.executables['command'], equals('command')); | |
529 }); | |
530 }); | |
531 }); | |
532 } | |
OLD | NEW |