public async Task DeepCycleCheck()
        {
            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            provider.Package("A", "1.0")
            .DependsOn("B", "2.0");

            provider.Package("B", "2.0")
            .DependsOn("C", "2.0");

            provider.Package("C", "2.0")
            .DependsOn("D", "1.0")
            .DependsOn("E", "1.0");

            provider.Package("D", "1.0");
            provider.Package("E", "1.0")
            .DependsOn("A", "1.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);
            var node   = await DoWalkAsync(walker, "A");

            var result = node.Analyze();

            Assert.Equal(1, result.Cycles.Count);

            var cycle = result.Cycles[0];

            AssertPath(cycle, "A 1.0", "B 2.0", "C 2.0", "E 1.0", "A 1.0");
        }
        public async Task DowngradeThenUpgradeThenDowngrade()
        {
            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            provider.Package("A", "1.0")
            .DependsOn("B", "1.0")
            .DependsOn("C", "1.0");

            provider.Package("B", "1.0");

            provider.Package("C", "1.0")
            .DependsOn("B", "2.0")
            .DependsOn("D", "1.0");

            provider.Package("B", "2.0");

            provider.Package("D", "1.0")
            .DependsOn("B", "1.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);
            var node   = await DoWalkAsync(walker, "A");

            var result = node.Analyze();

            Assert.Equal(1, result.Downgrades.Count);
            var downgraded   = result.Downgrades[0].DowngradedFrom;
            var downgradedBy = result.Downgrades[0].DowngradedTo;

            AssertPath(downgraded, "A 1.0", "C 1.0", "B 2.0");
            AssertPath(downgradedBy, "A 1.0", "B 1.0");
        }
        public async Task UpgradeThenDowngradeThenEqual()
        {
            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            provider.Package("A", "1.0")
            .DependsOn("B", "2.0")
            .DependsOn("C", "1.0");

            provider.Package("B", "1.0");

            provider.Package("C", "1.0")
            .DependsOn("B", "1.0")
            .DependsOn("D", "1.0");

            provider.Package("B", "2.0");

            provider.Package("D", "1.0")
            .DependsOn("B", "2.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);
            var node   = await DoWalkAsync(walker, "A");

            var result = node.Analyze();

            Assert.Equal(0, result.Downgrades.Count);
        }
        public async Task StrictDependenciesButNoConflict()
        {
            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            provider.Package("A", "1.0")
            .DependsOn("B", "2.0")
            .DependsOn("C", "2.0");

            provider.Package("B", "2.0")
            .DependsOn("D", "[2.0]");

            provider.Package("C", "2.0")
            .DependsOn("D", "[1.0, 3.0]");

            provider.Package("D", "1.0");
            provider.Package("D", "2.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);
            var node   = await DoWalkAsync(walker, "A");

            var result = node.Analyze();

            Assert.Equal(0, result.VersionConflicts.Count);
        }
        public async Task NearestWinsOverridesStrictDependencyButDowngradeWarns()
        {
            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            provider.Package("A", "1.0")
            .DependsOn("B", "2.0")
            .DependsOn("C", "2.0")
            .DependsOn("D", "1.0");

            provider.Package("B", "2.0")
            .DependsOn("D", "[2.0]");

            provider.Package("C", "2.0")
            .DependsOn("D", "[1.0]");

            provider.Package("D", "1.0");
            provider.Package("D", "2.0");
            provider.Package("D", "3.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);
            var node   = await DoWalkAsync(walker, "A");

            var result = node.Analyze();

            Assert.Equal(0, result.VersionConflicts.Count);
            Assert.Equal(1, result.Downgrades.Count);

            var downgraded   = result.Downgrades[0].DowngradedFrom;
            var downgradedBy = result.Downgrades[0].DowngradedTo;

            AssertPath(downgraded, "A 1.0", "B 2.0", "D 2.0");
            AssertPath(downgradedBy, "A 1.0", "D 1.0");
        }
        public async Task TryResolveConflicts_ThrowsIfPackageConstraintCannotBeResolved()
        {
            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            provider.Package("Root", "1.0")
            .DependsOn("A", "1.0")
            .DependsOn("B", "2.0");

            provider.Package("A", "1.0")
            .DependsOn("C", "(1.0, 1.4]");

            provider.Package("B", "2.0")
            .DependsOn("C", "1.8");

            provider.Package("C", "1.3.8");
            provider.Package("C", "1.8");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);
            var node   = await DoWalkAsync(walker, "Root");

            var result = node.Analyze();

            Assert.Equal(1, result.VersionConflicts.Count);

            var conflict = result.VersionConflicts[0];
            var c1       = conflict.Selected;
            var c2       = conflict.Conflicting;

            AssertPath(c1, "Root 1.0", "B 2.0", "C 1.8");
            AssertPath(c2, "Root 1.0", "A 1.0", "C 1.3.8");
        }
        public async Task AllowPreleaseVersionNoConflict()
        {
            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            provider.Package("A", "1.0-beta")
            .DependsOn("B", "1.0")
            .DependsOn("C", "1.0-beta")
            .DependsOn("E", "1.0");

            provider.Package("B", "1.0")
            .DependsOn("D", "1.0");

            provider.Package("C", "1.0-beta")
            .DependsOn("D", "1.1-beta");

            provider.Package("E", "1.0")
            .DependsOn("D", "0.1");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);
            var node   = await DoWalkAsync(walker, "A");

            var result = node.Analyze();

            Assert.Equal(0, result.VersionConflicts.Count);
        }
        public async Task SingleConflictWhereConflictingDependenyIsUnresolved()
        {
            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            provider.Package("A", "1.0")
            .DependsOn("B", "2.0")
            .DependsOn("C", "2.0");

            provider.Package("B", "2.0")
            .DependsOn("D", "[2.0]");

            provider.Package("C", "2.0")
            .DependsOn("D", "[1.0]");

            provider.Package("D", "2.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);
            var node   = await DoWalkAsync(walker, "A");

            var result = node.Analyze();

            Assert.Equal(1, result.VersionConflicts.Count);

            var conflict = result.VersionConflicts[0];
            var c1       = conflict.Selected;
            var c2       = conflict.Conflicting;

            AssertPath(c1, "A 1.0", "B 2.0", "D 2.0");
            AssertPath(c2, "A 1.0", "C 2.0", "D 1.0");
        }
        public async Task AllowProjectOverridePackageNoConflict()
        {
            var context         = new TestRemoteWalkContext();
            var packageProvider = new DependencyProvider();
            var projectProvider = new DependencyProvider();

            projectProvider.Package("A", "1.0", LibraryType.Project)
            .DependsOn("B", "2.0", LibraryDependencyTarget.Project)
            .DependsOn("C", "2.0");

            projectProvider.Package("B", "2.0", LibraryType.Project)
            .DependsOn("D", "[2.0]", LibraryDependencyTarget.Project);

            packageProvider.Package("C", "2.0")
            .DependsOn("D", "[1.0]");

            packageProvider.Package("D", "1.0");
            projectProvider.Package("D", "2.0", LibraryType.Project);

            context.LocalLibraryProviders.Add(packageProvider);
            context.ProjectLibraryProviders.Add(projectProvider);

            var walker = new RemoteDependencyWalker(context);
            var node   = await DoWalkAsync(walker, "A");

            var result = node.Analyze();

            Assert.Equal(0, result.VersionConflicts.Count);
        }
        public void IsDependencyValidForGraphTest(LibraryDependencyReferenceType referenceType, bool versionCentrallyManaged)
        {
            var centralPackageName    = "D";
            var context               = new TestRemoteWalkContext();
            var centralPackageVersion = new CentralPackageVersion(centralPackageName, VersionRange.Parse("2.0.0"));
            var centralPackageVersionDependecy_VersionCentrallyManaged = new LibraryDependency()
            {
                LibraryRange            = new LibraryRange(centralPackageVersion.Name, centralPackageVersion.VersionRange, LibraryDependencyTarget.Package),
                VersionCentrallyManaged = versionCentrallyManaged,
                ReferenceType           = referenceType,
            };
            var walker = new RemoteDependencyWalker(context);

            // Act
            var expectedResult = walker.IsDependencyValidForGraph(centralPackageVersionDependecy_VersionCentrallyManaged);

            // Assert
            if (referenceType != LibraryDependencyReferenceType.None)
            {
                Assert.True(expectedResult);
            }
            else
            {
                Assert.False(expectedResult);
            }
        }
        public async Task WalkAsyncDowngradesBecauseOfCentralDependecy()
        {
            var centralPackageName    = "D";
            var centralPackageVersion = "2.0.0";
            var otherVersion          = "3.0.0";
            var framework             = NuGetFramework.Parse("net45");

            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            // D is a transitive dependency for package A through package B -> C -> D
            // D is defined as a Central Package Version
            // In this context Package D with version centralPackageVersion will be added as inner node of Node A, next to B

            // Picture:
            // A -> B -> C -> D (version 1.0.0 or 2.0.0 as defined by "otherVersion" argument.
            // A ~> D (the version 2.0.0 or as defined by "centralPackageVersion" argument
            //         the dependency is not direct,
            //         it simulates the fact that there is a centrally defined "D" package
            //         the information is added to the provider)

            provider.Package("A", otherVersion)
            .DependsOn("B", otherVersion);

            provider.Package("B", otherVersion)
            .DependsOn("C", otherVersion);

            provider.Package("C", otherVersion)
            .DependsOn(centralPackageName, otherVersion);

            // Simulates the existence of a D centrally defined package that is not direct dependency
            provider.Package("A", otherVersion)
            .DependsOn(centralPackageName, centralPackageVersion, LibraryDependencyTarget.Package, versionCentrallyManaged: true);

            // Add central package to the source with multiple versions
            provider.Package(centralPackageName, "1.0.0");
            provider.Package(centralPackageName, centralPackageVersion);
            provider.Package(centralPackageName, "3.0.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);

            // Act
            var rootNode = await DoWalkAsync(walker, "A", framework);

            var analyzeResult = rootNode.Analyze();

            // Assert
            Assert.Equal(1, analyzeResult.Downgrades.Count);
            var downgrade = analyzeResult.Downgrades.First();

            Assert.Equal(centralPackageName, downgrade.DowngradedFrom.Key.Name);
            Assert.Equal("[3.0.0, )", downgrade.DowngradedFrom.Key.VersionRange.ToNormalizedString());
            Assert.Equal(centralPackageName, downgrade.DowngradedTo.Key.Name);
            Assert.Equal("[2.0.0, )", downgrade.DowngradedTo.Key.VersionRange.ToNormalizedString());
        }
        public async Task DoubleDowngrade()
        {
            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            provider.Package("A", "1.0")
            .DependsOn("B", "0.7")
            .DependsOn("C", "1.0");

            provider.Package("B", "0.7");

            provider.Package("C", "1.0")
            .DependsOn("B", "0.8")
            .DependsOn("D", "1.0");

            provider.Package("B", "0.8");

            provider.Package("D", "1.0")
            .DependsOn("B", "1.0");

            provider.Package("B", "1.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);
            var node   = await DoWalkAsync(walker, "A");

            var downgrades = new List <Tuple <GraphNode <RemoteResolveResult>, GraphNode <RemoteResolveResult> > >();
            var cycles     = new List <GraphNode <RemoteResolveResult> >();

            var result = node.Analyze();

            Assert.Equal(2, result.Downgrades.Count);


            var d0   = result.Downgrades[0];
            var d0To = d0.DowngradedFrom;
            var d0By = d0.DowngradedTo;

            AssertPath(d0To, "A 1.0", "C 1.0", "B 0.8");
            AssertPath(d0By, "A 1.0", "B 0.7");

            var d1   = result.Downgrades[1];
            var d1To = d1.DowngradedFrom;
            var d1By = d1.DowngradedTo;

            AssertPath(d1To, "A 1.0", "C 1.0", "D 1.0", "B 1.0");
            AssertPath(d1By, "A 1.0", "B 0.7");
        }
        public async Task WalkAsync_CentralTransitiveDependencyList_DoesNotHaveDuplicates()
        {
            var framework = NuGetFramework.Parse("net45");
            var context   = new TestRemoteWalkContext();
            var provider  = new DependencyProvider();

            // A -> centralPackage1
            //   -> centralPackage2 -> centralPackage1
            provider.Package("A", "1.0.0")
            .DependsOn("centralPackage1", "1.0.0", target: LibraryDependencyTarget.Package, versionCentrallyManaged: true);
            provider.Package("A", "1.0.0")
            .DependsOn("centralPackage2", "1.0.0", target: LibraryDependencyTarget.Package, versionCentrallyManaged: true);
            provider.Package("centralPackage2", "1.0.0")
            .DependsOn("centralPackage1", "1.0.0");

            // A -> projectB -> projectC -> centralPackage1
            provider.Package("A", "1.0.0")
            .DependsOn("B", "1.0.0");

            provider.Package("B", "1.0.0")
            .DependsOn("C", "1.0.0");

            provider.Package("C", "1.0.0")
            .DependsOn("centralPackage1", "1.0.0", target: LibraryDependencyTarget.Package, versionCentrallyManaged: true);

            // B ~> centralPackage1
            provider.Package("B", "1.0.0")
            .DependsOn("centralPackage1", "1.0.0", target: LibraryDependencyTarget.Package, versionCentrallyManaged: true, libraryDependencyReferenceType: LibraryDependencyReferenceType.None);

            provider.Package("centralPackage1", "1.0.0");
            provider.Package("centralPackage2", "1.0.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);

            // Act
            var rootNode = await DoWalkAsync(walker, "A", framework);

            // Assert
            Assert.Equal(3, rootNode.InnerNodes.Count);
        }
        public async Task TryResolveConflicts_WorksWhenVersionRangeIsNotSpecified()
        {
            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            provider.Package("Root", "1.0")
            .DependsOn("A", "1.0")
            .DependsOn("B", "2.0");

            provider.Package("A", "1.0")
            .DependsOn("C");

            provider.Package("B", "2.0")
            .DependsOn("C", "1.8");

            provider.Package("C", "1.8");
            provider.Package("C", "2.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);
            var node   = await DoWalkAsync(walker, "Root");

            // Restore doesn't actually support null versions so fake a resolved dependency
            var cNode = node.Path("A", "C");

            cNode.Key.TypeConstraint = LibraryDependencyTarget.Package;
            cNode.Item = new GraphItem <RemoteResolveResult>(new LibraryIdentity
            {
                Name    = "C",
                Version = new NuGetVersion("2.0")
            });

            var result = node.Analyze();

            Assert.Empty(result.VersionConflicts);

            Assert.Equal(Disposition.Accepted, cNode.Disposition);
            Assert.Equal(Disposition.Rejected, node.Path("B", "C").Disposition);
        }
        public async Task CyclesAreDetectedIf2VersionsOfTheSamePackageId()
        {
            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            provider.Package("A", "1.0")
            .DependsOn("B", "2.0");

            provider.Package("B", "2.0")
            .DependsOn("A", "5.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);
            var node   = await DoWalkAsync(walker, "A");

            var result = node.Analyze();

            Assert.Equal(1, result.Cycles.Count);

            var cycle = result.Cycles[0];

            AssertPath(cycle, "A 1.0", "B 2.0", "A 5.0");
        }
        public async Task WalkAsyncAddsTransitiveCentralDependency(string centralPackageVersion, string otherVersion)
        {
            var centralPackageName = "D";
            var framework          = NuGetFramework.Parse("net45");

            var context  = new TestRemoteWalkContext();
            var provider = new DependencyProvider();

            // D is a transitive dependency for package A through package B -> C -> D
            // D is defined as a Central Package Version
            // In this context Package D with version centralPackageVersion will be added as inner node of Node A, next to B

            // Input
            // A -> B (version = otherVersion) -> C (version = otherVersion) -> D (version = otherVersion)
            // A ~> D (the version 2.0.0 or as defined by "centralPackageVersion" argument
            //         the dependency is not direct,
            //         it simulates the fact that there is a centrally defined "D" package
            //         the information is added to the provider)

            // The expected output graph
            //    -> B (version = otherVersion) -> C (version = otherVersion)
            // A
            //    -> D (version = 2.0.0)

            provider.Package("A", otherVersion)
            .DependsOn("B", otherVersion);

            provider.Package("B", otherVersion)
            .DependsOn("C", otherVersion);

            provider.Package("C", otherVersion)
            .DependsOn(centralPackageName, otherVersion);

            // Simulates the existence of a D centrally defined package that is not direct dependency
            provider.Package("A", otherVersion)
            .DependsOn(centralPackageName, centralPackageVersion, LibraryDependencyTarget.Package, versionCentrallyManaged: true, libraryDependencyReferenceType: LibraryDependencyReferenceType.None);

            // Add central package to the source with multiple versions
            provider.Package(centralPackageName, "1.0.0");
            provider.Package(centralPackageName, centralPackageVersion);
            provider.Package(centralPackageName, "3.0.0");

            context.LocalLibraryProviders.Add(provider);
            var walker = new RemoteDependencyWalker(context);

            // Act
            var rootNode = await DoWalkAsync(walker, "A", framework);

            // Assert
            Assert.Equal(2, rootNode.InnerNodes.Count);
            var centralVersionInGraphNode = rootNode.InnerNodes.Where(n => n.Item.Key.Name == centralPackageName).FirstOrDefault();

            Assert.NotNull(centralVersionInGraphNode);
            Assert.Equal(centralPackageVersion, centralVersionInGraphNode.Item.Key.Version.ToNormalizedString());
            Assert.True(centralVersionInGraphNode.Item.IsCentralTransitive);

            var BNode = rootNode.InnerNodes.Where(n => n.Item.Key.Name == "B").FirstOrDefault();

            Assert.NotNull(BNode);
            Assert.Equal(1, BNode.InnerNodes.Count);
            Assert.Equal(otherVersion, BNode.Item.Key.Version.ToNormalizedString());
            Assert.False(BNode.Item.IsCentralTransitive);

            var CNode = BNode.InnerNodes.Where(n => n.Item.Key.Name == "C").FirstOrDefault();

            Assert.NotNull(CNode);
            Assert.Equal(otherVersion, CNode.Item.Key.Version.ToNormalizedString());
            Assert.Equal(0, CNode.InnerNodes.Count);
            Assert.False(CNode.Item.IsCentralTransitive);
        }