Skip to content
This repository has been archived by the owner on Jul 12, 2022. It is now read-only.

Commit

Permalink
Sort projects (#405)
Browse files Browse the repository at this point in the history
* Generic topo sort

* Sortings

* Improve NuGet CLI behaviour when running as global tool (#402)

* Log error instead of throwing when NuGet cli cannot be found.

This returns to the old behaviour, that was still expected by the consumers of this class.

* Do not run global nuget restore when dealing with a dotnetcore-only project.

* Include NuGet.exe in packaged tool

* Expanded diagnostic output when probing for NuGet.exe location

* NuGetFileRestoreCommand created by IoC

* NuGetUpdatePackageCommand created by IoC

* DotNetUpdateCommand  created by IoC

* UpdateProjectImportsCommand created by IoC

* UpdateNuspecCommand created by IoC

* Extract helper method to improve readability

* Cache the path to NuGet.exe when found

* Delay evaluation of NuGetPath so that it happens after logger is configured

* Generic topo sort

* Sortings

* Started sorter tests

* Test sort logger output

* Actual sort tests

* Fix integration bug

* A test on the "GetFullPath" line

* test sort with bad inout data cycle

* More PackageUpdateSetTopologicalSortTests
better test asserts

* cycle detection for PackageUpdateSet
  • Loading branch information
AnthonySteele authored Aug 25, 2018
1 parent d0610ad commit 1281f44
Show file tree
Hide file tree
Showing 12 changed files with 619 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,29 @@ public void ProjectReferencesIsPopulated()
StringAssert.EndsWith("other.csproj", package.ProjectReferences.First());
}

[Test]
public void RelativeProjectReferencesIsPopulated()
{
const string packagesText = @"<PackageReference Include=""foo"" Version=""1.2.3""></PackageReference>";

var projectFile = Vs2017ProjectFileTemplateWithPackages.Replace("{{Packages}}", packagesText);

var relativePath = $"..{Path.DirectorySeparatorChar}other{Path.DirectorySeparatorChar}other.csproj";
projectFile = projectFile.Replace("other.csproj", relativePath);

var reader = MakeReader();
var packages = reader.Read(StreamFromString(projectFile), _sampleDirectory, _sampleFile);

var package = packages.FirstOrDefault();

Assert.That(package.ProjectReferences.Count, Is.EqualTo(1));

var path = package.ProjectReferences.First();

StringAssert.EndsWith($"other{Path.DirectorySeparatorChar}other.csproj", path);
StringAssert.DoesNotContain("..", path);
}

[Test]
public void SinglePackageIsCorectlyRead()
{
Expand Down
173 changes: 173 additions & 0 deletions NuKeeper.Inspection.Tests/Sort/PackageInProjectTopologicalSortTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NSubstitute;
using NuGet.Packaging.Core;
using NuGet.Versioning;
using NuKeeper.Inspection.Logging;
using NuKeeper.Inspection.RepositoryInspection;
using NuKeeper.Inspection.Sort;
using NUnit.Framework;

namespace NuKeeper.Inspection.Tests.Sort
{
[TestFixture]
public class PackageInProjectTopologicalSortTests
{
[Test]
public void CanSortEmptyList()
{
var items = new List<PackageInProject>();

var sorter = new PackageInProjectTopologicalSort(Substitute.For<INuKeeperLogger>());

var sorted = sorter.Sort(items)
.ToList();

Assert.That(sorted, Is.Not.Null);
Assert.That(sorted, Is.Empty);
}

[Test]
public void CanSortOneItem()
{
var items = new List<PackageInProject>
{
PackageFor("foo", "1.2.3", "bar{sep}fish.csproj"),
};

var sorter = new PackageInProjectTopologicalSort(Substitute.For<INuKeeperLogger>());

var sorted = sorter.Sort(items)
.ToList();

AssertIsASortOf(sorted, items);
Assert.That(sorted[0], Is.EqualTo(items[0]));
}

[Test]
public void CanSortTwoUnrelatedItems()
{
var items = new List<PackageInProject>
{
PackageFor("foo", "1.2.3", "bar{sep}fish.csproj"),
PackageFor("bar", "2.3.4", "project2{sep}p2.csproj")
};

var logger = Substitute.For<INuKeeperLogger>();

var sorter = new PackageInProjectTopologicalSort(logger);

var sorted = sorter.Sort(items)
.ToList();

AssertIsASortOf(sorted, items);
logger.Received(1).Detailed("No dependencies between items, no need to sort on dependencies");
}

[Test]
public void CanSortTwoRelatedItemsinCorrectOrder()
{
var aProj = PackageFor("foo", "1.2.3", "someproject{sep}someproject.csproj");
var testProj = PackageFor("bar", "2.3.4", "someproject.tests{sep}someproject.tests.csproj", aProj);

var items = new List<PackageInProject>
{
testProj,
aProj
};

var logger = Substitute.For<INuKeeperLogger>();

var sorter = new PackageInProjectTopologicalSort(logger);

var sorted = sorter.Sort(items)
.ToList();

AssertIsASortOf(sorted, items);
Assert.That(sorted[0], Is.EqualTo(items[0]));
Assert.That(sorted[1], Is.EqualTo(items[1]));

logger.DidNotReceive().Detailed("No dependencies between items, no need to sort on dependencies");
logger.Received(1).Detailed("Sorted 2 projects by dependencies but no change made");
}

[Test]
public void CanSortTwoRelatedItemsinReverseOrder()
{
var aProj = PackageFor("foo", "1.2.3", "someproject{sep}someproject.csproj");
var testProj = PackageFor("bar", "2.3.4", "someproject.tests{sep}someproject.tests.csproj", aProj);

var items = new List<PackageInProject>
{
aProj,
testProj
};

var logger = Substitute.For<INuKeeperLogger>();

var sorter = new PackageInProjectTopologicalSort(logger);

var sorted = sorter.Sort(items)
.ToList();

AssertIsASortOf(sorted, items);
Assert.That(sorted[0], Is.EqualTo(testProj));
Assert.That(sorted[1], Is.EqualTo(aProj));

logger.Received(1).Detailed(Arg.Is<string>(s => s.StartsWith("Resorted 2 projects by dependencies,")));
}

[Test]
public void CanSortWithCycle()
{
var aProj = PackageFor("foo", "1.2.3", "someproject{sep}someproject.csproj");
var testProj = PackageFor("bar", "2.3.4", "someproject.tests{sep}someproject.tests.csproj", aProj);
// fake a circular ref - aproj is a new object but the same file path as above
aProj = PackageFor("foo", "1.2.3", "someproject{sep}someproject.csproj", testProj);

var items = new List<PackageInProject>
{
aProj,
testProj
};

var logger = Substitute.For<INuKeeperLogger>();

var sorter = new PackageInProjectTopologicalSort(logger);

var sorted = sorter.Sort(items)
.ToList();

AssertIsASortOf(sorted, items);
logger.Received(1).Minimal(Arg.Is<string>(s => s.StartsWith("Cannot sort by dependencies, cycle found at item")));
}

private static void AssertIsASortOf(List<PackageInProject> sorted, List<PackageInProject> original)
{
Assert.That(sorted, Is.Not.Null);
Assert.That(sorted, Is.Not.Empty);
Assert.That(sorted.Count, Is.EqualTo(original.Count));
CollectionAssert.AreEquivalent(sorted, original);
}

private PackageInProject PackageFor(string packageId, string packageVersion,
string relativePath, PackageInProject refProject = null)
{
relativePath = relativePath.Replace("{sep}", $"{Path.DirectorySeparatorChar}");
var basePath = "c_temp" + Path.DirectorySeparatorChar + "test";

var refs = new List<string>();

if (refProject != null)
{
refs.Add(refProject.Path.FullName);
}

return new PackageInProject(
new PackageIdentity(packageId, new NuGetVersion(packageVersion)),
new PackagePath(basePath, relativePath, PackageReferenceType.ProjectFile),
refs);
}
}
}
Loading

0 comments on commit 1281f44

Please sign in to comment.