From 04f08180fd2ae8f2848e6b7094b1d82979a079b6 Mon Sep 17 00:00:00 2001 From: Jeff Kluge Date: Mon, 9 Dec 2024 15:47:47 -0800 Subject: [PATCH 1/3] Fix floating version comparison in new dependency resolver --- .../RestoreCommand/DependencyGraphResolver.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/NuGet.Core/NuGet.Commands/RestoreCommand/DependencyGraphResolver.cs b/src/NuGet.Core/NuGet.Commands/RestoreCommand/DependencyGraphResolver.cs index d4b2051fdf0..b1ac5e67690 100644 --- a/src/NuGet.Core/NuGet.Commands/RestoreCommand/DependencyGraphResolver.cs +++ b/src/NuGet.Core/NuGet.Commands/RestoreCommand/DependencyGraphResolver.cs @@ -1504,9 +1504,11 @@ public bool Equals(LibraryRange? x, LibraryRange? y) break; } - return typeConstraint1 == typeConstraint2 && - VersionRangeComparer.Default.Equals(x.VersionRange, y.VersionRange) && - x.Name.Equals(y.Name, StringComparison.OrdinalIgnoreCase); + return typeConstraint1 == typeConstraint2 + && VersionRangeComparer.Default.Equals(x.VersionRange, y.VersionRange) + && x.Name.Equals(y.Name, StringComparison.OrdinalIgnoreCase) + && x.VersionRange.IsFloating == y.VersionRange.IsFloating + && EqualityUtility.EqualsWithNullCheck(x.VersionRange.Float, y.VersionRange.Float); } public int GetHashCode(LibraryRange obj) From 0276bd0e4b17375e734f9f8d5fcef836c8357378 Mon Sep 17 00:00:00 2001 From: Jeff Kluge Date: Mon, 16 Dec 2024 10:53:55 -0800 Subject: [PATCH 2/3] Add test --- ...estoreCommand_AlgorithmEquivalencyTests.cs | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/test/NuGet.Core.FuncTests/NuGet.Commands.FuncTest/RestoreCommand_AlgorithmEquivalencyTests.cs b/test/NuGet.Core.FuncTests/NuGet.Commands.FuncTest/RestoreCommand_AlgorithmEquivalencyTests.cs index 95f55e18fe1..4036d5004e7 100644 --- a/test/NuGet.Core.FuncTests/NuGet.Commands.FuncTest/RestoreCommand_AlgorithmEquivalencyTests.cs +++ b/test/NuGet.Core.FuncTests/NuGet.Commands.FuncTest/RestoreCommand_AlgorithmEquivalencyTests.cs @@ -1775,6 +1775,94 @@ await SimpleTestPackageUtility.CreatePackagesAsync( result.Success.Should().BeFalse(); } + // Project1 -> A 1.0.* -> C 1.0.0 + // B 1.0.* -> C 1.0.0 + // Project2 -> C 1.0.* + [Theory] + [InlineData("*")] + [InlineData("1.*")] + [InlineData("1.0.*")] + public async Task RestoreCommand_WithTransitiveFloatingVersion_ResolvesCorrectly(string floatingVersion) + { + // Arrange + using var pathContext = new SimpleTestPathContext(); + + var packageA = new SimpleTestPackageContext("A", "1.0.0") + { + Dependencies = + [ + new SimpleTestPackageContext("C", "1.0.0") + ] + }; + + var packageB = new SimpleTestPackageContext("B", "1.0.0") + { + Dependencies = + [ + new SimpleTestPackageContext("C", "1.0.0") + ] + }; + + var packageC101 = new SimpleTestPackageContext("C", "1.0.1"); + + await SimpleTestPackageUtility.CreateFolderFeedV3Async( + pathContext.PackageSource, + PackageSaveMode.Defaultv3, + packageA, + packageB, + packageC101); + + var project2Spec = ProjectTestHelpers.GetPackageSpecWithProjectNameAndSpec( + "Project2", + pathContext.SolutionRoot, + @" + { + ""frameworks"": { + ""net472"": { + ""dependencies"": { + ""C"": """ + floatingVersion + @""", + } + } + } + }"); + + var project1Spec = ProjectTestHelpers.GetPackageSpecWithProjectNameAndSpec( + "Project1", + pathContext.SolutionRoot, + @" + { + ""frameworks"": { + ""net472"": { + ""dependencies"": { + ""A"": ""1.0.*"", + ""B"": ""1.0.*"" + } + } + } + }") + .WithTestProjectReference(project2Spec); + + // Act & Assert + (var result, _) = await ValidateRestoreAlgorithmEquivalency(pathContext, project1Spec, project2Spec); + + // Additional assert + result.Success.Should().BeTrue(); + result.LogMessages.Should().BeEmpty(); + result.LockFile.Targets.Should().HaveCount(1); + result.LockFile.Targets[0].Libraries.Should().HaveCount(4); + result.LockFile.Targets[0].Libraries[0].Name.Should().Be("A"); + result.LockFile.Targets[0].Libraries[0].Version.Should().Be(new NuGetVersion("1.0.0")); + + result.LockFile.Targets[0].Libraries[1].Name.Should().Be("B"); + result.LockFile.Targets[0].Libraries[1].Version.Should().Be(new NuGetVersion("1.0.0")); + + result.LockFile.Targets[0].Libraries[2].Name.Should().Be("C"); + result.LockFile.Targets[0].Libraries[2].Version.Should().Be(new NuGetVersion("1.0.1")); + + result.LockFile.Targets[0].Libraries[3].Name.Should().Be("Project2"); + result.LockFile.Targets[0].Libraries[3].Version.Should().Be(new NuGetVersion("1.0.0")); + } + // P1 -> P2 -> B * // P1 -> A -> B 1.0.0 [Theory] From 2135e692d0f4501c2cc3096a3c10e7db6a2010fc Mon Sep 17 00:00:00 2001 From: Jeff Kluge Date: Mon, 16 Dec 2024 10:54:04 -0800 Subject: [PATCH 3/3] Use VersionRange.Equals instead --- .../NuGet.Commands/RestoreCommand/DependencyGraphResolver.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/NuGet.Core/NuGet.Commands/RestoreCommand/DependencyGraphResolver.cs b/src/NuGet.Core/NuGet.Commands/RestoreCommand/DependencyGraphResolver.cs index b1ac5e67690..e2a98d01277 100644 --- a/src/NuGet.Core/NuGet.Commands/RestoreCommand/DependencyGraphResolver.cs +++ b/src/NuGet.Core/NuGet.Commands/RestoreCommand/DependencyGraphResolver.cs @@ -1505,10 +1505,8 @@ public bool Equals(LibraryRange? x, LibraryRange? y) } return typeConstraint1 == typeConstraint2 - && VersionRangeComparer.Default.Equals(x.VersionRange, y.VersionRange) && x.Name.Equals(y.Name, StringComparison.OrdinalIgnoreCase) - && x.VersionRange.IsFloating == y.VersionRange.IsFloating - && EqualityUtility.EqualsWithNullCheck(x.VersionRange.Float, y.VersionRange.Float); + && x.VersionRange.Equals(y.VersionRange); } public int GetHashCode(LibraryRange obj)