diff --git a/CentralPackageManagementMigrator.slnx b/CentralPackageManagementMigrator.slnx index 28ec55e..1117e04 100644 --- a/CentralPackageManagementMigrator.slnx +++ b/CentralPackageManagementMigrator.slnx @@ -1,4 +1,5 @@ + diff --git a/global.json b/global.json new file mode 100644 index 0000000..3140116 --- /dev/null +++ b/global.json @@ -0,0 +1,5 @@ +{ + "test": { + "runner": "Microsoft.Testing.Platform" + } +} diff --git a/src/CentralPackageManagementMigrator/CentralPackageManagementMigrator.csproj b/src/CentralPackageManagementMigrator/CentralPackageManagementMigrator.csproj index 99789d8..18c53b7 100644 --- a/src/CentralPackageManagementMigrator/CentralPackageManagementMigrator.csproj +++ b/src/CentralPackageManagementMigrator/CentralPackageManagementMigrator.csproj @@ -30,12 +30,13 @@ - - - + + + + diff --git a/src/CentralPackageManagementMigrator/LoggingUtility.cs b/src/CentralPackageManagementMigrator/LoggingUtility.cs index aa9c8ea..e66ad3e 100644 --- a/src/CentralPackageManagementMigrator/LoggingUtility.cs +++ b/src/CentralPackageManagementMigrator/LoggingUtility.cs @@ -33,7 +33,7 @@ public static void SetupLogging(LogLevel logLevel) /// existing logs that haven't been output yet. Failure to call this /// method may result in lost messages. /// - public static void FlushLogging() => Factory?.Dispose(); + public static void FlushLogging() => Factory.Dispose(); public static ILogger CreateLogger() => Factory.CreateLogger(); } diff --git a/src/CentralPackageManagementMigrator/MigratorCommand.cs b/src/CentralPackageManagementMigrator/MigratorCommand.cs index a9e7559..32e30b2 100644 --- a/src/CentralPackageManagementMigrator/MigratorCommand.cs +++ b/src/CentralPackageManagementMigrator/MigratorCommand.cs @@ -21,7 +21,17 @@ public MigratorCommand() : base(CommandDescription) SetAction(parseResult => { var logLevel = parseResult.GetRequiredValue(_logLevelOption); - return Migrate(logLevel); + + try + { + return Migrate(logLevel); + } + catch + { + // Uncaught exception occurred. Indicate error. + } + + return 1; }); } diff --git a/tests/CentralPackageManagementMigrator.IntegrationTests/CentralPackageManagementMigrator.IntegrationTests.csproj b/tests/CentralPackageManagementMigrator.IntegrationTests/CentralPackageManagementMigrator.IntegrationTests.csproj new file mode 100644 index 0000000..eb690d1 --- /dev/null +++ b/tests/CentralPackageManagementMigrator.IntegrationTests/CentralPackageManagementMigrator.IntegrationTests.csproj @@ -0,0 +1,29 @@ + + + + net10.0 + Exe + enable + enable + false + + + + + + + + + Always + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/CentralPackageManagementMigrator.IntegrationTests/Helper.cs b/tests/CentralPackageManagementMigrator.IntegrationTests/Helper.cs new file mode 100644 index 0000000..6646663 --- /dev/null +++ b/tests/CentralPackageManagementMigrator.IntegrationTests/Helper.cs @@ -0,0 +1,169 @@ +using System.Reflection; + +namespace CentralPackageManagementMigrator.IntegrationTests; + +internal sealed class Helper : IDisposable +{ + /// + /// Contains absolute paths to various directories used for the test. + /// + /// + /// The temporary directory created for the requested test. Will serve as + /// the working directory for the migrator command to run in. + /// + /// + /// Path to the Actual directory that contains setup files for the + /// test. + /// + /// + /// Path to the Expected directory that contains expected files for + /// the test. + /// + private readonly record struct WorkDirectory(string Base, string Actual, string Expected); + + private WorkDirectory WorkDirectoryInfo { get; init; } + + private bool _disposed; + + private Helper() + { + } + + ~Helper() + { + Dispose(false); + } + + public static Helper Create(string test) + { + var helper = new Helper + { + WorkDirectoryInfo = FindWorkDirectory(test) + }; + + // Copy actual files to the work directory. + CopyDirectory(helper.WorkDirectoryInfo.Actual, helper.WorkDirectoryInfo.Base); + + return helper; + } + + public async Task RunMigrator() + { + Directory.SetCurrentDirectory(WorkDirectoryInfo.Base); + + var command = new MigratorCommand(); + return await command.Parse([]).InvokeAsync(null, TestContext.Current.CancellationToken); + } + + public async Task AssertDirectoryPackagesFile() + { + var directoryPackagesPath = Path.Combine(WorkDirectoryInfo.Base, "Directory.Packages.props"); + + Assert.True(Path.Exists(directoryPackagesPath), $"'{directoryPackagesPath}' not found"); + + var actual = await File.ReadAllTextAsync(directoryPackagesPath, TestContext.Current.CancellationToken); + var expected = await File.ReadAllTextAsync(Path.Combine(WorkDirectoryInfo.Expected, "Directory.Packages.xml"), + TestContext.Current.CancellationToken); + + Assert.Equal(actual, expected); + } + + public async Task AssertProjectFile(string filename) + { + var actualFilename = Path.Combine(WorkDirectoryInfo.Base, filename + ".csproj"); + Assert.True(Path.Exists(actualFilename), $"'{actualFilename}' not found"); + + var actual = await File.ReadAllTextAsync(actualFilename, TestContext.Current.CancellationToken); + + var expectedFilename = Path.Combine(WorkDirectoryInfo.Expected, filename + ".xml"); + Assert.True(Path.Exists(expectedFilename), $"'{expectedFilename}' not found"); + + var expected = await File.ReadAllTextAsync(expectedFilename, TestContext.Current.CancellationToken); + + Assert.Equal(actual, expected); + } + + private static WorkDirectory FindWorkDirectory(string test) + { + var assemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + Assert.NotNull(assemblyDirectory); + + // Ensure test data is set up correctly. + + var testDataDirectory = Path.Combine(assemblyDirectory, "TestData", test); + Assert.True(Directory.Exists(testDataDirectory), $"'{testDataDirectory}' directory cannot be found"); + + var actualDirectory = Path.Combine(testDataDirectory, "Actual"); + Assert.True(Directory.Exists(actualDirectory), "'Actual' subdirectory cannot be found"); + + var expectedDirectory = Path.Combine(testDataDirectory, "Expected"); + Assert.True(Directory.Exists(expectedDirectory), "'Expected' subdirectory cannot be found"); + + var tempDirectory = Directory.CreateTempSubdirectory().FullName; + + return new WorkDirectory(tempDirectory, actualDirectory, expectedDirectory); + } + + /// + private static void CopyDirectory(string source, string destination) + { + var dir = new DirectoryInfo(source); + Assert.True(dir.Exists, $"Source directory '{source}' not found"); + + var dirs = dir.GetDirectories(); + + Directory.CreateDirectory(destination); + + foreach (var file in dir.GetFiles()) + { + string filename; + + if (file.Name.StartsWith("project", StringComparison.InvariantCultureIgnoreCase)) + { + filename = Path.GetFileNameWithoutExtension(file.Name) + ".csproj"; + } + else if (file.Name.StartsWith("directory.packages", StringComparison.InvariantCultureIgnoreCase)) + { + filename = Path.GetFileNameWithoutExtension(file.Name) + ".props"; + } + else + { + filename = file.Name; + } + + var target = Path.Combine(destination, filename); + file.CopyTo(target); + } + + foreach (var subDirectory in dirs) + { + var newDestination = Path.Combine(destination, subDirectory.Name); + CopyDirectory(subDirectory.FullName, newDestination); + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (_disposed || !disposing) + { + return; + } + + try + { + Directory.Delete(WorkDirectoryInfo.Base, true); + } + catch + { + // Let OS prune it eventually + } + + _disposed = true; + } +} diff --git a/tests/CentralPackageManagementMigrator.IntegrationTests/IntegrationTests.cs b/tests/CentralPackageManagementMigrator.IntegrationTests/IntegrationTests.cs new file mode 100644 index 0000000..8d51771 --- /dev/null +++ b/tests/CentralPackageManagementMigrator.IntegrationTests/IntegrationTests.cs @@ -0,0 +1,52 @@ +namespace CentralPackageManagementMigrator.IntegrationTests; + +public class IntegrationTests +{ + [Fact] + public async Task Test001_BasicExample() + { + using var helper = Helper.Create("Test001"); + + var exitCode = await helper.RunMigrator(); + + Assert.Equal(0, exitCode); + await helper.AssertDirectoryPackagesFile(); + await helper.AssertProjectFile("Project"); + } + + [Fact] + public async Task Test002_PackageVersionAsChildElement() + { + using var helper = Helper.Create("Test002"); + + var exitCode = await helper.RunMigrator(); + + Assert.Equal(0, exitCode); + await helper.AssertDirectoryPackagesFile(); + await helper.AssertProjectFile("Project"); + } + + [Fact] + public async Task Test003_PackageNamesCaseInsensitive() + { + using var helper = Helper.Create("Test003"); + + var exitCode = await helper.RunMigrator(); + + Assert.Equal(0, exitCode); + await helper.AssertDirectoryPackagesFile(); + await helper.AssertProjectFile("ProjectA"); + await helper.AssertProjectFile("ProjectB"); + } + + [Fact] + public async Task Test004_DirectoryPackagesPropsAlreadyExists() + { + using var helper = Helper.Create("Test004"); + + var exitCode = await helper.RunMigrator(); + + Assert.Equal(1, exitCode); + await helper.AssertProjectFile("Project"); + } +} diff --git a/tests/CentralPackageManagementMigrator.IntegrationTests/README.md b/tests/CentralPackageManagementMigrator.IntegrationTests/README.md new file mode 100644 index 0000000..734402d --- /dev/null +++ b/tests/CentralPackageManagementMigrator.IntegrationTests/README.md @@ -0,0 +1,7 @@ +# Integration Tests + +Each scenario is stored under the [`TestData`](./TestData) directory as its own subdirectory. + +Within it, there are two additional subdirectories: `Actual` and `Expected`. Everything in the `Actual` subdirectory is copied to a temporary directory for the tool to work from -- all files and subdirectories are recursively copied. After the tool is invoked, the test case can make assertions on the resulting files against those in the `Expected` directory for equality. + +All the test files have had their extensions changed since having .CSPROJ files and .PROPS files could affect the solution. When these files are copied in preparation for the tool, their extensions are renamed to their intended use. `ProjectA.xml` becomes `ProjectA.csproj`, for example. diff --git a/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test001/Actual/Project.xml b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test001/Actual/Project.xml new file mode 100644 index 0000000..b441a2b --- /dev/null +++ b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test001/Actual/Project.xml @@ -0,0 +1,8 @@ + + + net6.0 + + + + + \ No newline at end of file diff --git a/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test001/Expected/Directory.Packages.xml b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test001/Expected/Directory.Packages.xml new file mode 100644 index 0000000..1d51991 --- /dev/null +++ b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test001/Expected/Directory.Packages.xml @@ -0,0 +1,8 @@ + + + true + + + + + \ No newline at end of file diff --git a/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test001/Expected/Project.xml b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test001/Expected/Project.xml new file mode 100644 index 0000000..641b0ff --- /dev/null +++ b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test001/Expected/Project.xml @@ -0,0 +1,8 @@ + + + net6.0 + + + + + \ No newline at end of file diff --git a/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test002/Actual/Project.xml b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test002/Actual/Project.xml new file mode 100644 index 0000000..03d740a --- /dev/null +++ b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test002/Actual/Project.xml @@ -0,0 +1,10 @@ + + + net6.0 + + + + 17.9.0 + + + \ No newline at end of file diff --git a/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test002/Expected/Directory.Packages.xml b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test002/Expected/Directory.Packages.xml new file mode 100644 index 0000000..1d51991 --- /dev/null +++ b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test002/Expected/Directory.Packages.xml @@ -0,0 +1,8 @@ + + + true + + + + + \ No newline at end of file diff --git a/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test002/Expected/Project.xml b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test002/Expected/Project.xml new file mode 100644 index 0000000..641b0ff --- /dev/null +++ b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test002/Expected/Project.xml @@ -0,0 +1,8 @@ + + + net6.0 + + + + + \ No newline at end of file diff --git a/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test003/Actual/ProjectA.xml b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test003/Actual/ProjectA.xml new file mode 100644 index 0000000..67397f9 --- /dev/null +++ b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test003/Actual/ProjectA.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test003/Actual/ProjectB.xml b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test003/Actual/ProjectB.xml new file mode 100644 index 0000000..253be39 --- /dev/null +++ b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test003/Actual/ProjectB.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test003/Expected/Directory.Packages.xml b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test003/Expected/Directory.Packages.xml new file mode 100644 index 0000000..a0a313a --- /dev/null +++ b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test003/Expected/Directory.Packages.xml @@ -0,0 +1,8 @@ + + + true + + + + + \ No newline at end of file diff --git a/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test003/Expected/ProjectA.xml b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test003/Expected/ProjectA.xml new file mode 100644 index 0000000..89bfd51 --- /dev/null +++ b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test003/Expected/ProjectA.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test003/Expected/ProjectB.xml b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test003/Expected/ProjectB.xml new file mode 100644 index 0000000..c7013c2 --- /dev/null +++ b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test003/Expected/ProjectB.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test004/Actual/Directory.Packages.xml b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test004/Actual/Directory.Packages.xml new file mode 100644 index 0000000..1d51991 --- /dev/null +++ b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test004/Actual/Directory.Packages.xml @@ -0,0 +1,8 @@ + + + true + + + + + \ No newline at end of file diff --git a/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test004/Actual/Project.xml b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test004/Actual/Project.xml new file mode 100644 index 0000000..b441a2b --- /dev/null +++ b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test004/Actual/Project.xml @@ -0,0 +1,8 @@ + + + net6.0 + + + + + \ No newline at end of file diff --git a/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test004/Expected/Project.xml b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test004/Expected/Project.xml new file mode 100644 index 0000000..b441a2b --- /dev/null +++ b/tests/CentralPackageManagementMigrator.IntegrationTests/TestData/Test004/Expected/Project.xml @@ -0,0 +1,8 @@ + + + net6.0 + + + + + \ No newline at end of file diff --git a/tests/CentralPackageManagementMigrator.Tests/CentralPackageManagementMigrator.Tests.csproj b/tests/CentralPackageManagementMigrator.Tests/CentralPackageManagementMigrator.Tests.csproj index a8f2ddc..67b49e9 100644 --- a/tests/CentralPackageManagementMigrator.Tests/CentralPackageManagementMigrator.Tests.csproj +++ b/tests/CentralPackageManagementMigrator.Tests/CentralPackageManagementMigrator.Tests.csproj @@ -2,6 +2,7 @@ net10.0 + Exe enable false true @@ -9,20 +10,11 @@ - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - + - +