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