@@ -61,7 +61,7 @@ let aRef = PackageReference.localSourceControl(identity: .plain("a"), path: .roo
61
61
let bRef = PackageReference . localSourceControl ( identity: . plain( " b " ) , path: . root)
62
62
let cRef = PackageReference . localSourceControl ( identity: . plain( " c " ) , path: . root)
63
63
64
- let rootRef = PackageReference . root ( identity: PackageIdentity ( " root " ) , path: . root)
64
+ let rootRef = PackageReference . root ( identity: . plain ( " root " ) , path: . root)
65
65
let rootNode = DependencyResolutionNode . root ( package : rootRef)
66
66
let rootCause = try ! Incompatibility ( Term ( rootNode, . exact( v1) ) , root: rootNode)
67
67
let _cause = try ! Incompatibility ( " [email protected] " , root
: rootNode
)
@@ -409,11 +409,139 @@ final class PubgrubTests: XCTestCase {
409
409
solution. decide ( . product( " a " , package : aRef) , at: v2)
410
410
solution. derive ( " b^1.0.0 " , cause: _cause)
411
411
412
- XCTAssertEqual ( try solution. satisfier ( for: Term ( " b^1.0.0 " ) ) . term, " b^1.0.0 " )
412
+ XCTAssertEqual ( try solution. satisfier ( for: Term ( " b^1.0.0 " ) ) . term, " b^1.0.0 " )
413
413
XCTAssertEqual ( try solution
. satisfier ( for
: Term ( " ¬a^1.0.0 " ) ) . term
, " [email protected] " )
414
414
XCTAssertEqual ( try solution
. satisfier ( for
: Term ( " a^2.0.0 " ) ) . term
, " [email protected] " )
415
415
}
416
416
417
+ // this test reconstruct the conditions described in radar/93335995
418
+ func testRadar93335995( ) throws {
419
+ let observability = ObservabilitySystem . makeForTesting ( )
420
+ let delegate = ObservabilityDependencyResolverDelegate ( observabilityScope: observability. topScope)
421
+ let solver = PubgrubDependencyResolver ( provider: emptyProvider, observabilityScope: observability. topScope, delegate: delegate)
422
+ let state = PubgrubDependencyResolver . State ( root: rootNode)
423
+
424
+ state. decide ( . root( package : aRef) , at: " 1.1.0 " )
425
+
426
+ do {
427
+ let cause = Incompatibility (
428
+ terms: . init( [
429
+ Term ( node: . root( package : aRef) ,
430
+ requirement: . exact( " 1.1.0 " ) ,
431
+ isPositive: true
432
+ ) ,
433
+ Term ( node: . root( package : bRef) ,
434
+ requirement: . range( " 1.1.0 " ..< " 2.0.0 " ) ,
435
+ isPositive: true
436
+ )
437
+ ] ) ,
438
+ cause: . noAvailableVersion
439
+ )
440
+ state. derive ( Term ( node: . root( package : bRef) , requirement: . range( " 1.1.0 " ..< " 2.0.0 " ) , isPositive: true ) , cause: cause)
441
+ }
442
+
443
+ do {
444
+ let cause = Incompatibility (
445
+ terms: . init( [
446
+ Term ( node: . root( package : aRef) ,
447
+ requirement: . exact( " 1.1.0 " ) ,
448
+ isPositive: true
449
+ ) ,
450
+ Term ( node: . root( package : bRef) ,
451
+ requirement: . range( " 1.3.1 " ..< " 2.0.0 " ) ,
452
+ isPositive: true
453
+ )
454
+ ] ) ,
455
+ cause: . noAvailableVersion
456
+ )
457
+ state. derive ( Term ( node: . root( package : bRef) , requirement: . range( " 1.3.1 " ..< " 2.0.0 " ) , isPositive: false ) , cause: cause)
458
+ // order here matters to reproduce the issue
459
+ state. derive ( Term ( node: . root( package : bRef) , requirement: . exact( " 1.3.0 " ) , isPositive: false ) , cause: cause)
460
+ state. derive ( Term ( node: . root( package : bRef) , requirement: . exact( " 1.3.1 " ) , isPositive: false ) , cause: cause)
461
+ state. derive ( Term ( node: . root( package : bRef) , requirement: . exact( " 1.2.0 " ) , isPositive: false ) , cause: cause)
462
+ state. derive ( Term ( node: . root( package : bRef) , requirement: . exact( " 1.1.0 " ) , isPositive: false ) , cause: cause)
463
+ }
464
+
465
+ let conflict = Incompatibility (
466
+ terms: . init( [
467
+ Term ( node: . root( package : aRef) ,
468
+ requirement: . exact( " 1.1.0 " ) ,
469
+ isPositive: true
470
+ ) ,
471
+ Term ( node: . root( package : bRef) ,
472
+ requirement: . ranges( [ " 1.1.1 " ..< " 1.2.0 " , " 1.2.1 " ..< " 1.3.0 " ] ) ,
473
+ isPositive: true
474
+ )
475
+ ] ) ,
476
+ cause: . noAvailableVersion
477
+ )
478
+
479
+ _ = try solver. resolve ( state: state, conflict: conflict)
480
+ XCTAssertNoDiagnostics ( observability. diagnostics)
481
+ }
482
+
483
+ func testNoInfiniteLoop( ) throws {
484
+ let observability = ObservabilitySystem . makeForTesting ( )
485
+ let delegate = ObservabilityDependencyResolverDelegate ( observabilityScope: observability. topScope)
486
+ let solver = PubgrubDependencyResolver ( provider: emptyProvider, observabilityScope: observability. topScope, delegate: delegate)
487
+ let state = PubgrubDependencyResolver . State ( root: rootNode)
488
+
489
+ do {
490
+ let cause = Incompatibility (
491
+ terms: . init( [
492
+ Term ( node: . root( package : aRef) ,
493
+ requirement: . exact( " 1.1.0 " ) ,
494
+ isPositive: true
495
+ ) ,
496
+ Term ( node: . root( package : bRef) ,
497
+ requirement: . range( " 1.1.0 " ..< " 2.0.0 " ) ,
498
+ isPositive: true
499
+ )
500
+ ] ) ,
501
+ cause: . noAvailableVersion
502
+ )
503
+ state. derive ( Term ( node: . root( package : aRef) , requirement: . exact( " 1.1.0 " ) , isPositive: true ) , cause: cause) // no decision available on this which will throw it into an infinite loop
504
+ state. derive ( Term ( node: . root( package : bRef) , requirement: . range( " 1.1.0 " ..< " 2.0.0 " ) , isPositive: true ) , cause: cause)
505
+ }
506
+
507
+ do {
508
+ let cause = Incompatibility (
509
+ terms: . init( [
510
+ Term ( node: . root( package : aRef) ,
511
+ requirement: . exact( " 1.1.0 " ) ,
512
+ isPositive: true
513
+ ) ,
514
+ Term ( node: . root( package : bRef) ,
515
+ requirement: . range( " 1.2.0 " ..< " 2.0.0 " ) ,
516
+ isPositive: true
517
+ )
518
+ ] ) ,
519
+ cause: . noAvailableVersion
520
+ )
521
+ state. derive ( Term ( node: . root( package : bRef) , requirement: . range( " 1.2.0 " ..< " 2.0.0 " ) , isPositive: false ) , cause: cause)
522
+ state. derive ( Term ( node: . root( package : bRef) , requirement: . exact( " 1.2.0 " ) , isPositive: false ) , cause: cause)
523
+ state. derive ( Term ( node: . root( package : bRef) , requirement: . exact( " 1.1.0 " ) , isPositive: false ) , cause: cause)
524
+ }
525
+
526
+ let conflict = Incompatibility (
527
+ terms: . init( [
528
+ Term ( node: . root( package : aRef) ,
529
+ requirement: . exact( " 1.1.0 " ) ,
530
+ isPositive: true
531
+ ) ,
532
+ Term ( node: . root( package : bRef) ,
533
+ requirement: . ranges( [ " 1.1.1 " ..< " 1.2.0 " ] ) ,
534
+ isPositive: true
535
+ )
536
+ ] ) ,
537
+ cause: . noAvailableVersion
538
+ )
539
+
540
+ XCTAssertThrowsError ( try solver. resolve ( state: state, conflict: conflict) ) { error in
541
+ XCTAssertTrue ( error is PubgrubDependencyResolver . PubgrubError )
542
+ }
543
+ }
544
+
417
545
func testResolutionNoConflicts( ) {
418
546
builder. serve ( " a " , at: v1, with: [ " a " : [ " b " : ( . versionSet( v1Range) , . specific( [ " b " ] ) ) ] ] )
419
547
builder. serve ( " b " , at: v1)
@@ -500,6 +628,58 @@ final class PubgrubTests: XCTestCase {
500
628
] )
501
629
}
502
630
631
+ func testUsecase1( ) throws {
632
+ builder. serve ( " a " ,
633
+ at: " 1.0.0 " ,
634
+ with: [
635
+ " a " : [
636
+ " b " : ( . versionSet( . range( " 1.1.0 " ..< " 2.0.0 " ) ) , . everything) ,
637
+ " c " : ( . versionSet( . range( " 1.2.1 " ..< " 2.0.0 " ) ) , . everything)
638
+ ] ,
639
+ ]
640
+ )
641
+
642
+ builder. serve ( " b " ,
643
+ at: " 1.0.0 " ,
644
+ with: [
645
+ " b " : [
646
+ " c " : ( . versionSet( . range( " 1.3.1 " ..< " 2.0.0 " ) ) , . everything) ,
647
+ ] ,
648
+ ]
649
+ )
650
+ builder. serve ( " b " ,
651
+ at: " 1.1.0 " ,
652
+ with: [
653
+ " b " : [
654
+ " c " : ( . versionSet( . range( " 1.4.1 " ..< " 2.0.0 " ) ) , . everything) ,
655
+ ] ,
656
+ ]
657
+ )
658
+
659
+ builder. serve ( " c " ,
660
+ at: [ " 1.0.0 " , " 1.1.0 " , " 1.2.0 " , " 1.2.1 " , " 1.3.0 " , " 1.3.1 " , " 1.4.0 " , " 1.4.1 " , " 2.0.0 " , " 2.1.0 " ] ,
661
+ with: [
662
+ " c " : [ " d " : ( . versionSet( v1Range) , . everything) ] ,
663
+ ]
664
+ )
665
+
666
+ builder. serve ( " d " , at: [ " 1.0.0 " , " 1.1.0 " , " 1.1.1 " , " 1.1.2 " , " 1.2.0 " , " 1.2.1 " ] )
667
+
668
+ let resolver = builder. create ( )
669
+ let dependencies = builder. create ( dependencies: [
670
+ " a " : ( . versionSet( v1Range) , . everything) ,
671
+ " c " : ( . versionSet( v1Range) , . everything)
672
+ ] )
673
+ let result = resolver. solve ( constraints: dependencies)
674
+
675
+ AssertResult ( result, [
676
+ ( " a " , . version( v1) ) ,
677
+ ( " b " , . version( " 1.1.0 " ) ) ,
678
+ ( " c " , . version( " 1.4.1 " ) ) ,
679
+ ( " d " , . version( " 1.2.1 " ) )
680
+ ] )
681
+ }
682
+
503
683
func testCycle1( ) {
504
684
builder. serve ( " foo " , at: v1_1, with: [ " foo " : [ " foo " : ( . versionSet( v1Range) , . specific( [ " foo " ] ) ) ] ] )
505
685
@@ -2820,6 +3000,15 @@ class DependencyGraphBuilder {
2820
3000
}
2821
3001
}
2822
3002
3003
+ func serve(
3004
+ _ package : String ,
3005
+ at versions: [ Version ] ,
3006
+ toolsVersion: ToolsVersion ? = nil ,
3007
+ with dependencies: KeyValuePairs < String , OrderedCollections . OrderedDictionary < String , ( PackageRequirement , ProductFilter ) > > = [ : ]
3008
+ ) {
3009
+ self . serve ( package , at: versions. map { . version( $0) } , toolsVersion: toolsVersion, with: dependencies)
3010
+ }
3011
+
2823
3012
func serve(
2824
3013
_ package : String ,
2825
3014
at version: Version ,
@@ -2829,6 +3018,21 @@ class DependencyGraphBuilder {
2829
3018
self . serve ( package , at: . version( version) , toolsVersion: toolsVersion, with: dependencies)
2830
3019
}
2831
3020
3021
+ func serve(
3022
+ _ package : String ,
3023
+ at versions: [ BoundVersion ] ,
3024
+ toolsVersion: ToolsVersion ? = nil ,
3025
+ with dependencies: KeyValuePairs < String , OrderedCollections . OrderedDictionary < String , ( PackageRequirement , ProductFilter ) > > = [ : ]
3026
+ ) {
3027
+ let packageReference = reference ( for: package )
3028
+ self . serve (
3029
+ packageReference,
3030
+ at: versions,
3031
+ toolsVersion: toolsVersion,
3032
+ with: dependencies
3033
+ )
3034
+ }
3035
+
2832
3036
func serve(
2833
3037
_ package : String ,
2834
3038
at version: BoundVersion ,
@@ -2844,6 +3048,17 @@ class DependencyGraphBuilder {
2844
3048
)
2845
3049
}
2846
3050
3051
+ func serve(
3052
+ _ packageReference: PackageReference ,
3053
+ at versions: [ BoundVersion ] ,
3054
+ toolsVersion: ToolsVersion ? = nil ,
3055
+ with dependencies: KeyValuePairs < String , OrderedCollections . OrderedDictionary < String , ( PackageRequirement , ProductFilter ) > > = [ : ]
3056
+ ) {
3057
+ for version in versions {
3058
+ serve ( packageReference, at: version, toolsVersion: toolsVersion, with: dependencies)
3059
+ }
3060
+ }
3061
+
2847
3062
func serve(
2848
3063
_ packageReference: PackageReference ,
2849
3064
at version: BoundVersion ,
0 commit comments