| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library validator_test; | 5 library validator_test; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:io'; | 8 import 'dart:io'; |
| 9 import 'dart:json' as json; | 9 import 'dart:json' as json; |
| 10 import 'dart:math' as math; | 10 import 'dart:math' as math; |
| 11 | 11 |
| 12 import 'test_pub.dart'; | 12 import 'test_pub.dart'; |
| 13 import '../../../pkg/unittest/lib/unittest.dart'; | |
| 14 import '../../../pkg/http/lib/http.dart' as http; | 13 import '../../../pkg/http/lib/http.dart' as http; |
| 15 import '../../../pkg/http/lib/testing.dart'; | 14 import '../../../pkg/http/lib/testing.dart'; |
| 15 import '../../../pkg/path/lib/path.dart' as path; |
| 16 import '../../../pkg/unittest/lib/unittest.dart'; |
| 16 import '../../pub/entrypoint.dart'; | 17 import '../../pub/entrypoint.dart'; |
| 17 import '../../pub/io.dart'; | 18 import '../../pub/io.dart'; |
| 18 import '../../pub/validator.dart'; | 19 import '../../pub/validator.dart'; |
| 19 import '../../pub/validator/compiled_dartdoc.dart'; | 20 import '../../pub/validator/compiled_dartdoc.dart'; |
| 20 import '../../pub/validator/dependency.dart'; | 21 import '../../pub/validator/dependency.dart'; |
| 21 import '../../pub/validator/directory.dart'; | 22 import '../../pub/validator/directory.dart'; |
| 22 import '../../pub/validator/lib.dart'; | 23 import '../../pub/validator/lib.dart'; |
| 23 import '../../pub/validator/license.dart'; | 24 import '../../pub/validator/license.dart'; |
| 24 import '../../pub/validator/name.dart'; | 25 import '../../pub/validator/name.dart'; |
| 25 import '../../pub/validator/pubspec_field.dart'; | 26 import '../../pub/validator/pubspec_field.dart'; |
| 26 import '../../pub/validator/size.dart'; | 27 import '../../pub/validator/size.dart'; |
| 27 import '../../pub/validator/utf8_readme.dart'; | 28 import '../../pub/validator/utf8_readme.dart'; |
| 28 | 29 |
| 29 void expectNoValidationError(ValidatorCreator fn) { | 30 void expectNoValidationError(ValidatorCreator fn) { |
| 30 expectLater(schedulePackageValidation(fn), pairOf(isEmpty, isEmpty)); | 31 expectLater(schedulePackageValidation(fn), pairOf(isEmpty, isEmpty)); |
| 31 } | 32 } |
| 32 | 33 |
| 33 void expectValidationError(ValidatorCreator fn) { | 34 void expectValidationError(ValidatorCreator fn) { |
| 34 expectLater(schedulePackageValidation(fn), pairOf(isNot(isEmpty), anything)); | 35 expectLater(schedulePackageValidation(fn), pairOf(isNot(isEmpty), anything)); |
| 35 } | 36 } |
| 36 | 37 |
| 37 void expectValidationWarning(ValidatorCreator fn) { | 38 void expectValidationWarning(ValidatorCreator fn) { |
| 38 expectLater(schedulePackageValidation(fn), pairOf(isEmpty, isNot(isEmpty))); | 39 expectLater(schedulePackageValidation(fn), pairOf(isEmpty, isNot(isEmpty))); |
| 39 } | 40 } |
| 40 | 41 |
| 42 expectDependencyValidationError(String error) { |
| 43 expectLater(schedulePackageValidation(dependency), |
| 44 pairOf(someElement(contains(error)), isEmpty)); |
| 45 } |
| 46 |
| 47 expectDependencyValidationWarning(String warning) { |
| 48 expectLater(schedulePackageValidation(dependency), |
| 49 pairOf(isEmpty, someElement(contains(warning)))); |
| 50 } |
| 51 |
| 41 Validator compiledDartdoc(Entrypoint entrypoint) => | 52 Validator compiledDartdoc(Entrypoint entrypoint) => |
| 42 new CompiledDartdocValidator(entrypoint); | 53 new CompiledDartdocValidator(entrypoint); |
| 43 | 54 |
| 44 Validator dependency(Entrypoint entrypoint) => | 55 Validator dependency(Entrypoint entrypoint) => |
| 45 new DependencyValidator(entrypoint); | 56 new DependencyValidator(entrypoint); |
| 46 | 57 |
| 47 Validator directory(Entrypoint entrypoint) => | 58 Validator directory(Entrypoint entrypoint) => |
| 48 new DirectoryValidator(entrypoint); | 59 new DirectoryValidator(entrypoint); |
| 49 | 60 |
| 50 Validator lib(Entrypoint entrypoint) => new LibValidator(entrypoint); | 61 Validator lib(Entrypoint entrypoint) => new LibValidator(entrypoint); |
| 51 | 62 |
| 52 Validator license(Entrypoint entrypoint) => new LicenseValidator(entrypoint); | 63 Validator license(Entrypoint entrypoint) => new LicenseValidator(entrypoint); |
| 53 | 64 |
| 54 Validator name(Entrypoint entrypoint) => new NameValidator(entrypoint); | 65 Validator name(Entrypoint entrypoint) => new NameValidator(entrypoint); |
| 55 | 66 |
| 56 Validator pubspecField(Entrypoint entrypoint) => | 67 Validator pubspecField(Entrypoint entrypoint) => |
| 57 new PubspecFieldValidator(entrypoint); | 68 new PubspecFieldValidator(entrypoint); |
| 58 | 69 |
| 59 Function size(int size) { | 70 Function size(int size) { |
| 60 return (entrypoint) => | 71 return (entrypoint) => |
| 61 new SizeValidator(entrypoint, new Future.immediate(size)); | 72 new SizeValidator(entrypoint, new Future.immediate(size)); |
| 62 } | 73 } |
| 63 | 74 |
| 64 Validator utf8Readme(Entrypoint entrypoint) => | 75 Validator utf8Readme(Entrypoint entrypoint) => |
| 65 new Utf8ReadmeValidator(entrypoint); | 76 new Utf8ReadmeValidator(entrypoint); |
| 66 | 77 |
| 67 void scheduleNormalPackage() => normalPackage.scheduleCreate(); | 78 void scheduleNormalPackage() => normalPackage.scheduleCreate(); |
| 68 | 79 |
| 80 /// Sets up a test package with dependency [dep] and mocks a server with |
| 81 /// [hostedVersions] of the package available. |
| 82 setUpDependency(Map dep, {List<String> hostedVersions}) { |
| 83 useMockClient(new MockClient((request) { |
| 84 expect(request.method, equals("GET")); |
| 85 expect(request.url.path, equals("/packages/foo.json")); |
| 86 |
| 87 if (hostedVersions == null) { |
| 88 return new Future.immediate(new http.Response("not found", 404)); |
| 89 } else { |
| 90 return new Future.immediate(new http.Response(json.stringify({ |
| 91 "name": "foo", |
| 92 "uploaders": ["nweiz@google.com"], |
| 93 "versions": hostedVersions |
| 94 }), 200)); |
| 95 } |
| 96 })); |
| 97 |
| 98 dir(appPath, [ |
| 99 libPubspec("test_pkg", "1.0.0", deps: [dep]) |
| 100 ]).scheduleCreate(); |
| 101 } |
| 102 |
| 69 main() { | 103 main() { |
| 104 initConfig(); |
| 70 group('should consider a package valid if it', () { | 105 group('should consider a package valid if it', () { |
| 71 setUp(scheduleNormalPackage); | 106 setUp(scheduleNormalPackage); |
| 72 | 107 |
| 73 integration('looks normal', () { | 108 integration('looks normal', () { |
| 74 dir(appPath, [libPubspec("test_pkg", "1.0.0")]).scheduleCreate(); | 109 dir(appPath, [libPubspec("test_pkg", "1.0.0")]).scheduleCreate(); |
| 75 expectNoValidationError(dependency); | 110 expectNoValidationError(dependency); |
| 76 expectNoValidationError(lib); | 111 expectNoValidationError(lib); |
| 77 expectNoValidationError(license); | 112 expectNoValidationError(license); |
| 78 expectNoValidationError(name); | 113 expectNoValidationError(name); |
| 79 expectNoValidationError(pubspecField); | 114 expectNoValidationError(pubspecField); |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 319 integration('has a lib directory containing only src', () { | 354 integration('has a lib directory containing only src', () { |
| 320 file(join(appPath, "lib", "test_pkg.dart"), '').scheduleDelete(); | 355 file(join(appPath, "lib", "test_pkg.dart"), '').scheduleDelete(); |
| 321 dir(appPath, [ | 356 dir(appPath, [ |
| 322 dir("lib", [ | 357 dir("lib", [ |
| 323 dir("src", [file("test_pkg.dart", "int i = 0;")]) | 358 dir("src", [file("test_pkg.dart", "int i = 0;")]) |
| 324 ]) | 359 ]) |
| 325 ]).scheduleCreate(); | 360 ]).scheduleCreate(); |
| 326 expectValidationError(lib); | 361 expectValidationError(lib); |
| 327 }); | 362 }); |
| 328 | 363 |
| 329 group('has a dependency with a non-hosted source', () { | 364 group('has a git dependency', () { |
| 330 group('where a hosted version of that dependency exists', () { | 365 group('where a hosted version exists', () { |
| 331 integration("and should suggest the hosted package's primary " | 366 integration("and should suggest the hosted primary version", () { |
| 332 "version", () { | 367 setUpDependency({'git': 'git://github.com/dart-lang/foo'}, |
| 333 useMockClient(new MockClient((request) { | 368 hostedVersions: ["3.0.0-pre", "2.0.0", "1.0.0"]); |
| 334 expect(request.method, equals("GET")); | 369 expectDependencyValidationWarning(' foo: ">=2.0.0 <3.0.0"'); |
| 335 expect(request.url.path, equals("/packages/foo.json")); | |
| 336 | |
| 337 return new Future.immediate(new http.Response(json.stringify({ | |
| 338 "name": "foo", | |
| 339 "uploaders": ["nweiz@google.com"], | |
| 340 "versions": ["3.0.0-pre", "2.0.0", "1.0.0"] | |
| 341 }), 200)); | |
| 342 })); | |
| 343 | |
| 344 dir(appPath, [ | |
| 345 libPubspec("test_pkg", "1.0.0", deps: [ | |
| 346 {'git': 'git://github.com/dart-lang/foo'} | |
| 347 ]) | |
| 348 ]).scheduleCreate(); | |
| 349 | |
| 350 expectLater(schedulePackageValidation(dependency), | |
| 351 pairOf(isEmpty, someElement(contains( | |
| 352 ' foo: ">=2.0.0 <3.0.0"')))); | |
| 353 }); | 370 }); |
| 354 | 371 |
| 355 integration("and should suggest the hosted package's prerelease " | 372 integration("and should suggest the hosted prerelease version if " |
| 356 "version if it's the only version available", () { | 373 "it's the only version available", () { |
| 357 useMockClient(new MockClient((request) { | 374 setUpDependency({'git': 'git://github.com/dart-lang/foo'}, |
| 358 expect(request.method, equals("GET")); | 375 hostedVersions: ["3.0.0-pre", "2.0.0-pre"]); |
| 359 expect(request.url.path, equals("/packages/foo.json")); | 376 expectDependencyValidationWarning(' foo: ">=3.0.0-pre <4.0.0"'); |
| 360 | |
| 361 return new Future.immediate(new http.Response(json.stringify({ | |
| 362 "name": "foo", | |
| 363 "uploaders": ["nweiz@google.com"], | |
| 364 "versions": ["3.0.0-pre", "2.0.0-pre"] | |
| 365 }), 200)); | |
| 366 })); | |
| 367 | |
| 368 dir(appPath, [ | |
| 369 libPubspec("test_pkg", "1.0.0", deps: [ | |
| 370 {'git': 'git://github.com/dart-lang/foo'} | |
| 371 ]) | |
| 372 ]).scheduleCreate(); | |
| 373 | |
| 374 expectLater(schedulePackageValidation(dependency), | |
| 375 pairOf(isEmpty, someElement(contains( | |
| 376 ' foo: ">=3.0.0-pre <4.0.0"')))); | |
| 377 }); | 377 }); |
| 378 | 378 |
| 379 integration("and should suggest a tighter constraint if the primary " | 379 integration("and should suggest a tighter constraint if primary is " |
| 380 "version is pre-1.0.0", () { | 380 "pre-1.0.0", () { |
| 381 useMockClient(new MockClient((request) { | 381 setUpDependency({'git': 'git://github.com/dart-lang/foo'}, |
| 382 expect(request.method, equals("GET")); | 382 hostedVersions: ["0.0.1", "0.0.2"]); |
| 383 expect(request.url.path, equals("/packages/foo.json")); | 383 expectDependencyValidationWarning(' foo: ">=0.0.2 <0.0.3"'); |
| 384 | |
| 385 return new Future.immediate(new http.Response(json.stringify({ | |
| 386 "name": "foo", | |
| 387 "uploaders": ["nweiz@google.com"], | |
| 388 "versions": ["0.0.1", "0.0.2"] | |
| 389 }), 200)); | |
| 390 })); | |
| 391 | |
| 392 dir(appPath, [ | |
| 393 libPubspec("test_pkg", "1.0.0", deps: [ | |
| 394 {'git': 'git://github.com/dart-lang/foo'} | |
| 395 ]) | |
| 396 ]).scheduleCreate(); | |
| 397 | |
| 398 expectLater(schedulePackageValidation(dependency), | |
| 399 pairOf(isEmpty, someElement(contains( | |
| 400 ' foo: ">=0.0.2 <0.0.3"')))); | |
| 401 }); | 384 }); |
| 402 }); | 385 }); |
| 403 | 386 |
| 404 group('where no hosted version of that dependency exists', () { | 387 group('where no hosted version exists', () { |
| 405 integration("and should use the other source's version", () { | 388 integration("and should use the other source's version", () { |
| 406 useMockClient(new MockClient((request) { | 389 setUpDependency({ |
| 407 expect(request.method, equals("GET")); | 390 'git': 'git://github.com/dart-lang/foo', |
| 408 expect(request.url.path, equals("/packages/foo.json")); | 391 'version': '>=1.0.0 <2.0.0' |
| 409 | 392 }); |
| 410 return new Future.immediate(new http.Response("not found", 404)); | 393 expectDependencyValidationWarning(' foo: ">=1.0.0 <2.0.0"'); |
| 411 })); | |
| 412 | |
| 413 dir(appPath, [ | |
| 414 libPubspec("test_pkg", "1.0.0", deps: [ | |
| 415 { | |
| 416 'git': {'url': 'git://github.com/dart-lang/foo'}, | |
| 417 'version': '>=1.0.0 <2.0.0' | |
| 418 } | |
| 419 ]) | |
| 420 ]).scheduleCreate(); | |
| 421 | |
| 422 expectLater(schedulePackageValidation(dependency), | |
| 423 pairOf(isEmpty, someElement(contains( | |
| 424 ' foo: ">=1.0.0 <2.0.0"')))); | |
| 425 }); | 394 }); |
| 426 | 395 |
| 427 integration("and should use the other source's unquoted version if " | 396 integration("and should use the other source's unquoted version if " |
| 428 "it's concrete", () { | 397 "concrete", () { |
| 429 useMockClient(new MockClient((request) { | 398 setUpDependency({ |
| 430 expect(request.method, equals("GET")); | 399 'git': 'git://github.com/dart-lang/foo', |
| 431 expect(request.url.path, equals("/packages/foo.json")); | 400 'version': '0.2.3' |
| 432 | 401 }); |
| 433 return new Future.immediate(new http.Response("not found", 404)); | 402 expectDependencyValidationWarning(' foo: 0.2.3'); |
| 434 })); | |
| 435 | |
| 436 dir(appPath, [ | |
| 437 libPubspec("test_pkg", "1.0.0", deps: [ | |
| 438 { | |
| 439 'git': {'url': 'git://github.com/dart-lang/foo'}, | |
| 440 'version': '0.2.3' | |
| 441 } | |
| 442 ]) | |
| 443 ]).scheduleCreate(); | |
| 444 | |
| 445 expectLater(schedulePackageValidation(dependency), | |
| 446 pairOf(isEmpty, someElement(contains(' foo: 0.2.3')))); | |
| 447 }); | 403 }); |
| 448 }); | 404 }); |
| 449 }); | 405 }); |
| 406 |
| 407 group('has a path dependency', () { |
| 408 group('where a hosted version exists', () { |
| 409 integration("and should suggest the hosted primary version", () { |
| 410 setUpDependency({'path': path.join(sandboxDir, 'foo')}, |
| 411 hostedVersions: ["3.0.0-pre", "2.0.0", "1.0.0"]); |
| 412 expectDependencyValidationError(' foo: ">=2.0.0 <3.0.0"'); |
| 413 }); |
| 414 |
| 415 integration("and should suggest the hosted prerelease version if " |
| 416 "it's the only version available", () { |
| 417 setUpDependency({'path': path.join(sandboxDir, 'foo')}, |
| 418 hostedVersions: ["3.0.0-pre", "2.0.0-pre"]); |
| 419 expectDependencyValidationError(' foo: ">=3.0.0-pre <4.0.0"'); |
| 420 }); |
| 421 |
| 422 integration("and should suggest a tighter constraint if primary is " |
| 423 "pre-1.0.0", () { |
| 424 setUpDependency({'path': path.join(sandboxDir, 'foo')}, |
| 425 hostedVersions: ["0.0.1", "0.0.2"]); |
| 426 expectDependencyValidationError(' foo: ">=0.0.2 <0.0.3"'); |
| 427 }); |
| 428 }); |
| 429 |
| 430 group('where no hosted version exists', () { |
| 431 integration("and should use the other source's version", () { |
| 432 setUpDependency({ |
| 433 'path': path.join(sandboxDir, 'foo'), |
| 434 'version': '>=1.0.0 <2.0.0' |
| 435 }); |
| 436 expectDependencyValidationError(' foo: ">=1.0.0 <2.0.0"'); |
| 437 }); |
| 438 |
| 439 integration("and should use the other source's unquoted version if " |
| 440 "concrete", () { |
| 441 setUpDependency({ |
| 442 'path': path.join(sandboxDir, 'foo'), |
| 443 'version': '0.2.3' |
| 444 }); |
| 445 expectDependencyValidationError(' foo: 0.2.3'); |
| 446 }); |
| 447 }); |
| 448 }); |
| 450 | 449 |
| 451 group('has an unconstrained dependency', () { | 450 group('has an unconstrained dependency', () { |
| 452 group('and it should not suggest a version', () { | 451 group('and it should not suggest a version', () { |
| 453 integration("if there's no lockfile", () { | 452 integration("if there's no lockfile", () { |
| 454 dir(appPath, [ | 453 dir(appPath, [ |
| 455 libPubspec("test_pkg", "1.0.0", deps: [ | 454 libPubspec("test_pkg", "1.0.0", deps: [ |
| 456 {'hosted': 'foo'} | 455 {'hosted': 'foo'} |
| 457 ]) | 456 ]) |
| 458 ]).scheduleCreate(); | 457 ]).scheduleCreate(); |
| 459 | 458 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 500 'source': 'hosted', | 499 'source': 'hosted', |
| 501 'description': { | 500 'description': { |
| 502 'name': 'foo', | 501 'name': 'foo', |
| 503 'url': 'http://pub.dartlang.org' | 502 'url': 'http://pub.dartlang.org' |
| 504 } | 503 } |
| 505 } | 504 } |
| 506 } | 505 } |
| 507 })) | 506 })) |
| 508 ]).scheduleCreate(); | 507 ]).scheduleCreate(); |
| 509 | 508 |
| 510 expectLater(schedulePackageValidation(dependency), | 509 expectDependencyValidationWarning(' foo: ">=1.2.3 <2.0.0"'); |
| 511 pairOf(isEmpty, someElement(contains( | |
| 512 ' foo: ">=1.2.3 <2.0.0"')))); | |
| 513 }); | 510 }); |
| 514 | 511 |
| 515 integration('and it should suggest a concrete constraint if the locked ' | 512 integration('and it should suggest a concrete constraint if the locked ' |
| 516 'version is pre-1.0.0', () { | 513 'version is pre-1.0.0', () { |
| 517 dir(appPath, [ | 514 dir(appPath, [ |
| 518 libPubspec("test_pkg", "1.0.0", deps: [ | 515 libPubspec("test_pkg", "1.0.0", deps: [ |
| 519 {'hosted': 'foo'} | 516 {'hosted': 'foo'} |
| 520 ]), | 517 ]), |
| 521 file("pubspec.lock", json.stringify({ | 518 file("pubspec.lock", json.stringify({ |
| 522 'packages': { | 519 'packages': { |
| 523 'foo': { | 520 'foo': { |
| 524 'version': '0.1.2', | 521 'version': '0.1.2', |
| 525 'source': 'hosted', | 522 'source': 'hosted', |
| 526 'description': { | 523 'description': { |
| 527 'name': 'foo', | 524 'name': 'foo', |
| 528 'url': 'http://pub.dartlang.org' | 525 'url': 'http://pub.dartlang.org' |
| 529 } | 526 } |
| 530 } | 527 } |
| 531 } | 528 } |
| 532 })) | 529 })) |
| 533 ]).scheduleCreate(); | 530 ]).scheduleCreate(); |
| 534 | 531 |
| 535 expectLater(schedulePackageValidation(dependency), | 532 expectDependencyValidationWarning(' foo: ">=0.1.2 <0.1.3"'); |
| 536 pairOf(isEmpty, someElement(contains( | |
| 537 ' foo: ">=0.1.2 <0.1.3"')))); | |
| 538 }); | 533 }); |
| 539 }); | 534 }); |
| 540 }); | 535 }); |
| 541 | 536 |
| 542 integration('has a hosted dependency on itself', () { | 537 integration('has a hosted dependency on itself', () { |
| 543 dir(appPath, [ | 538 dir(appPath, [ |
| 544 libPubspec("test_pkg", "1.0.0", deps: [ | 539 libPubspec("test_pkg", "1.0.0", deps: [ |
| 545 {'hosted': {'name': 'test_pkg', 'version': '>=1.0.0'}} | 540 {'hosted': {'name': 'test_pkg', 'version': '>=1.0.0'}} |
| 546 ]) | 541 ]) |
| 547 ]).scheduleCreate(); | 542 ]).scheduleCreate(); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 580 }); | 575 }); |
| 581 | 576 |
| 582 test('has a README with invalid utf-8', () { | 577 test('has a README with invalid utf-8', () { |
| 583 dir(appPath, [ | 578 dir(appPath, [ |
| 584 binaryFile("README", [192]) | 579 binaryFile("README", [192]) |
| 585 ]).scheduleCreate(); | 580 ]).scheduleCreate(); |
| 586 expectValidationWarning(utf8Readme); | 581 expectValidationWarning(utf8Readme); |
| 587 }); | 582 }); |
| 588 }); | 583 }); |
| 589 } | 584 } |
| OLD | NEW |