From 44b14f987ef4f2c629535c686f2a611226941381 Mon Sep 17 00:00:00 2001 From: Satya Madala Date: Thu, 19 Jan 2017 11:27:37 +0530 Subject: [PATCH 1/8] Add results directory arg to dotnet test --- src/dotnet/commands/dotnet-test/LocalizableStrings.cs | 2 ++ src/dotnet/commands/dotnet-test/Program.cs | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/dotnet/commands/dotnet-test/LocalizableStrings.cs b/src/dotnet/commands/dotnet-test/LocalizableStrings.cs index 0f69a5cc8..af567dceb 100644 --- a/src/dotnet/commands/dotnet-test/LocalizableStrings.cs +++ b/src/dotnet/commands/dotnet-test/LocalizableStrings.cs @@ -55,5 +55,7 @@ public const string RunSettingsArgsHelpText = @"Any extra commandline runsettings arguments that should be passed to vstest. See 'dotnet vstest --help' for available options. Example: -- RunConfiguration.ResultsDirectory=""C:\users\user\desktop\Results Directory"" MSTest.DeploymentEnabled=false"; + public const string CmdResultsDirectoryDescription = @"Test results directory will be created in specified path if not exists. + Example: --results-directory "; } } diff --git a/src/dotnet/commands/dotnet-test/Program.cs b/src/dotnet/commands/dotnet-test/Program.cs index 89d0c3595..26a57f494 100644 --- a/src/dotnet/commands/dotnet-test/Program.cs +++ b/src/dotnet/commands/dotnet-test/Program.cs @@ -83,6 +83,11 @@ namespace Microsoft.DotNet.Tools.Test LocalizableStrings.CmdNoBuildDescription, CommandOptionType.NoValue); + var resultsDirectoryOption = cmd.Option( + "-r|--results-directory", + LocalizableStrings.CmdResultsDirectoryDescription, + CommandOptionType.SingleValue); + CommandOption verbosityOption = MSBuildForwardingApp.AddVerbosityOption(cmd); cmd.OnExecute(() => @@ -129,6 +134,11 @@ namespace Microsoft.DotNet.Tools.Test msbuildArgs.Add($"/p:TargetFramework={frameworkOption.Value()}"); } + if (resultsDirectoryOption.HasValue()) + { + msbuildArgs.Add($"/p:VSTestResultsDirectory={resultsDirectoryOption.Value()}"); + } + if (outputOption.HasValue()) { msbuildArgs.Add($"/p:OutputPath={outputOption.Value()}"); From 5bbac55736ab0246b00fe2d8933b0d29b7a42800 Mon Sep 17 00:00:00 2001 From: Justin Goshi Date: Thu, 19 Jan 2017 11:23:01 -0800 Subject: [PATCH 2/8] Migration: do not add a csproj to the solution if it already exists --- .../TestApp/Program.cs | 16 ++++++++++ .../TestApp/TestApp.sln | 25 ++++++++++++++++ .../TestApp/TestApp.xproj | 18 +++++++++++ .../TestApp/project.json | 30 +++++++++++++++++++ .../TestLibrary/Helper.cs | 15 ++++++++++ .../TestLibrary/TestLibrary.csproj | 13 ++++++++ .../TestLibrary/TestLibrary.xproj | 18 +++++++++++ .../TestLibrary/project.json | 9 ++++++ .../commands/dotnet-migrate/MigrateCommand.cs | 21 +++++++++---- .../GivenThatIWantToMigrateSolutions.cs | 18 +++++++++++ 10 files changed, 177 insertions(+), 6 deletions(-) create mode 100644 TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/Program.cs create mode 100644 TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/TestApp.sln create mode 100644 TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/TestApp.xproj create mode 100644 TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/project.json create mode 100644 TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/Helper.cs create mode 100644 TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/TestLibrary.csproj create mode 100644 TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/TestLibrary.xproj create mode 100644 TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/project.json diff --git a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/Program.cs b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/Program.cs new file mode 100644 index 000000000..7937a9ba0 --- /dev/null +++ b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/Program.cs @@ -0,0 +1,16 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace TestApp +{ + public class Program + { + public static int Main(string[] args) + { + Console.WriteLine(TestLibrary.Helper.GetMessage()); + return 0; + } + } +} diff --git a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/TestApp.sln b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/TestApp.sln new file mode 100644 index 000000000..0935de81a --- /dev/null +++ b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/TestApp.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TestApp", "TestApp.xproj", "{0138CB8F-4AA9-4029-A21E-C07C30F425BA}" +EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TestLibrary", "..\TestLibrary\TestLibrary.csproj", "{DC0B35D0-8A36-4B52-8A11-B86739F055D2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0138CB8F-4AA9-4029-A21E-C07C30F425BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0138CB8F-4AA9-4029-A21E-C07C30F425BA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0138CB8F-4AA9-4029-A21E-C07C30F425BA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0138CB8F-4AA9-4029-A21E-C07C30F425BA}.Release|Any CPU.Build.0 = Release|Any CPU + {DC0B35D0-8A36-4B52-8A11-B86739F055D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DC0B35D0-8A36-4B52-8A11-B86739F055D2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DC0B35D0-8A36-4B52-8A11-B86739F055D2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DC0B35D0-8A36-4B52-8A11-B86739F055D2}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/TestApp.xproj b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/TestApp.xproj new file mode 100644 index 000000000..d18702195 --- /dev/null +++ b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/TestApp.xproj @@ -0,0 +1,18 @@ + + + + 14.0.23107 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 0138cb8f-4aa9-4029-a21e-c07c30f425ba + TestAppWithContents + ..\..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\..\artifacts\ + + + 2.0 + + + diff --git a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/project.json b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/project.json new file mode 100644 index 000000000..666d644b9 --- /dev/null +++ b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestApp/project.json @@ -0,0 +1,30 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "dependencies": { + "TestLibrary": { + "target": "project", + "version": "1.0.0-*" + }, + "Microsoft.NETCore.App": "1.0.1" + }, + "frameworks": { + "netcoreapp1.0": {} + }, + "runtimes": { + "win7-x64": {}, + "win7-x86": {}, + "osx.10.10-x64": {}, + "osx.10.11-x64": {}, + "ubuntu.14.04-x64": {}, + "ubuntu.16.04-x64": {}, + "centos.7-x64": {}, + "rhel.7.2-x64": {}, + "debian.8-x64": {}, + "fedora.23-x64": {}, + "opensuse.13.2-x64": {} + } +} diff --git a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/Helper.cs b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/Helper.cs new file mode 100644 index 000000000..6c3bc0e53 --- /dev/null +++ b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/Helper.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace TestLibrary +{ + public static class Helper + { + public static string GetMessage() + { + return "This string came from the test library!"; + } + } +} diff --git a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/TestLibrary.csproj b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/TestLibrary.csproj new file mode 100644 index 000000000..2debc348d --- /dev/null +++ b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/TestLibrary.csproj @@ -0,0 +1,13 @@ + + + + netstandard1.5 + TestLibrary + TestLibrary + + + + + + + diff --git a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/TestLibrary.xproj b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/TestLibrary.xproj new file mode 100644 index 000000000..dc8eb7060 --- /dev/null +++ b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/TestLibrary.xproj @@ -0,0 +1,18 @@ + + + + 14.0.23107 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + dc0b35d0-8a36-4b52-8a11-b86739f055d2 + TestAppWithContents + ..\..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\..\artifacts\ + + + 2.0 + + + diff --git a/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/project.json b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/project.json new file mode 100644 index 000000000..032754312 --- /dev/null +++ b/TestAssets/NonRestoredTestProjects/PJAppWithSlnAndOneAlreadyMigratedCsproj/TestLibrary/project.json @@ -0,0 +1,9 @@ +{ + "version": "1.0.0-*", + "dependencies": { + "NETStandard.Library": "1.6.0" + }, + "frameworks": { + "netstandard1.5": {} + } +} diff --git a/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs b/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs index 9a61d3a3e..54f9a56a2 100644 --- a/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs +++ b/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs @@ -109,17 +109,18 @@ namespace Microsoft.DotNet.Tools.Migrate return; } - List csprojFilesToAdd = new List(); + var csprojFilesToAdd = new HashSet(); var slnPathWithTrailingSlash = PathUtility.EnsureTrailingSlash(_slnFile.BaseDirectory); foreach (var report in migrationReport.ProjectMigrationReports) { var reportPathWithTrailingSlash = PathUtility.EnsureTrailingSlash(report.ProjectDirectory); - var reportRelPath = Path.Combine( - PathUtility.GetRelativePath(slnPathWithTrailingSlash, reportPathWithTrailingSlash), - report.ProjectName + ".xproj"); + var relReportPath = PathUtility.GetRelativePath( + slnPathWithTrailingSlash, + reportPathWithTrailingSlash); - var projects = _slnFile.Projects.Where(p => p.FilePath == reportRelPath); + var xprojPath = Path.Combine(relReportPath, report.ProjectName + ".xproj"); + var projects = _slnFile.Projects.Where(p => p.FilePath == xprojPath); var migratedProjectName = report.ProjectName + ".csproj"; if (projects.Count() == 1) @@ -132,7 +133,15 @@ namespace Microsoft.DotNet.Tools.Migrate } else { - csprojFilesToAdd.Add(Path.Combine(report.ProjectDirectory, migratedProjectName)); + var csprojPath = Path.Combine(relReportPath, migratedProjectName); + var slnAlreadyContainsMigratedCsproj = _slnFile.Projects + .Where(p => p.FilePath == csprojPath) + .Any(); + + if (!slnAlreadyContainsMigratedCsproj) + { + csprojFilesToAdd.Add(Path.Combine(report.ProjectDirectory, migratedProjectName)); + } } foreach (var preExisting in report.PreExistingCsprojDependencies) diff --git a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs index 17ee1299a..2111a9ac7 100644 --- a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs +++ b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs @@ -38,6 +38,24 @@ namespace Microsoft.DotNet.Migration.Tests "PJAppWithSlnAndXprojRefThatRefsCsprojWhereSlnDoesNotRefCsproj"); } + [Fact] + public void WhenSolutionContainsACsprojFileItDoesNotTryToAddItAgain() + { + var projectDirectory = TestAssets + .Get("NonRestoredTestProjects", "PJAppWithSlnAndOneAlreadyMigratedCsproj") + .CreateInstance() + .WithSourceFiles() + .Root; + + var solutionRelPath = Path.Combine("TestApp", "TestApp.sln"); + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"migrate \"{solutionRelPath}\""); + cmd.Should().Pass(); + cmd.StdOut.Should().NotContain("already contains project"); + cmd.StdErr.Should().BeEmpty(); + } + private void MigrateAndBuild(string groupName, string projectName, [CallerMemberName] string callingMethod = "", string identifier = "") { var projectDirectory = TestAssets From 717d0a45fa722897f7a418a679c08a2e1df6fc8e Mon Sep 17 00:00:00 2001 From: Justin Goshi Date: Fri, 20 Jan 2017 12:21:04 -0800 Subject: [PATCH 3/8] Moving existing csproj files with same name as migration output to backup --- .../MigrationBackupPlan.cs | 22 ++++++++++-- .../ProjectMigrator.cs | 35 +++++++++++-------- .../commands/dotnet-migrate/MigrateCommand.cs | 17 +++++---- .../GivenThatIWantToMigrateSolutions.cs | 24 +++++++++++++ 4 files changed, 72 insertions(+), 26 deletions(-) diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/MigrationBackupPlan.cs b/src/Microsoft.DotNet.ProjectJsonMigration/MigrationBackupPlan.cs index c0423293f..43325ea77 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/MigrationBackupPlan.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/MigrationBackupPlan.cs @@ -11,6 +11,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration { internal class MigrationBackupPlan { + private const string TempCsprojExtention = ".migration_in_place_backup"; + private readonly FileInfo globalJson; public MigrationBackupPlan( @@ -57,7 +59,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration .Where(f => f.Name == "project.json" || f.Extension == ".xproj" || f.FullName.EndsWith(".xproj.user") - || f.FullName.EndsWith(".lock.json")); + || f.FullName.EndsWith(".lock.json") + || f.FullName.EndsWith(TempCsprojExtention)); } public DirectoryInfo ProjectBackupDirectory { get; } @@ -81,10 +84,23 @@ namespace Microsoft.DotNet.ProjectJsonMigration foreach (var file in FilesToMove) { + var fileName = file.Name.EndsWith(TempCsprojExtention) + ? Path.GetFileNameWithoutExtension(file.Name) + : file.Name; + file.MoveTo( - Path.Combine( - ProjectBackupDirectory.FullName, file.Name)); + Path.Combine(ProjectBackupDirectory.FullName, fileName)); } } + + public static void RenameCsprojFromMigrationOutputNameToTempName(string outputProject) + { + var backupFileName = $"{outputProject}{TempCsprojExtention}"; + if (File.Exists(backupFileName)) + { + File.Delete(backupFileName); + } + File.Move(outputProject, backupFileName); + } } } diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectMigrator.cs b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectMigrator.cs index 3aaeebda5..2596d8f2f 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/ProjectMigrator.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/ProjectMigrator.cs @@ -20,6 +20,7 @@ namespace Microsoft.DotNet.ProjectJsonMigration { private readonly IMigrationRule _ruleSet; private readonly ProjectDependencyFinder _projectDependencyFinder = new ProjectDependencyFinder(); + private HashSet _migratedProjects = new HashSet(); public ProjectMigrator() : this(new DefaultMigrationRuleSet()) { } @@ -76,7 +77,6 @@ namespace Microsoft.DotNet.ProjectJsonMigration var settings = new MigrationSettings(projectDir, projectDir, rootSettings.MSBuildProjectTemplatePath); - MigrateProject(settings); projectMigrationReports.Add(MigrateProject(settings)); } @@ -141,13 +141,28 @@ namespace Microsoft.DotNet.ProjectJsonMigration { var migrationRuleInputs = ComputeMigrationRuleInputs(migrationSettings); var projectName = migrationRuleInputs.DefaultProjectContext.GetProjectName(); + var outputProject = Path.Combine(migrationSettings.OutputDirectory, projectName + ".csproj"); try { - if (IsMigrated(migrationSettings, migrationRuleInputs)) + if (File.Exists(outputProject)) { - MigrationTrace.Instance.WriteLine(String.Format(LocalizableStrings.SkipMigrationAlreadyMigrated, nameof(ProjectMigrator), migrationSettings.ProjectDirectory)); - return new ProjectMigrationReport(migrationSettings.ProjectDirectory, projectName, skipped: true); + if (_migratedProjects.Contains(outputProject)) + { + MigrationTrace.Instance.WriteLine(String.Format( + LocalizableStrings.SkipMigrationAlreadyMigrated, + nameof(ProjectMigrator), + migrationSettings.ProjectDirectory)); + + return new ProjectMigrationReport( + migrationSettings.ProjectDirectory, + projectName, + skipped: true); + } + else + { + MigrationBackupPlan.RenameCsprojFromMigrationOutputNameToTempName(outputProject); + } } VerifyInputs(migrationRuleInputs, migrationSettings); @@ -185,7 +200,8 @@ namespace Microsoft.DotNet.ProjectJsonMigration } } - var outputProject = Path.Combine(migrationSettings.OutputDirectory, projectName + ".csproj"); + _migratedProjects.Add(outputProject); + return new ProjectMigrationReport( migrationSettings.ProjectDirectory, projectName, @@ -286,14 +302,5 @@ namespace Microsoft.DotNet.ProjectJsonMigration File.Copy(sourceFilePath, destinationFilePath); } } - - public bool IsMigrated(MigrationSettings migrationSettings, MigrationRuleInputs migrationRuleInputs) - { - var outputName = migrationRuleInputs.DefaultProjectContext.GetProjectName(); - - var outputProject = Path.Combine(migrationSettings.OutputDirectory, outputName + ".csproj"); - return File.Exists(outputProject); - } - } } diff --git a/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs b/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs index 9f6dc5444..f1b97846a 100644 --- a/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs +++ b/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs @@ -119,17 +119,17 @@ namespace Microsoft.DotNet.Tools.Migrate foreach (var report in migrationReport.ProjectMigrationReports) { var reportPathWithTrailingSlash = PathUtility.EnsureTrailingSlash(report.ProjectDirectory); - var relReportPath = PathUtility.GetRelativePath( + var relativeReportPath = PathUtility.GetRelativePath( slnPathWithTrailingSlash, reportPathWithTrailingSlash); - var xprojPath = Path.Combine(relReportPath, report.ProjectName + ".xproj"); - var projects = _slnFile.Projects.Where(p => p.FilePath == xprojPath); + var xprojPath = Path.Combine(relativeReportPath, report.ProjectName + ".xproj"); + var xprojProjectsReferencedBySolution = _slnFile.Projects.Where(p => p.FilePath == xprojPath); var migratedProjectName = report.ProjectName + ".csproj"; - if (projects.Count() == 1) + if (xprojProjectsReferencedBySolution.Count() == 1) { - var slnProject = projects.Single(); + var slnProject = xprojProjectsReferencedBySolution.Single(); slnProject.FilePath = Path.Combine( Path.GetDirectoryName(slnProject.FilePath), migratedProjectName); @@ -137,12 +137,12 @@ namespace Microsoft.DotNet.Tools.Migrate } else { - var csprojPath = Path.Combine(relReportPath, migratedProjectName); - var slnAlreadyContainsMigratedCsproj = _slnFile.Projects + var csprojPath = Path.Combine(relativeReportPath, migratedProjectName); + var solutionContainsCsprojPriorToMigration = _slnFile.Projects .Where(p => p.FilePath == csprojPath) .Any(); - if (!slnAlreadyContainsMigratedCsproj) + if (!solutionContainsCsprojPriorToMigration) { csprojFilesToAdd.Add(Path.Combine(report.ProjectDirectory, migratedProjectName)); } @@ -299,7 +299,6 @@ namespace Microsoft.DotNet.Tools.Migrate if (projectMigrationReport.Errors.Any()) { - sb.AppendLine(RedIfColored($"Project {projectMigrationReport.ProjectName} migration failed ({projectMigrationReport.ProjectDirectory})")); foreach (var error in projectMigrationReport.Errors.Select(e => e.GetFormattedErrorMessage())) diff --git a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs index 9f43a25dc..cb4bbe619 100644 --- a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs +++ b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs @@ -67,6 +67,30 @@ namespace Microsoft.DotNet.Migration.Tests "PJAppWithSlnAndXprojRefThatRefsCsprojWhereSlnDoesNotRefCsproj"); } + [Fact] + public void WhenSolutionContainsACsprojFileItGetsMovedToBackup() + { + var projectDirectory = TestAssets + .Get("NonRestoredTestProjects", "PJAppWithSlnAndOneAlreadyMigratedCsproj") + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var solutionRelPath = Path.Combine("TestApp", "TestApp.sln"); + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"migrate \"{solutionRelPath}\""); + cmd.Should().Pass(); + + File.Exists(Path.Combine(projectDirectory, "TestLibrary", "TestLibrary.csproj")) + .Should().BeTrue(); + File.Exists(Path.Combine(projectDirectory, "TestLibrary", "TestLibrary.csproj.migration_in_place_backup")) + .Should().BeFalse(); + File.Exists(Path.Combine(projectDirectory, "backup", "TestLibrary", "TestLibrary.csproj")) + .Should().BeTrue(); + } + [Fact] public void WhenSolutionContainsACsprojFileItDoesNotTryToAddItAgain() { From b2c51b7269dc5795f6f62fae4e70b81646927eb0 Mon Sep 17 00:00:00 2001 From: Justin Goshi Date: Fri, 20 Jan 2017 16:34:37 -1000 Subject: [PATCH 4/8] Do not add duplicate solution folders or project directories (#5377) * Do not add duplicate solution folders or project directories * Fix the algorithm for removing empty solution folders * Improving code by adding description methods. To address PR comments. --- .../TestAppWithSlnAndSolutionFolders/App.sln | 39 +++++++++ .../src/App/App.csproj | 15 ++++ .../src/App/Program.cs | 10 +++ .../src/src/Lib/Lib.csproj | 11 +++ .../src/src/Lib/Library.cs | 12 +++ src/dotnet/SlnProjectCollectionExtensions.cs | 36 +++----- src/dotnet/SlnProjectExtensions.cs | 41 +++++++-- src/dotnet/commands/dotnet-sln/add/Program.cs | 59 ++++++++++--- .../commands/dotnet-sln/remove/Program.cs | 32 ++++++- .../dotnet-sln-add.Tests/GivenDotnetSlnAdd.cs | 85 ++++++++++++++----- 10 files changed, 270 insertions(+), 70 deletions(-) create mode 100644 TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/App.sln create mode 100644 TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/App/App.csproj create mode 100644 TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/App/Program.cs create mode 100644 TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/src/Lib/Lib.csproj create mode 100644 TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/src/Lib/Library.cs diff --git a/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/App.sln b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/App.sln new file mode 100644 index 000000000..6b63b4437 --- /dev/null +++ b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/App.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26006.2 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "src\App\App.csproj", "{DDF3765C-59FB-4AA6-BE83-779ED13AA64A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{72BFCA87-B033-4721-8712-4D12166B4A39}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Debug|x64.ActiveCfg = Debug|x64 + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Debug|x64.Build.0 = Debug|x64 + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Debug|x86.ActiveCfg = Debug|x86 + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Debug|x86.Build.0 = Debug|x86 + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Release|Any CPU.Build.0 = Release|Any CPU + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Release|x64.ActiveCfg = Release|x64 + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Release|x64.Build.0 = Release|x64 + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Release|x86.ActiveCfg = Release|x86 + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {DDF3765C-59FB-4AA6-BE83-779ED13AA64A} = {72BFCA87-B033-4721-8712-4D12166B4A39} + EndGlobalSection +EndGlobal diff --git a/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/App/App.csproj b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/App/App.csproj new file mode 100644 index 000000000..b38669c62 --- /dev/null +++ b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/App/App.csproj @@ -0,0 +1,15 @@ + + + Exe + netcoreapp1.0 + + + + + + + + + + + diff --git a/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/App/Program.cs b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/App/Program.cs new file mode 100644 index 000000000..abb853a4a --- /dev/null +++ b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/App/Program.cs @@ -0,0 +1,10 @@ +using System; + +class Program +{ + static void Main(string[] args) + { + Console.WriteLine("Hello from the main app"); + Console.WriteLine(Lib.Library.GetMessage()); + } +} diff --git a/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/src/Lib/Lib.csproj b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/src/Lib/Lib.csproj new file mode 100644 index 000000000..9f8bcbb51 --- /dev/null +++ b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/src/Lib/Lib.csproj @@ -0,0 +1,11 @@ + + + + netstandard1.4 + + + + + + + diff --git a/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/src/Lib/Library.cs b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/src/Lib/Library.cs new file mode 100644 index 000000000..205c42a01 --- /dev/null +++ b/TestAssets/TestProjects/TestAppWithSlnAndSolutionFolders/src/src/Lib/Library.cs @@ -0,0 +1,12 @@ +using System; + +namespace Lib +{ + public class Library + { + public static string GetMessage() + { + return "Message from Lib"; + } + } +} diff --git a/src/dotnet/SlnProjectCollectionExtensions.cs b/src/dotnet/SlnProjectCollectionExtensions.cs index 1e964f775..d99b34eee 100644 --- a/src/dotnet/SlnProjectCollectionExtensions.cs +++ b/src/dotnet/SlnProjectCollectionExtensions.cs @@ -10,34 +10,18 @@ namespace Microsoft.DotNet.Tools.Common { public static class SlnProjectCollectionExtensions { - public static HashSet GetReferencedSolutionFolders(this SlnProjectCollection projects) + public static IEnumerable GetProjectsByType( + this SlnProjectCollection projects, + string typeGuid) { - var referencedSolutionFolders = new HashSet(); + return projects.Where(p => p.TypeGuid == typeGuid); + } - var solutionFolderProjects = projects - .Where(p => p.TypeGuid == ProjectTypeGuids.SolutionFolderGuid) - .ToList(); - - if (solutionFolderProjects.Any()) - { - var nonSolutionFolderProjects = projects - .Where(p => p.TypeGuid != ProjectTypeGuids.SolutionFolderGuid) - .ToList(); - - foreach (var project in nonSolutionFolderProjects) - { - var solutionFolders = project.GetSolutionFoldersFromProject(); - foreach (var solutionFolder in solutionFolders) - { - if (!referencedSolutionFolders.Contains(solutionFolder)) - { - referencedSolutionFolders.Add(solutionFolder); - } - } - } - } - - return referencedSolutionFolders; + public static IEnumerable GetProjectsNotOfType( + this SlnProjectCollection projects, + string typeGuid) + { + return projects.Where(p => p.TypeGuid != typeGuid); } } } diff --git a/src/dotnet/SlnProjectExtensions.cs b/src/dotnet/SlnProjectExtensions.cs index 14f730329..925089beb 100644 --- a/src/dotnet/SlnProjectExtensions.cs +++ b/src/dotnet/SlnProjectExtensions.cs @@ -12,17 +12,44 @@ namespace Microsoft.DotNet.Tools.Common { public static IList GetSolutionFoldersFromProject(this SlnProject project) { - var currentDirString = $".{Path.DirectorySeparatorChar}"; + var solutionFolders = new List(); - var directoryPath = Path.GetDirectoryName(project.FilePath); - if (directoryPath.StartsWith(currentDirString)) + var projectFilePath = project.FilePath; + if (IsPathInTreeRootedAtSolutionDirectory(projectFilePath)) { - directoryPath = directoryPath.Substring(currentDirString.Length); + var currentDirString = $".{Path.DirectorySeparatorChar}"; + if (projectFilePath.StartsWith(currentDirString)) + { + projectFilePath = projectFilePath.Substring(currentDirString.Length); + } + + var projectDirectoryPath = TrimProject(projectFilePath); + if (!string.IsNullOrEmpty(projectDirectoryPath)) + { + var solutionFoldersPath = TrimProjectDirectory(projectDirectoryPath); + if (!string.IsNullOrEmpty(solutionFoldersPath)) + { + solutionFolders.AddRange(solutionFoldersPath.Split(Path.DirectorySeparatorChar)); + } + } } - return directoryPath.StartsWith("..") - ? new List() - : new List(directoryPath.Split(Path.DirectorySeparatorChar)); + return solutionFolders; + } + + private static bool IsPathInTreeRootedAtSolutionDirectory(string path) + { + return !path.StartsWith(".."); + } + + private static string TrimProject(string path) + { + return Path.GetDirectoryName(path); + } + + private static string TrimProjectDirectory(string path) + { + return Path.GetDirectoryName(path); } } } diff --git a/src/dotnet/commands/dotnet-sln/add/Program.cs b/src/dotnet/commands/dotnet-sln/add/Program.cs index 5cb8869ce..889506662 100644 --- a/src/dotnet/commands/dotnet-sln/add/Program.cs +++ b/src/dotnet/commands/dotnet-sln/add/Program.cs @@ -163,28 +163,61 @@ namespace Microsoft.DotNet.Tools.Sln.Add "NestedProjects", SlnSectionType.PreProcess); + var pathToGuidMap = GetSolutionFolderPaths(slnFile, nestedProjectsSection.Properties); + string parentDirGuid = null; + var solutionFolderHierarchy = string.Empty; foreach (var dir in solutionFolders) { - var solutionFolder = new SlnProject + solutionFolderHierarchy = Path.Combine(solutionFolderHierarchy, dir); + if (pathToGuidMap.ContainsKey(solutionFolderHierarchy)) { - Id = Guid.NewGuid().ToString("B").ToUpper(), - TypeGuid = ProjectTypeGuids.SolutionFolderGuid, - Name = dir, - FilePath = dir - }; - - slnFile.Projects.Add(solutionFolder); - - if (parentDirGuid != null) - { - nestedProjectsSection.Properties[solutionFolder.Id] = parentDirGuid; + parentDirGuid = pathToGuidMap[solutionFolderHierarchy]; + } + else + { + var solutionFolder = new SlnProject + { + Id = Guid.NewGuid().ToString("B").ToUpper(), + TypeGuid = ProjectTypeGuids.SolutionFolderGuid, + Name = dir, + FilePath = dir + }; + + slnFile.Projects.Add(solutionFolder); + + if (parentDirGuid != null) + { + nestedProjectsSection.Properties[solutionFolder.Id] = parentDirGuid; + } + parentDirGuid = solutionFolder.Id; } - parentDirGuid = solutionFolder.Id; } nestedProjectsSection.Properties[slnProject.Id] = parentDirGuid; } } + + private IDictionary GetSolutionFolderPaths(SlnFile slnFile, SlnPropertySet nestedProjects) + { + var solutionFolderPaths = new Dictionary(); + + var solutionFolderProjects = slnFile.Projects.GetProjectsByType(ProjectTypeGuids.SolutionFolderGuid); + foreach (var slnProject in solutionFolderProjects) + { + var path = slnProject.FilePath; + var id = slnProject.Id; + while (nestedProjects.ContainsKey(id)) + { + id = nestedProjects[id]; + var parentSlnProject = solutionFolderProjects.Where(p => p.Id == id).Single(); + path = Path.Combine(parentSlnProject.FilePath, path); + } + + solutionFolderPaths[path] = slnProject.Id; + } + + return solutionFolderPaths; + } } } diff --git a/src/dotnet/commands/dotnet-sln/remove/Program.cs b/src/dotnet/commands/dotnet-sln/remove/Program.cs index deb9ea72a..18f3866e5 100644 --- a/src/dotnet/commands/dotnet-sln/remove/Program.cs +++ b/src/dotnet/commands/dotnet-sln/remove/Program.cs @@ -126,10 +126,8 @@ namespace Microsoft.DotNet.Tools.Sln.Remove private void RemoveEmptySolutionFolders(SlnFile slnFile) { - var referencedSolutionFolders = slnFile.Projects.GetReferencedSolutionFolders(); - var solutionFolderProjects = slnFile.Projects - .Where(p => p.TypeGuid == ProjectTypeGuids.SolutionFolderGuid) + .GetProjectsByType(ProjectTypeGuids.SolutionFolderGuid) .ToList(); if (solutionFolderProjects.Any()) @@ -138,9 +136,13 @@ namespace Microsoft.DotNet.Tools.Sln.Remove "NestedProjects", SlnSectionType.PreProcess); + var solutionFoldersInUse = GetSolutionFoldersThatContainProjectsInItsHierarchy( + slnFile, + nestedProjectsSection.Properties); + foreach (var solutionFolderProject in solutionFolderProjects) { - if (!referencedSolutionFolders.Contains(solutionFolderProject.Name)) + if (!solutionFoldersInUse.Contains(solutionFolderProject.Id)) { slnFile.Projects.Remove(solutionFolderProject); nestedProjectsSection.Properties.Remove(solutionFolderProject.Id); @@ -153,5 +155,27 @@ namespace Microsoft.DotNet.Tools.Sln.Remove } } } + + private HashSet GetSolutionFoldersThatContainProjectsInItsHierarchy( + SlnFile slnFile, + SlnPropertySet nestedProjects) + { + var solutionFoldersInUse = new HashSet(); + + var nonSolutionFolderProjects = slnFile.Projects.GetProjectsNotOfType( + ProjectTypeGuids.SolutionFolderGuid); + + foreach (var nonSolutionFolderProject in nonSolutionFolderProjects) + { + var id = nonSolutionFolderProject.Id; + while (nestedProjects.ContainsKey(id)) + { + id = nestedProjects[id]; + solutionFoldersInUse.Add(id); + } + } + + return solutionFoldersInUse; + } } } diff --git a/test/dotnet-sln-add.Tests/GivenDotnetSlnAdd.cs b/test/dotnet-sln-add.Tests/GivenDotnetSlnAdd.cs index 4a0d87381..c1ca138d5 100644 --- a/test/dotnet-sln-add.Tests/GivenDotnetSlnAdd.cs +++ b/test/dotnet-sln-add.Tests/GivenDotnetSlnAdd.cs @@ -35,8 +35,6 @@ VisualStudioVersion = 15.0.26006.2 MinimumVisualStudioVersion = 10.0.40219.1 Project(""{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"") = ""App"", ""App\App.csproj"", ""{7072A694-548F-4CAE-A58F-12D257D5F486}"" EndProject -Project(""{2150E333-8FDC-42A3-9474-1A3956D46DE8}"") = ""Lib"", ""Lib"", ""__LIB_FOLDER_GUID__"" -EndProject Project(""{13B669BE-BB05-4DDF-9536-439F39A36129}"") = ""Lib"", ""Lib\Lib.csproj"", ""__LIB_PROJECT_GUID__"" EndProject Global @@ -77,9 +75,6 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(NestedProjects) = preSolution - __LIB_PROJECT_GUID__ = __LIB_FOLDER_GUID__ - EndGlobalSection EndGlobal "; @@ -88,8 +83,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26006.2 MinimumVisualStudioVersion = 10.0.40219.1 -Project(""{2150E333-8FDC-42A3-9474-1A3956D46DE8}"") = ""Lib"", ""Lib"", ""__LIB_FOLDER_GUID__"" -EndProject Project(""{13B669BE-BB05-4DDF-9536-439F39A36129}"") = ""Lib"", ""Lib\Lib.csproj"", ""__LIB_PROJECT_GUID__"" EndProject Global @@ -115,9 +108,6 @@ Global __LIB_PROJECT_GUID__.Release|x86.ActiveCfg = Release|x86 __LIB_PROJECT_GUID__.Release|x86.Build.0 = Release|x86 EndGlobalSection - GlobalSection(NestedProjects) = preSolution - __LIB_PROJECT_GUID__ = __LIB_FOLDER_GUID__ - EndGlobalSection EndGlobal "; @@ -130,8 +120,6 @@ Project(""{9A19103F-16F7-4668-BE54-9A1E7A4F7556}"") = ""App"", ""App.csproj"", " EndProject Project(""{2150E333-8FDC-42A3-9474-1A3956D46DE8}"") = ""src"", ""src"", ""__SRC_FOLDER_GUID__"" EndProject -Project(""{2150E333-8FDC-42A3-9474-1A3956D46DE8}"") = ""Lib"", ""Lib"", ""__LIB_FOLDER_GUID__"" -EndProject Project(""{13B669BE-BB05-4DDF-9536-439F39A36129}"") = ""Lib"", ""src\Lib\Lib.csproj"", ""__LIB_PROJECT_GUID__"" EndProject Global @@ -173,8 +161,7 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - __LIB_FOLDER_GUID__ = __SRC_FOLDER_GUID__ - __LIB_PROJECT_GUID__ = __LIB_FOLDER_GUID__ + __LIB_PROJECT_GUID__ = __SRC_FOLDER_GUID__ EndGlobalSection EndGlobal "; @@ -345,6 +332,70 @@ EndGlobal .Should().BeVisuallyEquivalentTo(expectedSlnContents); } + [Fact] + public void WhenProjectDirectoryIsAddedSolutionFoldersAreNotCreated() + { + var projectDirectory = TestAssets + .Get("TestAppWithSlnAndCsprojFiles") + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var projectToAdd = Path.Combine("Lib", "Lib.csproj"); + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"sln App.sln add {projectToAdd}"); + cmd.Should().Pass(); + + var slnFile = SlnFile.Read(Path.Combine(projectDirectory, "App.sln")); + var solutionFolderProjects = slnFile.Projects.Where( + p => p.TypeGuid == ProjectTypeGuids.SolutionFolderGuid); + solutionFolderProjects.Count().Should().Be(0); + slnFile.Sections.GetSection("NestedProjects").Should().BeNull(); + } + + [Theory] + [InlineData(".")] + [InlineData("")] + public void WhenSolutionFolderExistsItDoesNotGetAdded(string firstComponent) + { + var projectDirectory = TestAssets + .Get("TestAppWithSlnAndSolutionFolders") + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var projectToAdd = Path.Combine($"{firstComponent}", "src", "src", "Lib", "Lib.csproj"); + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"sln App.sln add {projectToAdd}"); + cmd.Should().Pass(); + + var slnFile = SlnFile.Read(Path.Combine(projectDirectory, "App.sln")); + slnFile.Projects.Count().Should().Be(4); + + var solutionFolderProjects = slnFile.Projects.Where( + p => p.TypeGuid == ProjectTypeGuids.SolutionFolderGuid); + solutionFolderProjects.Count().Should().Be(2); + + var solutionFolders = slnFile.Sections.GetSection("NestedProjects").Properties; + solutionFolders.Count.Should().Be(3); + + solutionFolders["{DDF3765C-59FB-4AA6-BE83-779ED13AA64A}"] + .Should().Be("{72BFCA87-B033-4721-8712-4D12166B4A39}"); + + var newlyAddedSrcFolder = solutionFolderProjects.Where( + p => p.Id != "{72BFCA87-B033-4721-8712-4D12166B4A39}").Single(); + solutionFolders[newlyAddedSrcFolder.Id] + .Should().Be("{72BFCA87-B033-4721-8712-4D12166B4A39}"); + + var libProject = slnFile.Projects.Where(p => p.Name == "Lib").Single(); + solutionFolders[libProject.Id] + .Should().Be(newlyAddedSrcFolder.Id); + } + [Theory] [InlineData("TestAppWithSlnAndCsprojFiles", ExpectedSlnFileAfterAddingLibProj, "")] [InlineData("TestAppWithSlnAndCsprojProjectGuidFiles", ExpectedSlnFileAfterAddingLibProj, "{84A45D44-B677-492D-A6DA-B3A71135AB8E}")] @@ -574,12 +625,6 @@ EndGlobal } var slnContents = slnTemplate.Replace("__LIB_PROJECT_GUID__", expectedLibProjectGuid); - var matchingLibFolder = slnFile.Projects - .Where((p) => p.FilePath == "Lib") - .ToList(); - matchingLibFolder.Count.Should().Be(1); - slnContents = slnContents.Replace("__LIB_FOLDER_GUID__", matchingLibFolder[0].Id); - var matchingSrcFolder = slnFile.Projects .Where((p) => p.FilePath == "src") .ToList(); From 8ac7312fa37f9a74d544160612860846c9ef1b47 Mon Sep 17 00:00:00 2001 From: Mike Lorbetske Date: Fri, 20 Jan 2017 23:03:03 -0800 Subject: [PATCH 5/8] Take the latest WebSDK version to absorb a publish output directory change (#5409) --- build/Microsoft.DotNet.Cli.DependencyVersions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Microsoft.DotNet.Cli.DependencyVersions.props b/build/Microsoft.DotNet.Cli.DependencyVersions.props index 86351a0f6..bc2c3ca66 100644 --- a/build/Microsoft.DotNet.Cli.DependencyVersions.props +++ b/build/Microsoft.DotNet.Cli.DependencyVersions.props @@ -5,7 +5,7 @@ 2.0.0-rc3-61212-03 1.0.0-alpha-20170117-4 4.0.0-rc3 - 1.0.0-alpha-20170114-1-223 + 1.0.0-alpha-20170120-3-249 15.0.0-preview-20170106-08 1.0.0-beta1-20170108-83 From 04a7fca9fc5512e738cd9386e129f09a2235a55f Mon Sep 17 00:00:00 2001 From: Piotr Puszkiewicz Date: Sat, 21 Jan 2017 00:11:18 -0800 Subject: [PATCH 6/8] Fixing argument parsing in add package command (#5421) * Fixing argument parsing in add package command * Adding check to throw if extra args were passed * Removing string and adding test cases for dotnet add package command * Add new test to test.sln, and fix naming, and clean csproj --- .../dotnet-add-package/LocalizableStrings.cs | 4 +- .../dotnet-add/dotnet-add-package/Program.cs | 25 ++-- test/Microsoft.DotNet.Cli.Tests.sln | 14 +++ .../GivenDotnetPackageAdd.cs | 119 ++++++++++++++++++ test/dotnet-add-package.Tests/MSBuild.exe | 1 + .../MSBuild.exe.config | 1 + .../dotnet-add-package.Tests.csproj | 26 ++++ 7 files changed, 179 insertions(+), 11 deletions(-) create mode 100644 test/dotnet-add-package.Tests/GivenDotnetPackageAdd.cs create mode 100644 test/dotnet-add-package.Tests/MSBuild.exe create mode 100644 test/dotnet-add-package.Tests/MSBuild.exe.config create mode 100644 test/dotnet-add-package.Tests/dotnet-add-package.Tests.csproj diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-package/LocalizableStrings.cs b/src/dotnet/commands/dotnet-add/dotnet-add-package/LocalizableStrings.cs index 1290883a3..21f84fe76 100644 --- a/src/dotnet/commands/dotnet-add/dotnet-add-package/LocalizableStrings.cs +++ b/src/dotnet/commands/dotnet-add/dotnet-add-package/LocalizableStrings.cs @@ -9,7 +9,7 @@ namespace Microsoft.DotNet.Tools.Add.PackageReference public const string AppDescription = "Command to add package reference"; - public const string AppHelpText = "Package references to add"; + public const string CmdPackageDescription = "Package references to add"; public const string SpecifyExactlyOnePackageReference = "Please specify one package reference to add."; @@ -25,6 +25,8 @@ namespace Microsoft.DotNet.Tools.Add.PackageReference public const string CmdDGFileException = "Unable to Create Dependency graph file for project '{0}'. Cannot add package reference."; + public const string CmdPackage = "PACKAGE_NAME"; + public const string CmdVersion = "VERSION"; public const string CmdFramework = "FRAMEWORK"; diff --git a/src/dotnet/commands/dotnet-add/dotnet-add-package/Program.cs b/src/dotnet/commands/dotnet-add/dotnet-add-package/Program.cs index 1394638e8..4f7d4f594 100644 --- a/src/dotnet/commands/dotnet-add/dotnet-add-package/Program.cs +++ b/src/dotnet/commands/dotnet-add/dotnet-add-package/Program.cs @@ -1,12 +1,6 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text; using Microsoft.Build.Evaluation; using Microsoft.DotNet.Cli; using Microsoft.DotNet.Cli.CommandLine; @@ -15,6 +9,12 @@ using Microsoft.DotNet.Tools.Common; using Microsoft.DotNet.Tools.MSBuild; using Microsoft.DotNet.Tools.NuGet; using NuGet.Frameworks; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; namespace Microsoft.DotNet.Tools.Add.PackageReference { @@ -25,6 +25,7 @@ namespace Microsoft.DotNet.Tools.Add.PackageReference private CommandOption _noRestoreOption; private CommandOption _sourceOption; private CommandOption _packageDirectoryOption; + private CommandArgument _packageNameArgument; public static DotNetSubCommandBase Create() { @@ -33,12 +34,16 @@ namespace Microsoft.DotNet.Tools.Add.PackageReference Name = "package", FullName = LocalizableStrings.AppFullName, Description = LocalizableStrings.AppDescription, - HandleRemainingArguments = true, - ArgumentSeparatorHelpText = LocalizableStrings.AppHelpText, + HandleRemainingArguments = false }; command.HelpOption("-h|--help"); + command._packageNameArgument = command.Argument( + $"<{LocalizableStrings.CmdPackage}>", + LocalizableStrings.CmdPackageDescription, + multipleValues: false); + command._versionOption = command.Option( $"-v|--version <{LocalizableStrings.CmdVersion}>", LocalizableStrings.CmdVersionDescription, @@ -69,7 +74,7 @@ namespace Microsoft.DotNet.Tools.Add.PackageReference public override int Run(string fileOrDirectory) { - if (RemainingArguments.Count != 1) + if (_packageNameArgument.Values.Count != 1 || string.IsNullOrWhiteSpace(_packageNameArgument.Value) || RemainingArguments.Count > 0) { throw new GracefulException(LocalizableStrings.SpecifyExactlyOnePackageReference); } @@ -94,7 +99,7 @@ namespace Microsoft.DotNet.Tools.Add.PackageReference GetProjectDependencyGraph(projectFilePath, tempDgFilePath); } - var result = NuGetCommand.Run(TransformArgs(RemainingArguments.First(), tempDgFilePath, projectFilePath)); + var result = NuGetCommand.Run(TransformArgs(_packageNameArgument.Value, tempDgFilePath, projectFilePath)); DisposeTemporaryFile(tempDgFilePath); return result; diff --git a/test/Microsoft.DotNet.Cli.Tests.sln b/test/Microsoft.DotNet.Cli.Tests.sln index 8d1578038..95ea83fcb 100644 --- a/test/Microsoft.DotNet.Cli.Tests.sln +++ b/test/Microsoft.DotNet.Cli.Tests.sln @@ -76,6 +76,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dotnet-sln-remove.Tests", " EndProject Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "dotnet-sln-remove.Tests", "dotnet-sln-remove.Tests\dotnet-sln-remove.Tests.csproj", "{92BA9F90-E25B-4A1C-9598-2295D3DFC12F}" EndProject +Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "dotnet-add-package.Tests", "dotnet-add-package.Tests\dotnet-add-package.Tests.csproj", "{3501AB72-3E05-45EE-9000-9515F5A139AC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -246,6 +248,18 @@ Global {92BA9F90-E25B-4A1C-9598-2295D3DFC12F}.Release|x64.Build.0 = Release|x64 {92BA9F90-E25B-4A1C-9598-2295D3DFC12F}.Release|x86.ActiveCfg = Release|x86 {92BA9F90-E25B-4A1C-9598-2295D3DFC12F}.Release|x86.Build.0 = Release|x86 + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Debug|x64.ActiveCfg = Debug|x64 + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Debug|x64.Build.0 = Debug|x64 + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Debug|x86.ActiveCfg = Debug|x86 + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Debug|x86.Build.0 = Debug|x86 + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Release|Any CPU.Build.0 = Release|Any CPU + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Release|x64.ActiveCfg = Release|x64 + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Release|x64.Build.0 = Release|x64 + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Release|x86.ActiveCfg = Release|x86 + {3501AB72-3E05-45EE-9000-9515F5A139AC}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/test/dotnet-add-package.Tests/GivenDotnetPackageAdd.cs b/test/dotnet-add-package.Tests/GivenDotnetPackageAdd.cs new file mode 100644 index 000000000..def951aec --- /dev/null +++ b/test/dotnet-add-package.Tests/GivenDotnetPackageAdd.cs @@ -0,0 +1,119 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using FluentAssertions; +using Microsoft.Build.Construction; +using Microsoft.DotNet.Cli.Sln.Internal; +using Microsoft.DotNet.Tools.Test.Utilities; +using System; +using System.IO; +using System.Linq; +using Xunit; + +namespace Microsoft.DotNet.Cli.Package.Add.Tests +{ + public class GivenDotnetPackageAdd : TestBase + { + + [Fact] + public void WhenValidPackageIsPassedBeforeVersionItGetsAdded() + { + var testAsset = "TestAppSimple"; + var projectDirectory = TestAssets + .Get(testAsset) + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var packageName = "Newtonsoft.Json"; + var packageVersion = "9.0.1"; + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"add package {packageName} --version {packageVersion}"); + cmd.Should().Pass(); + cmd.StdOut.Should().Contain($"PackageReference for package '{packageName}' version '{packageVersion}' " + + $"added to file '{projectDirectory + Path.DirectorySeparatorChar + testAsset}.csproj'."); + cmd.StdErr.Should().BeEmpty(); + } + + [Fact] + public void WhenValidPackageIsPassedAfterVersionItGetsAdded() + { + var testAsset = "TestAppSimple"; + var projectDirectory = TestAssets + .Get(testAsset) + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var packageName = "Newtonsoft.Json"; + var packageVersion = "9.0.1"; + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"add package --version {packageVersion} {packageName}"); + cmd.Should().Pass(); + cmd.StdOut.Should().Contain($"PackageReference for package '{packageName}' version '{packageVersion}' " + + $"added to file '{projectDirectory + Path.DirectorySeparatorChar + testAsset}.csproj'."); + cmd.StdErr.Should().BeEmpty(); + } + + [Fact] + public void WhenValidPackageIsPassedWithFrameworkItGetsAdded() + { + var testAsset = "TestAppSimple"; + var projectDirectory = TestAssets + .Get(testAsset) + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var packageName = "Newtonsoft.Json"; + var packageVersion = "9.0.1"; + var framework = "netcoreapp1.0"; + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"add package {packageName} --version {packageVersion} --framework {framework}"); + cmd.Should().Pass(); + cmd.StdOut.Should().Contain($"PackageReference for package '{packageName}' version '{packageVersion}' " + + $"added to file '{projectDirectory + Path.DirectorySeparatorChar + testAsset}.csproj'."); + cmd.StdErr.Should().BeEmpty(); + } + + [Fact] + public void WhenMultiplePackagesArePassedCommandFails() + { + var projectDirectory = TestAssets + .Get("TestAppSimple") + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"add package package1 package2 package3"); + cmd.Should().Fail(); + cmd.StdErr.Should().Contain("Please specify one package reference to add."); + } + + [Fact] + public void WhenNoPackageisPassedCommandFails() + { + var projectDirectory = TestAssets + .Get("TestAppSimple") + .CreateInstance() + .WithSourceFiles() + .Root + .FullName; + + var cmd = new DotnetCommand() + .WithWorkingDirectory(projectDirectory) + .ExecuteWithCapturedOutput($"add package"); + cmd.Should().Fail(); + cmd.StdErr.Should().Contain("Please specify one package reference to add."); + } + } +} diff --git a/test/dotnet-add-package.Tests/MSBuild.exe b/test/dotnet-add-package.Tests/MSBuild.exe new file mode 100644 index 000000000..9bda258ef --- /dev/null +++ b/test/dotnet-add-package.Tests/MSBuild.exe @@ -0,0 +1 @@ +https://github.com/Microsoft/msbuild/issues/927 diff --git a/test/dotnet-add-package.Tests/MSBuild.exe.config b/test/dotnet-add-package.Tests/MSBuild.exe.config new file mode 100644 index 000000000..9bda258ef --- /dev/null +++ b/test/dotnet-add-package.Tests/MSBuild.exe.config @@ -0,0 +1 @@ +https://github.com/Microsoft/msbuild/issues/927 diff --git a/test/dotnet-add-package.Tests/dotnet-add-package.Tests.csproj b/test/dotnet-add-package.Tests/dotnet-add-package.Tests.csproj new file mode 100644 index 000000000..6a052db05 --- /dev/null +++ b/test/dotnet-add-package.Tests/dotnet-add-package.Tests.csproj @@ -0,0 +1,26 @@ + + + + + netcoreapp1.0 + true + dotnet-add-package.Tests + $(PackageTargetFallback);dotnet5.4;portable-net451+win8 + + + + + + + + + + + + + + + + + + From 0a62481cc074ec123c09214c84a66367e3d6057f Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Sat, 21 Jan 2017 01:58:28 -0800 Subject: [PATCH 7/8] Create backup folder in the directory where 'dotnet migrate' is executed (#5306) * Create backup folder in the directory where 'dotnet migrate' is executed With this change, 'dotnet migrate' will create the backup folder in the workspace directory rather than the parent of the workspace directory. This solves two problems: 1. It makes it easier for the user where the backup is -- it's in the directory they targeted with 'dotnet migrate'. 2. It solves a problem of file oollisions with global.json files when migrating multiple projects. Consider the following directory structure: root | project1 | global.json | src | project1 project2 | global.json | src | project2 Prior to this change, running 'dotnet migrate' project1 and then running it again in project2 would have caused an exception to be thrown because the migration would try to produce a backup folder like so: root | backup | | | global.json | | | project1 | | | project2 | | project1 | src | project1 project2 | src | project2 Now, we produce the following structure, which has no collisions: root | project1 | backup | | | global.json | | | project1 | src | project1 | project2 | backup | | | global.json | | | project2 | src | project2 In addition, to help avoid further collisions, a number is appened to the backup folder's name if it already exists. So, if the user runs dotnet migrate again for some reason, they'll see backup_1, backup_2, etc. * Fix test helper * Fix foolish bug causing infinite loop * Fix up a couple more tests * Rework MigrationBackupPlan to process all projects at once * Fix up tests * Still fixing tests * Compute common root folder of projects to determine where backup folder should be placed * Fix typo * Fix test to not look in backup folder now that it's in a better location --- .../MigrationBackupPlan.cs | 201 ++++++++++++++---- .../TestDirectory.cs | 2 +- .../commands/dotnet-migrate/MigrateCommand.cs | 15 +- .../MigrationBackupPlanTests.cs | 141 +++++++----- .../GivenThatAnAppWasMigrated.cs | 8 +- .../GivenThatIWantToMigrateTestApps.cs | 4 + 6 files changed, 267 insertions(+), 104 deletions(-) diff --git a/src/Microsoft.DotNet.ProjectJsonMigration/MigrationBackupPlan.cs b/src/Microsoft.DotNet.ProjectJsonMigration/MigrationBackupPlan.cs index 43325ea77..9224dfaa2 100644 --- a/src/Microsoft.DotNet.ProjectJsonMigration/MigrationBackupPlan.cs +++ b/src/Microsoft.DotNet.ProjectJsonMigration/MigrationBackupPlan.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using Microsoft.DotNet.Internal.ProjectModel.Utilities; namespace Microsoft.DotNet.ProjectJsonMigration @@ -14,92 +15,206 @@ namespace Microsoft.DotNet.ProjectJsonMigration private const string TempCsprojExtention = ".migration_in_place_backup"; private readonly FileInfo globalJson; + private readonly Dictionary> mapOfProjectBackupDirectoryToFilesToMove; + + public DirectoryInfo RootBackupDirectory { get; } + public DirectoryInfo[] ProjectBackupDirectories { get; } + + public IEnumerable FilesToMove(DirectoryInfo projectBackupDirectory) + => mapOfProjectBackupDirectoryToFilesToMove[projectBackupDirectory]; public MigrationBackupPlan( - DirectoryInfo projectDirectory, + IEnumerable projectDirectories, DirectoryInfo workspaceDirectory, Func> getFiles = null) { - if (projectDirectory == null) + if (projectDirectories == null) { - throw new ArgumentNullException(nameof(projectDirectory)); + throw new ArgumentNullException(nameof(projectDirectories)); } + + if (!projectDirectories.Any()) + { + throw new ArgumentException("No project directories provided.", nameof(projectDirectories)); + } + if (workspaceDirectory == null) { throw new ArgumentNullException(nameof(workspaceDirectory)); } - globalJson = new FileInfo(Path.Combine( - workspaceDirectory.FullName, - "global.json")); + MigrationTrace.Instance.WriteLine("Computing migration backup plan..."); - projectDirectory = new DirectoryInfo(projectDirectory.FullName.EnsureTrailingSlash()); + projectDirectories = projectDirectories.Select(pd => new DirectoryInfo(pd.FullName.EnsureTrailingSlash())); workspaceDirectory = new DirectoryInfo(workspaceDirectory.FullName.EnsureTrailingSlash()); + MigrationTrace.Instance.WriteLine($" Workspace: {workspaceDirectory.FullName}"); + foreach (var projectDirectory in projectDirectories) + { + MigrationTrace.Instance.WriteLine($" Project: {projectDirectory.FullName}"); + } + + var rootDirectory = FindCommonRootPath(projectDirectories.ToArray()) ?? workspaceDirectory; + rootDirectory = new DirectoryInfo(rootDirectory.FullName.EnsureTrailingSlash()); + + MigrationTrace.Instance.WriteLine($" Root: {rootDirectory.FullName}"); + + globalJson = new FileInfo( + Path.Combine( + workspaceDirectory.FullName, + "global.json")); + RootBackupDirectory = new DirectoryInfo( - Path.Combine( - workspaceDirectory.Parent.FullName, - "backup") + GetUniqueDirectoryPath( + Path.Combine( + rootDirectory.FullName, + "backup")) .EnsureTrailingSlash()); - ProjectBackupDirectory = new DirectoryInfo( - Path.Combine( - RootBackupDirectory.FullName, - projectDirectory.Name) - .EnsureTrailingSlash()); + MigrationTrace.Instance.WriteLine($" Root Backup: {RootBackupDirectory.FullName}"); - var relativeDirectory = PathUtility.GetRelativePath( - workspaceDirectory.FullName, - projectDirectory.FullName); + var projectBackupDirectories = new List(); + mapOfProjectBackupDirectoryToFilesToMove = new Dictionary>(); + getFiles = getFiles ?? (dir => dir.EnumerateFiles()); - getFiles = getFiles ?? - (dir => dir.EnumerateFiles()); + foreach (var projectDirectory in projectDirectories) + { + var projectBackupDirectory = ComputeProjectBackupDirectoryPath(rootDirectory, projectDirectory, RootBackupDirectory); + var filesToMove = getFiles(projectDirectory).Where(NeedsBackup); - FilesToMove = getFiles(projectDirectory) - .Where(f => f.Name == "project.json" - || f.Extension == ".xproj" - || f.FullName.EndsWith(".xproj.user") - || f.FullName.EndsWith(".lock.json") - || f.FullName.EndsWith(TempCsprojExtention)); + projectBackupDirectories.Add(projectBackupDirectory); + mapOfProjectBackupDirectoryToFilesToMove.Add(projectBackupDirectory, filesToMove); + } + + ProjectBackupDirectories = projectBackupDirectories.ToArray(); } - public DirectoryInfo ProjectBackupDirectory { get; } - - public DirectoryInfo RootBackupDirectory { get; } - - public IEnumerable FilesToMove { get; } - public void PerformBackup() { if (globalJson.Exists) { PathUtility.EnsureDirectoryExists(RootBackupDirectory.FullName); - globalJson.MoveTo(Path.Combine( - ProjectBackupDirectory.Parent.FullName, - globalJson.Name)); + globalJson.MoveTo( + Path.Combine( + RootBackupDirectory.FullName, + globalJson.Name)); } - PathUtility.EnsureDirectoryExists(ProjectBackupDirectory.FullName); - - foreach (var file in FilesToMove) + foreach (var kvp in mapOfProjectBackupDirectoryToFilesToMove) { - var fileName = file.Name.EndsWith(TempCsprojExtention) - ? Path.GetFileNameWithoutExtension(file.Name) - : file.Name; + var projectBackupDirectory = kvp.Key; + var filesToMove = kvp.Value; - file.MoveTo( - Path.Combine(ProjectBackupDirectory.FullName, fileName)); + PathUtility.EnsureDirectoryExists(projectBackupDirectory.FullName); + + foreach (var file in filesToMove) + { + var fileName = file.Name.EndsWith(TempCsprojExtention) + ? Path.GetFileNameWithoutExtension(file.Name) + : file.Name; + + file.MoveTo( + Path.Combine( + projectBackupDirectory.FullName, + fileName)); + } } } + private static DirectoryInfo ComputeProjectBackupDirectoryPath( + DirectoryInfo rootDirectory, DirectoryInfo projectDirectory, DirectoryInfo rootBackupDirectory) + { + if (PathUtility.IsChildOfDirectory(rootDirectory.FullName, projectDirectory.FullName)) + { + var relativePath = PathUtility.GetRelativePath( + rootDirectory.FullName, + projectDirectory.FullName); + + return new DirectoryInfo( + Path.Combine( + rootBackupDirectory.FullName, + relativePath) + .EnsureTrailingSlash()); + } + + // Ensure that we use a unique name to avoid collisions as a fallback. + return new DirectoryInfo( + GetUniqueDirectoryPath( + Path.Combine( + rootBackupDirectory.FullName, + projectDirectory.Name) + .EnsureTrailingSlash())); + } + + private static bool NeedsBackup(FileInfo file) + => file.Name == "project.json" + || file.Extension == ".xproj" + || file.FullName.EndsWith(".xproj.user") + || file.FullName.EndsWith(".lock.json") + || file.FullName.EndsWith(TempCsprojExtention); + + private static string GetUniqueDirectoryPath(string directoryPath) + { + var candidatePath = directoryPath; + + var suffix = 1; + while (Directory.Exists(candidatePath)) + { + candidatePath = $"{directoryPath}_{suffix++}"; + } + + return candidatePath; + } + + private static DirectoryInfo FindCommonRootPath(DirectoryInfo[] paths) + { + var pathSplits = new string[paths.Length][]; + var shortestLength = int.MaxValue; + for (int i = 0; i < paths.Length; i++) + { + pathSplits[i] = paths[i].FullName.Split(new[] { Path.DirectorySeparatorChar }); + shortestLength = Math.Min(shortestLength, pathSplits[i].Length); + } + + var builder = new StringBuilder(); + var splitIndex = 0; + while (splitIndex < shortestLength) + { + var split = pathSplits[0][splitIndex]; + + var done = false; + for (int i = 1; i < pathSplits.Length; i++) + { + if (pathSplits[i][splitIndex] != split) + { + done = true; + break; + } + } + + if (done) + { + break; + } + + builder.Append(split); + builder.Append(Path.DirectorySeparatorChar); + splitIndex++; + } + + return new DirectoryInfo(builder.ToString().EnsureTrailingSlash()); + } + public static void RenameCsprojFromMigrationOutputNameToTempName(string outputProject) { var backupFileName = $"{outputProject}{TempCsprojExtention}"; + if (File.Exists(backupFileName)) { File.Delete(backupFileName); } + File.Move(outputProject, backupFileName); } } diff --git a/src/Microsoft.DotNet.TestFramework/TestDirectory.cs b/src/Microsoft.DotNet.TestFramework/TestDirectory.cs index 9705b9569..78c577f1d 100644 --- a/src/Microsoft.DotNet.TestFramework/TestDirectory.cs +++ b/src/Microsoft.DotNet.TestFramework/TestDirectory.cs @@ -30,7 +30,7 @@ namespace Microsoft.DotNet.TestFramework var testDirectory = new DirectoryInfo(path); var migrationBackupDirectory = new DirectoryInfo( - System.IO.Path.Combine(testDirectory.Parent.FullName, "backup")); + System.IO.Path.Combine(testDirectory.FullName, "backup")); if (testDirectory.Exists) { diff --git a/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs b/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs index d74487514..bc7e6b444 100644 --- a/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs +++ b/src/dotnet/commands/dotnet-migrate/MigrateCommand.cs @@ -202,14 +202,19 @@ namespace Microsoft.DotNet.Tools.Migrate private void BackupProjects(MigrationReport migrationReport) { + var projectDirectories = new List(); foreach (var report in migrationReport.ProjectMigrationReports) { - var backupPlan = new MigrationBackupPlan( - new DirectoryInfo(report.ProjectDirectory), - _workspaceDirectory); - - backupPlan.PerformBackup(); + projectDirectories.Add(new DirectoryInfo(report.ProjectDirectory)); } + + var backupPlan = new MigrationBackupPlan( + projectDirectories, + _workspaceDirectory); + + backupPlan.PerformBackup(); + + Reporter.Output.WriteLine($"Files backed up to {backupPlan.RootBackupDirectory.FullName}"); } private void WriteReport(MigrationReport migrationReport) diff --git a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/MigrationBackupPlanTests.cs b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/MigrationBackupPlanTests.cs index b54f265b0..227cef562 100644 --- a/test/Microsoft.DotNet.ProjectJsonMigration.Tests/MigrationBackupPlanTests.cs +++ b/test/Microsoft.DotNet.ProjectJsonMigration.Tests/MigrationBackupPlanTests.cs @@ -5,6 +5,7 @@ using FluentAssertions; using Microsoft.DotNet.Internal.ProjectModel.Utilities; using Microsoft.DotNet.ProjectJsonMigration; using System; +using System.Collections.Generic; using System.IO; using System.Linq; using Xunit; @@ -14,81 +15,123 @@ namespace Microsoft.DotNet.ProjectJsonMigration.Tests public partial class MigrationBackupPlanTests { [Fact] - public void TheRootBackupDirectoryIsASiblingOfTheRootProject() + public void TheBackupDirectoryIsASubfolderOfTheMigratedProject() { - var dir = new DirectoryInfo(Path.Combine("src", "some-proj")); + var workspaceDirectory = Path.Combine("src", "root"); + var projectDirectory = Path.Combine("src", "project1"); - System.Console.WriteLine(dir.FullName); - - WhenMigrating( - projectDirectory: dir.FullName, - workspaceDirectory: Path.Combine("src", "RootProject")) - .RootBackupDirectory - .FullName - .Should() - .Be(new DirectoryInfo(Path.Combine("src", "backup")).FullName.EnsureTrailingSlash()); + WhenMigrating(projectDirectory, workspaceDirectory) + .RootBackupDirectory + .FullName + .Should() + .Be(new DirectoryInfo(Path.Combine("src", "project1", "backup")).FullName.EnsureTrailingSlash()); } [Fact] - public void TheRootProjectsBackupDirectoryIsASubfolderOfTheRootBackupDirectory() + public void TheBackupDirectoryIsASubfolderOfTheMigratedProjectWhenInitiatedFromProjectFolder() { - WhenMigrating( - projectDirectory: Path.Combine("src", "RootProject"), - workspaceDirectory: Path.Combine("src", "RootProject")) - .ProjectBackupDirectory - .FullName - .Should() - .Be(new DirectoryInfo(Path.Combine("src", "backup", "RootProject")).FullName.EnsureTrailingSlash()); + var workspaceDirectory = Path.Combine("src", "root"); + var projectDirectory = Path.Combine("src", "root"); + + WhenMigrating(projectDirectory, workspaceDirectory) + .ProjectBackupDirectories.Single() + .FullName + .Should() + .Be(new DirectoryInfo(Path.Combine("src", "root", "backup")).FullName.EnsureTrailingSlash()); } [Fact] - public void ADependentProjectsMigrationBackupDirectoryIsASubfolderOfTheRootBackupDirectory() + public void TheBackupDirectoryIsInTheCommonRootOfTwoProjectFoldersWhenInitiatedFromProjectFolder() { - WhenMigrating( - projectDirectory: Path.Combine("src", "Dependency"), - workspaceDirectory: Path.Combine("src", "RootProject")) - .ProjectBackupDirectory - .FullName - .Should() - .Be(new DirectoryInfo(Path.Combine("src", "backup", "Dependency")).FullName.EnsureTrailingSlash()); + var projectDirectories = new [] + { + Path.Combine("root", "project1"), + Path.Combine("root", "project2") + }; + + var workspaceDirectory = Path.Combine("root", "project1"); + + WhenMigrating(projectDirectories, workspaceDirectory) + .RootBackupDirectory + .FullName + .Should() + .Be(new DirectoryInfo(Path.Combine("root", "backup")).FullName.EnsureTrailingSlash()); } [Fact] - public void FilesToBackUpAreIdentifiedInTheTheRootProjectDirectory() + public void TheBackupDirectoryIsInTheCommonRootOfTwoProjectFoldersWhenInitiatedFromCommonRoot() { - var root = new DirectoryInfo(Path.Combine("src", "RootProject")); + var projectDirectories = new [] + { + Path.Combine("root", "project1"), + Path.Combine("root", "project2") + }; - WhenMigrating( - projectDirectory: root.FullName, - workspaceDirectory: root.FullName) - .FilesToMove - .Should() - .Contain(_ => _.FullName == Path.Combine(root.FullName, "project.json")); + var workspaceDirectory = Path.Combine("root"); + WhenMigrating(projectDirectories, workspaceDirectory) + .RootBackupDirectory + .FullName + .Should() + .Be(new DirectoryInfo(Path.Combine("root", "backup")).FullName.EnsureTrailingSlash()); } [Fact] - public void FilesToBackUpAreIdentifiedInTheTheDependencyProjectDirectory() + public void TheBackupDirectoryIsInTheCommonRootOfTwoProjectFoldersAtDifferentLevelsWhenInitiatedFromProjectFolder() { - var root = new DirectoryInfo(Path.Combine("src", "RootProject")); - var dependency = new DirectoryInfo(Path.Combine("src", "RootProject")); + var projectDirectories = new [] + { + Path.Combine("root", "tests", "inner", "project1"), + Path.Combine("root", "src", "project2") + }; - WhenMigrating( - projectDirectory: dependency.FullName, - workspaceDirectory: root.FullName) - .FilesToMove - .Should() - .Contain(_ => _.FullName == Path.Combine(dependency.FullName, "project.json")); + var workspaceDirectory = Path.Combine("root", "tests", "inner"); + WhenMigrating(projectDirectories, workspaceDirectory) + .RootBackupDirectory + .FullName + .Should() + .Be(new DirectoryInfo(Path.Combine("root", "backup")).FullName.EnsureTrailingSlash()); } - private MigrationBackupPlan WhenMigrating( - string projectDirectory, - string workspaceDirectory) => + [Fact] + public void FilesToBackUpAreIdentifiedInTheRootProjectDirectory() + { + var workspaceDirectory = Path.Combine("src", "root"); + var projectDirectory = Path.Combine("src", "root"); + + var whenMigrating = WhenMigrating(projectDirectory, workspaceDirectory); + + whenMigrating + .FilesToMove(whenMigrating.ProjectBackupDirectories.Single()) + .Should() + .Contain(_ => _.FullName == Path.Combine(new DirectoryInfo(workspaceDirectory).FullName, "project.json")); + } + + [Fact] + public void FilesToBackUpAreIdentifiedInTheDependencyProjectDirectory() + { + var workspaceDirectory = Path.Combine("src", "root"); + var projectDirectory = Path.Combine("src", "root"); + + var whenMigrating = WhenMigrating(projectDirectory, workspaceDirectory); + + whenMigrating + .FilesToMove(whenMigrating.ProjectBackupDirectories.Single()) + .Should() + .Contain(_ => _.FullName == Path.Combine(new DirectoryInfo(projectDirectory).FullName, "project.json")); + } + + private MigrationBackupPlan WhenMigrating(string projectDirectory, string workspaceDirectory) => new MigrationBackupPlan( - new DirectoryInfo(projectDirectory), + new [] { new DirectoryInfo(projectDirectory) }, new DirectoryInfo(workspaceDirectory), - dir => new[] { new FileInfo(Path.Combine(dir.FullName, "project.json")) }); + dir => new [] { new FileInfo(Path.Combine(dir.FullName, "project.json")) }); + private MigrationBackupPlan WhenMigrating(string[] projectDirectories, string workspaceDirectory) => + new MigrationBackupPlan( + projectDirectories.Select(p => new DirectoryInfo(p)), + new DirectoryInfo(workspaceDirectory), + dir => new [] { new FileInfo(Path.Combine(dir.FullName, "project.json")) }); } } diff --git a/test/dotnet-migrate.Tests/GivenThatAnAppWasMigrated.cs b/test/dotnet-migrate.Tests/GivenThatAnAppWasMigrated.cs index bab4f3358..c9f5ad342 100644 --- a/test/dotnet-migrate.Tests/GivenThatAnAppWasMigrated.cs +++ b/test/dotnet-migrate.Tests/GivenThatAnAppWasMigrated.cs @@ -19,9 +19,7 @@ namespace Microsoft.DotNet.Migration.Tests .CreateTestInstance(testProjectName) .Path; - var testRootParent = new DirectoryInfo(testRoot).Parent.FullName; - - var backupRoot = Path.Combine(testRootParent, "backup"); + var backupRoot = Path.Combine(testRoot, "backup"); var migratableArtifacts = GetProjectJsonArtifacts(testRoot); @@ -47,9 +45,7 @@ namespace Microsoft.DotNet.Migration.Tests .CreateTestInstance(testProjectName) .Path; - var testRootParent = new DirectoryInfo(testRoot).Parent.FullName; - - var backupRoot = Path.Combine(testRootParent, "backup", testProjectName); + var backupRoot = Path.Combine(testRoot, "backup"); var migratableArtifacts = GetProjectJsonArtifacts(testRoot); diff --git a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs index 1b35012cf..a80e6fd5b 100644 --- a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs +++ b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs @@ -3,6 +3,7 @@ using Microsoft.Build.Construction; using Microsoft.DotNet.TestFramework; +using Microsoft.DotNet.Tools.Common; using Microsoft.DotNet.Tools.Test.Utilities; using System; using System.Collections.Generic; @@ -573,7 +574,10 @@ namespace Microsoft.DotNet.Migration.Tests private void VerifyMigration(IEnumerable expectedProjects, string rootDir) { + var backupDir = Path.Combine(rootDir, "backup"); + var migratedProjects = Directory.EnumerateFiles(rootDir, "*.csproj", SearchOption.AllDirectories) + .Where(s => !PathUtility.IsChildOfDirectory(backupDir, s)) .Where(s => Directory.EnumerateFiles(Path.GetDirectoryName(s), "*.csproj").Count() == 1) .Where(s => Path.GetFileName(Path.GetDirectoryName(s)).Contains("Project")) .Select(s => Path.GetFileName(Path.GetDirectoryName(s))); From 1dfee9ead8fcc63b68baba801a88fd2f9b7d251b Mon Sep 17 00:00:00 2001 From: Piotr Puszkiewicz Date: Sun, 22 Jan 2017 14:40:00 -0800 Subject: [PATCH 8/8] [WIP] Reduce test target complexity [and running time] (#5403) * Reduce test target complexity [and running time] * WiP * Enable building tests via solution Remove deprecated tests Make Microsoft.DotNet.Tools.Tests.Utilities portable-only Remove MSI tests from the solution as they are the only tests that currently require dekstop. * Enable building of tests * Move migration tests to TA to allow them to self-restore * Reduce project nesting and test directory name --- .../ProjectsWithGlobalJson/global.json | 4 + .../src with spaces/ProjectJ/.noautobuild | 0 .../src with spaces/ProjectJ/Program.cs | 19 + .../src with spaces/ProjectJ/project.json | 20 + .../src/ProjectH/.noautobuild | 0 .../src/ProjectH/Program.cs | 19 + .../src/ProjectH/project.json | 20 + .../src/ProjectI/.noautobuild | 0 .../src/ProjectI/Helper.cs | 15 + .../src/ProjectI/project.json | 18 + build/Microsoft.DotNet.Cli.Test.targets | 123 +---- build/test/TestProjects.targets | 67 +-- .../TestAssetInfo.cs | 2 +- .../Microsoft.DotNet.Cli.Msi.Tests.csproj | 6 +- test/Kestrel.Tests/DotnetBuildTest.cs | 48 -- test/Kestrel.Tests/DotnetRunTest.cs | 65 --- test/Kestrel.Tests/DotnetTest.cs | 141 ----- test/Kestrel.Tests/Kestrel.Tests.csproj | 49 -- test/Microsoft.DotNet.Cli.Tests.sln | 18 - ...rosoft.DotNet.Tools.Tests.Utilities.csproj | 2 +- test/Performance/.gitignore | 4 - test/Performance/BuildPerformanceTest.cs | 353 ------------- test/Performance/HelloWorld.cs | 89 ---- test/Performance/Performance.csproj | 55 -- test/Performance/README.md | 54 -- test/Performance/run-perftests.py | 249 --------- .../binding-redirects.Tests.csproj | 51 +- .../GivenThatAnAppWasMigrated.cs | 72 +-- ...enThatIWantToMigrateAppsUsingGlobalJson.cs | 37 +- .../GivenThatIWantToMigrateSolutions.cs | 42 +- .../GivenThatIWantToMigrateTestApps.cs | 489 ++++++++++-------- .../1.0.0-rc4-004536/osx.10.11-x64/dotnet | Bin 0 -> 64 bytes 32 files changed, 520 insertions(+), 1611 deletions(-) create mode 100644 TestAssets/TestProjects/ProjectsWithGlobalJson/global.json create mode 100644 TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/.noautobuild create mode 100644 TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/Program.cs create mode 100644 TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/project.json create mode 100644 TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/.noautobuild create mode 100644 TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/Program.cs create mode 100644 TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/project.json create mode 100644 TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/.noautobuild create mode 100644 TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/Helper.cs create mode 100644 TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/project.json delete mode 100644 test/Kestrel.Tests/DotnetBuildTest.cs delete mode 100644 test/Kestrel.Tests/DotnetRunTest.cs delete mode 100644 test/Kestrel.Tests/DotnetTest.cs delete mode 100644 test/Kestrel.Tests/Kestrel.Tests.csproj delete mode 100644 test/Performance/.gitignore delete mode 100644 test/Performance/BuildPerformanceTest.cs delete mode 100644 test/Performance/HelloWorld.cs delete mode 100644 test/Performance/Performance.csproj delete mode 100644 test/Performance/README.md delete mode 100644 test/Performance/run-perftests.py create mode 100644 test/dotnet.Tests/¬/.dotnet/optimizationdata/1.0.0-rc4-004536/osx.10.11-x64/dotnet diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/global.json b/TestAssets/TestProjects/ProjectsWithGlobalJson/global.json new file mode 100644 index 000000000..2b2293b26 --- /dev/null +++ b/TestAssets/TestProjects/ProjectsWithGlobalJson/global.json @@ -0,0 +1,4 @@ + +{ + "projects": [ "src", "src with spaces", "src without projects" ] +} \ No newline at end of file diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/.noautobuild b/TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/Program.cs b/TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/Program.cs new file mode 100644 index 000000000..db2c801fd --- /dev/null +++ b/TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/Program.cs @@ -0,0 +1,19 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Diagnostics; + +namespace TestApp +{ + public class Program + { + public static int Main(string[] args) + { + Console.WriteLine("This string came from ProjectJ"); + string helperStr = TestLibrary.ProjectI.GetMessage(); + Console.WriteLine(helperStr); + return 0; + } + } +} diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/project.json b/TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/project.json new file mode 100644 index 000000000..7952dd345 --- /dev/null +++ b/TestAssets/TestProjects/ProjectsWithGlobalJson/src with spaces/ProjectJ/project.json @@ -0,0 +1,20 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "dependencies": { + "ProjectI": { + "target": "project", + "version": "1.0.0-*" + }, + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.1" + } + }, + "frameworks": { + "netcoreapp1.0": {} + } +} diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/.noautobuild b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/Program.cs b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/Program.cs new file mode 100644 index 000000000..27e455e98 --- /dev/null +++ b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/Program.cs @@ -0,0 +1,19 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Diagnostics; + +namespace TestApp +{ + public class Program + { + public static int Main(string[] args) + { + Console.WriteLine("This string came from ProjectH"); + string helperStr = TestLibrary.ProjectI.GetMessage(); + Console.WriteLine(helperStr); + return 0; + } + } +} diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/project.json b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/project.json new file mode 100644 index 000000000..7952dd345 --- /dev/null +++ b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectH/project.json @@ -0,0 +1,20 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "emitEntryPoint": true, + "preserveCompilationContext": true + }, + "dependencies": { + "ProjectI": { + "target": "project", + "version": "1.0.0-*" + }, + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.1" + } + }, + "frameworks": { + "netcoreapp1.0": {} + } +} diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/.noautobuild b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/.noautobuild new file mode 100644 index 000000000..e69de29bb diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/Helper.cs b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/Helper.cs new file mode 100644 index 000000000..d92100c45 --- /dev/null +++ b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/Helper.cs @@ -0,0 +1,15 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace TestLibrary +{ + public static class ProjectI + { + public static string GetMessage() + { + return "This string came from ProjectI"; + } + } +} diff --git a/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/project.json b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/project.json new file mode 100644 index 000000000..48bc772d8 --- /dev/null +++ b/TestAssets/TestProjects/ProjectsWithGlobalJson/src/ProjectI/project.json @@ -0,0 +1,18 @@ +{ + "version": "1.0.0-*", + "buildOptions": { + "nowarn": [ + "CS1591" + ], + "xmlDoc": true, + "additionalArguments": [ + "-highentropyva+" + ] + }, + "dependencies": { + "NETStandard.Library": "1.6.0" + }, + "frameworks": { + "netstandard1.5": {} + } +} diff --git a/build/Microsoft.DotNet.Cli.Test.targets b/build/Microsoft.DotNet.Cli.Test.targets index 410cd753d..59ec2aae9 100644 --- a/build/Microsoft.DotNet.Cli.Test.targets +++ b/build/Microsoft.DotNet.Cli.Test.targets @@ -1,5 +1,5 @@ - - + + / @@ -7,14 +7,11 @@ - + DependsOnTargets="BuildTests;"> : @@ -39,11 +36,10 @@ CLIBuildDll=$(CLIBuildDll); Configuration=$(Configuration); EnvironmentVariables=$(RunTestEnvironmentVariables); - TestProject=%(TestProjects.ProjectPath); - TestProjectName=%(TestProjects.OutputName); + TestProject=%(TestProjects.Identity); TestResultXmlDir=$(TestResultXmlDir); ToolPath=$(Stage0Directory); - WorkingDirectory=%(TestProjects.ProjectDir) + WorkingDirectory=$([System.IO.Directory]::GetParent(%(TestProjects.Identity))) @@ -59,7 +55,8 @@ + DependsOnTargets="Init; + SetupTestProjectData"> $(CommitCount) $(RepoRoot)/artifacts/testpackages/ @@ -74,113 +71,21 @@ - - - - - - + DependsOnTargets="PrepareTests; + CreateTestAssetPackageNuPkgs;"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/build/test/TestProjects.targets b/build/test/TestProjects.targets index 6ac27eaf9..846c7be22 100644 --- a/build/test/TestProjects.targets +++ b/build/test/TestProjects.targets @@ -1,32 +1,7 @@ - - - - - %(TestProjects.ProjectPath) - - - - - @(TestProjectInputs) - - - - - - - - %(TestProjects.ProjectPath) - - + DependsOnTargets="SetupBuildTestProjectInputs"> @@ -37,53 +12,21 @@ --> - - + test$(PathSeparator)Msbuild.Tests.Utilities$(PathSeparator)Msbuild.Tests.Utilities.csproj; + test$(PathSeparator)Performance$(PathSeparator)Performance.csproj" /> - - - - - - + - - - %(RelativeDir)**/*.* - %(RelativeDir)bin/**/*.*;%(RelativeDir)obj/**/*.* - $([System.IO.Directory]::GetParent(%(Identity))) - %(Identity) - netcoreapp1.0 - - - - $([System.IO.Path]::GetFileName(%(ProjectDir))) - - - - $(RepoRoot)%(TestProjects.RelativeDir)bin/$(Configuration)/%(TestProjects.Framework)/%(TestProjects.OutputName).dll - - - - net46 - - - - \ No newline at end of file + diff --git a/src/Microsoft.DotNet.TestFramework/TestAssetInfo.cs b/src/Microsoft.DotNet.TestFramework/TestAssetInfo.cs index e1bcbcbf8..760c33ec4 100644 --- a/src/Microsoft.DotNet.TestFramework/TestAssetInfo.cs +++ b/src/Microsoft.DotNet.TestFramework/TestAssetInfo.cs @@ -346,7 +346,7 @@ namespace Microsoft.DotNet.TestFramework file.Refresh(); if (!file.Exists) { - throw new ArgumentException("Inventory file should exist."); + return Enumerable.Empty(); } var inventory = new List(); diff --git a/test/Installer/Microsoft.DotNet.Cli.Msi.Tests/Microsoft.DotNet.Cli.Msi.Tests.csproj b/test/Installer/Microsoft.DotNet.Cli.Msi.Tests/Microsoft.DotNet.Cli.Msi.Tests.csproj index e444481b1..b24cec34e 100644 --- a/test/Installer/Microsoft.DotNet.Cli.Msi.Tests/Microsoft.DotNet.Cli.Msi.Tests.csproj +++ b/test/Installer/Microsoft.DotNet.Cli.Msi.Tests/Microsoft.DotNet.Cli.Msi.Tests.csproj @@ -1,4 +1,4 @@ - + @@ -35,8 +35,4 @@ - - - $(DefineConstants);RELEASE - diff --git a/test/Kestrel.Tests/DotnetBuildTest.cs b/test/Kestrel.Tests/DotnetBuildTest.cs deleted file mode 100644 index fb4fc8a54..000000000 --- a/test/Kestrel.Tests/DotnetBuildTest.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.IO; -using Microsoft.DotNet.Tools.Test.Utilities; -using Xunit; -using Microsoft.DotNet.TestFramework; - -namespace Microsoft.DotNet.Kestrel.Tests -{ - public class DotnetBuildTest : TestBase - { - public static string KestrelPortableApp { get; } = "KestrelPortable"; - - [Fact] - public void BuildingKestrelPortableFatAppProducesExpectedArtifacts() - { - var testInstance = TestAssetsManager.CreateTestInstance("KestrelSample") - .WithLockFiles(); - - BuildAndTest(Path.Combine(testInstance.TestRoot, KestrelPortableApp)); - } - - private static void BuildAndTest(string testRoot) - { - string appName = Path.GetFileName(testRoot); - - - var result = new BuildCommand( - projectPath: testRoot) - .ExecuteWithCapturedOutput(); - - result.Should().Pass(); - - var outputBase = new DirectoryInfo(Path.Combine(testRoot, "bin", "Debug")); - - var netcoreAppOutput = outputBase.Sub("netcoreapp1.0"); - - netcoreAppOutput.Should() - .Exist().And - .OnlyHaveFiles(new[] - { - $"{appName}.deps.json", - $"{appName}.dll", - $"{appName}.pdb", - $"{appName}.runtimeconfig.json", - $"{appName}.runtimeconfig.dev.json" - }); - } - } -} diff --git a/test/Kestrel.Tests/DotnetRunTest.cs b/test/Kestrel.Tests/DotnetRunTest.cs deleted file mode 100644 index 121c97a05..000000000 --- a/test/Kestrel.Tests/DotnetRunTest.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.IO; -using Microsoft.DotNet.TestFramework; -using Microsoft.DotNet.Tools.Test.Utilities; -using Xunit; -using System.Net.Http; -using System.Threading.Tasks; -using FluentAssertions; - -namespace Microsoft.DotNet.Kestrel.Tests -{ - public class DotnetRunTest : TestBase - { - private const string KestrelSampleBase = "KestrelSample"; - private const string KestrelPortable = "KestrelPortable"; - private const string KestrelStandalone = "KestrelStandalone"; - - [Fact] - public void ItRunsKestrelPortableApp() - { - TestInstance instance = TestAssetsManager.CreateTestInstance(KestrelSampleBase) - .WithLockFiles(); - - var url = NetworkHelper.GetLocalhostUrlWithFreePort(); - var args = $"{url} {Guid.NewGuid().ToString()}"; - var runCommand = new RunCommand(Path.Combine(instance.TestRoot, KestrelPortable)); - - try - { - runCommand.ExecuteAsync(args); - NetworkHelper.IsServerUp(url).Should().BeTrue($"Unable to connect to kestrel server - {KestrelPortable} @ {url}"); - NetworkHelper.TestGetRequest(url, args); - } - finally - { - runCommand.KillTree(); - } - } - - [Fact] - public void ItRunsKestrelStandaloneApp() - { - TestInstance instance = TestAssetsManager.CreateTestInstance(KestrelSampleBase) - .WithLockFiles(); - - var url = NetworkHelper.GetLocalhostUrlWithFreePort(); - var args = $"{url} {Guid.NewGuid().ToString()}"; - var runCommand = new RunCommand(Path.Combine(instance.TestRoot, KestrelStandalone)); - - try - { - runCommand.ExecuteAsync(args); - NetworkHelper.IsServerUp(url).Should().BeTrue($"Unable to connect to kestrel server - {KestrelStandalone} @ {url}"); - NetworkHelper.TestGetRequest(url, args); - } - finally - { - runCommand.KillTree(); - } - } - } -} diff --git a/test/Kestrel.Tests/DotnetTest.cs b/test/Kestrel.Tests/DotnetTest.cs deleted file mode 100644 index 4953e89fa..000000000 --- a/test/Kestrel.Tests/DotnetTest.cs +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Microsoft.DotNet.TestFramework; -using Microsoft.DotNet.Tools.Test.Utilities; -using Xunit; -using System.Threading.Tasks; -using FluentAssertions; - -namespace Microsoft.DotNet.Kestrel.Tests -{ - public class DotnetTest : TestBase - { - private const string KestrelSampleBase = "KestrelSample"; - private const string KestrelPortable = "KestrelPortable"; - private const string KestrelStandalone = "KestrelStandalone"; - - [Fact] - public void ItRunsKestrelPortableAfterBuild() - { - TestInstance instance = TestAssetsManager.CreateTestInstance(KestrelSampleBase) - .WithLockFiles(); - - var url = NetworkHelper.GetLocalhostUrlWithFreePort(); - var args = $"{url} {Guid.NewGuid().ToString()}"; - var dotnetCommand = new DotnetCommand(); - var output = Build(Path.Combine(instance.TestRoot, KestrelPortable)); - - try - { - dotnetCommand.ExecuteAsync($"{output} {args}"); - NetworkHelper.IsServerUp(url).Should().BeTrue($"Unable to connect to kestrel server - {KestrelPortable} @ {url}"); - NetworkHelper.TestGetRequest(url, args); - } - finally - { - dotnetCommand.KillTree(); - } - } - - [Fact] - public void ItRunsKestrelStandaloneAfterBuild() - { - TestInstance instance = TestAssetsManager.CreateTestInstance(KestrelSampleBase) - .WithLockFiles(); - - var url = NetworkHelper.GetLocalhostUrlWithFreePort(); - var args = $"{url} {Guid.NewGuid().ToString()}"; - var dotnetCommand = new DotnetCommand(); - var output = Build(Path.Combine(instance.TestRoot, KestrelStandalone)); - - try - { - dotnetCommand.ExecuteAsync($"{output} {args}"); - NetworkHelper.IsServerUp(url).Should().BeTrue($"Unable to connect to kestrel server - {KestrelStandalone} @ {url}"); - NetworkHelper.TestGetRequest(url, args); - } - finally - { - dotnetCommand.KillTree(); - } - } - - [Fact] - public void ItRunsKestrelPortableAfterPublish() - { - TestInstance instance = TestAssetsManager.CreateTestInstance(KestrelSampleBase) - .WithLockFiles(); - - var url = NetworkHelper.GetLocalhostUrlWithFreePort(); - var args = $"{url} {Guid.NewGuid().ToString()}"; - var dotnetCommand = new DotnetCommand(); - var output = Publish(Path.Combine(instance.TestRoot, KestrelPortable), true); - - try - { - dotnetCommand.ExecuteAsync($"{output} {args}"); - NetworkHelper.IsServerUp(url).Should().BeTrue($"Unable to connect to kestrel server - {KestrelPortable} @ {url}"); - NetworkHelper.TestGetRequest(url, args); - } - finally - { - dotnetCommand.KillTree(); - } - } - - [Fact] - public void ItRunsKestrelStandaloneAfterPublish() - { - TestInstance instance = TestAssetsManager.CreateTestInstance(KestrelSampleBase) - .WithLockFiles(); - - var url = NetworkHelper.GetLocalhostUrlWithFreePort(); - var args = $"{url} {Guid.NewGuid().ToString()}"; - var output = Publish(Path.Combine(instance.TestRoot, KestrelStandalone), false); - var command = new TestCommand(output); - - try - { - command.ExecuteAsync($"{args}"); - NetworkHelper.IsServerUp(url).Should().BeTrue($"Unable to connect to kestrel server - {KestrelStandalone} @ {url}"); - NetworkHelper.TestGetRequest(url, args); - } - finally - { - command.KillTree(); - } - } - - private static string Build(string testRoot) - { - string appName = Path.GetFileName(testRoot); - - var result = new BuildCommand( - projectPath: testRoot) - .ExecuteWithCapturedOutput(); - - result.Should().Pass(); - - // the correct build assembly is next to its deps.json file - var depsJsonFile = Directory.EnumerateFiles(testRoot, appName + FileNameSuffixes.DepsJson, SearchOption.AllDirectories).First(); - return Path.Combine(Path.GetDirectoryName(depsJsonFile), appName + ".dll"); - } - - private static string Publish(string testRoot, bool isPortable) - { - string appName = Path.GetFileName(testRoot); - - var publishCmd = new PublishCommand(projectPath: testRoot, output: Path.Combine(testRoot, "bin")); - var result = publishCmd.ExecuteWithCapturedOutput(); - result.Should().Pass(); - - var publishDir = publishCmd.GetOutputDirectory(portable: isPortable).FullName; - return Path.Combine(publishDir, appName + (isPortable ? ".dll" : FileNameSuffixes.CurrentPlatform.Exe)); - } - } -} diff --git a/test/Kestrel.Tests/Kestrel.Tests.csproj b/test/Kestrel.Tests/Kestrel.Tests.csproj deleted file mode 100644 index 7542b751f..000000000 --- a/test/Kestrel.Tests/Kestrel.Tests.csproj +++ /dev/null @@ -1,49 +0,0 @@ - - - - - netcoreapp1.0 - true - Kestrel.Tests - $(PackageTargetFallback);dotnet5.4;portable-net451+win8 - - - - - - - true - - - true - - - - - - true - - - - - - 15.0.0-preview-20161024-02 - - - 2.2.0-beta4-build1194 - - - 1.0.3 - - - 4.1.1 - - - 2.2.0-beta4-build3444 - - - - - $(DefineConstants);RELEASE - - diff --git a/test/Microsoft.DotNet.Cli.Tests.sln b/test/Microsoft.DotNet.Cli.Tests.sln index 95ea83fcb..dd933551d 100644 --- a/test/Microsoft.DotNet.Cli.Tests.sln +++ b/test/Microsoft.DotNet.Cli.Tests.sln @@ -38,10 +38,6 @@ Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "crossgen.Tests", "crossgen. EndProject Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "binding-redirects.Tests", "binding-redirects.Tests\binding-redirects.Tests.csproj", "{18702FC5-7B1A-49B7-A335-A926064D577A}" EndProject -Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "Microsoft.DotNet.Cli.Msi.Tests", "Installer\Microsoft.DotNet.Cli.Msi.Tests\Microsoft.DotNet.Cli.Msi.Tests.csproj", "{2867CE61-92A5-49EC-B9F5-424655257069}" -EndProject -Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "Kestrel.Tests", "Kestrel.Tests\Kestrel.Tests.csproj", "{642A0997-86E6-40E6-8E74-BFE2DC7C4A58}" -EndProject Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "ArgumentForwardingTests", "ArgumentForwardingTests\ArgumentForwardingTests.csproj", "{67418187-0CF6-4213-87D0-5B9B841FD755}" EndProject Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "ArgumentsReflector", "ArgumentsReflector\ArgumentsReflector.csproj", "{8818FEBB-7243-4AB5-9E1C-179F5189FBD7}" @@ -62,8 +58,6 @@ Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "EndToEnd", "EndToEnd\EndToE EndProject Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "dotnet.Tests", "dotnet.Tests\dotnet.Tests.csproj", "{B4B5DA8E-E2EA-49CB-8B8C-4E157D42E710}" EndProject -Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "Performance", "Performance\Performance.csproj", "{2CD55F27-3755-4E7D-8524-81B0BBCB93A4}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dotnet-sln-add.Tests", "dotnet-sln-add.Tests", "{5FF48976-B083-4E3B-A8E7-6FCD225D5C8E}" EndProject Project("{13B669BE-BB05-4DDF-9536-439F39A36129}") = "dotnet-sln-add.Tests", "dotnet-sln-add.Tests\dotnet-sln-add.Tests.csproj", "{FC849626-89C9-4F50-A2CA-53C4315A87F8}" @@ -160,14 +154,6 @@ Global {18702FC5-7B1A-49B7-A335-A926064D577A}.Debug|Any CPU.Build.0 = Debug|Any CPU {18702FC5-7B1A-49B7-A335-A926064D577A}.Release|Any CPU.ActiveCfg = Release|Any CPU {18702FC5-7B1A-49B7-A335-A926064D577A}.Release|Any CPU.Build.0 = Release|Any CPU - {2867CE61-92A5-49EC-B9F5-424655257069}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2867CE61-92A5-49EC-B9F5-424655257069}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2867CE61-92A5-49EC-B9F5-424655257069}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2867CE61-92A5-49EC-B9F5-424655257069}.Release|Any CPU.Build.0 = Release|Any CPU - {642A0997-86E6-40E6-8E74-BFE2DC7C4A58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {642A0997-86E6-40E6-8E74-BFE2DC7C4A58}.Debug|Any CPU.Build.0 = Debug|Any CPU - {642A0997-86E6-40E6-8E74-BFE2DC7C4A58}.Release|Any CPU.ActiveCfg = Release|Any CPU - {642A0997-86E6-40E6-8E74-BFE2DC7C4A58}.Release|Any CPU.Build.0 = Release|Any CPU {67418187-0CF6-4213-87D0-5B9B841FD755}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {67418187-0CF6-4213-87D0-5B9B841FD755}.Debug|Any CPU.Build.0 = Debug|Any CPU {67418187-0CF6-4213-87D0-5B9B841FD755}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -208,10 +194,6 @@ Global {B4B5DA8E-E2EA-49CB-8B8C-4E157D42E710}.Debug|Any CPU.Build.0 = Debug|Any CPU {B4B5DA8E-E2EA-49CB-8B8C-4E157D42E710}.Release|Any CPU.ActiveCfg = Release|Any CPU {B4B5DA8E-E2EA-49CB-8B8C-4E157D42E710}.Release|Any CPU.Build.0 = Release|Any CPU - {2CD55F27-3755-4E7D-8524-81B0BBCB93A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2CD55F27-3755-4E7D-8524-81B0BBCB93A4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2CD55F27-3755-4E7D-8524-81B0BBCB93A4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2CD55F27-3755-4E7D-8524-81B0BBCB93A4}.Release|Any CPU.Build.0 = Release|Any CPU {FC849626-89C9-4F50-A2CA-53C4315A87F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FC849626-89C9-4F50-A2CA-53C4315A87F8}.Debug|Any CPU.Build.0 = Debug|Any CPU {FC849626-89C9-4F50-A2CA-53C4315A87F8}.Debug|x64.ActiveCfg = Debug|x64 diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Microsoft.DotNet.Tools.Tests.Utilities.csproj b/test/Microsoft.DotNet.Tools.Tests.Utilities/Microsoft.DotNet.Tools.Tests.Utilities.csproj index e353bcbfe..32a322248 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Microsoft.DotNet.Tools.Tests.Utilities.csproj +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Microsoft.DotNet.Tools.Tests.Utilities.csproj @@ -3,7 +3,7 @@ Microsoft.DotNet.Tools.Tests.Utilities Class Library - netcoreapp1.0;net46 + netcoreapp1.0 true Microsoft.DotNet.Tools.Tests.Utilities ../../tools/Key.snk diff --git a/test/Performance/.gitignore b/test/Performance/.gitignore deleted file mode 100644 index c52d34fee..000000000 --- a/test/Performance/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/*.html -/*.csv -/*.xml -/*.xml.bak diff --git a/test/Performance/BuildPerformanceTest.cs b/test/Performance/BuildPerformanceTest.cs deleted file mode 100644 index b3e649a72..000000000 --- a/test/Performance/BuildPerformanceTest.cs +++ /dev/null @@ -1,353 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Linq; -using Microsoft.DotNet.Tools.Test.Utilities; -using Microsoft.Xunit.Performance; -using Microsoft.DotNet.TestFramework; -using System.IO; -using System.Runtime.CompilerServices; -using System; -using System.Collections.Generic; - -namespace Microsoft.DotNet.Tools.Builder.Tests -{ - public class BuildPerformanceTest : TestBase - { - private static string SingleTargetApp = "SingleTargetApp"; - private static string TwoTargetApp = "TwoTargetApp"; - - private static string[] SingleTargetGraph = new[] - { - "SingleTargetGraph/SingleTargetP0", - "SingleTargetGraph/SingleTargetP1", - "SingleTargetGraph/SingleTargetP2" - }; - - private static string[] TwoTargetGraph = new[] - { - "TwoTargetGraph/TwoTargetP0", - "TwoTargetGraph/TwoTargetP1", - "TwoTargetGraph/TwoTargetP2" - }; - - private static string[] TwoTargetGraphLarge = new[] - { - "TwoTargetGraphLarge/TwoTargetLargeP0", - "TwoTargetGraphLarge/TwoTargetLargeP1", - "TwoTargetGraphLarge/TwoTargetLargeP2", - "TwoTargetGraphLarge/TwoTargetLargeP3", - "TwoTargetGraphLarge/TwoTargetLargeP4", - "TwoTargetGraphLarge/TwoTargetLargeP5", - "TwoTargetGraphLarge/TwoTargetLargeP6" - }; - - [Benchmark] - public void BuildSingleProject_SingleTargetApp() => BuildSingleProject(CreateTestInstance(SingleTargetApp)); - - [Benchmark] - public void BuildSingleProject_TwoTargetApp() => BuildSingleProject(CreateTestInstance(TwoTargetApp)); - - public void BuildSingleProject(TestAssetInstance instance) - { - foreach (var iteration in Benchmark.Iterations) - { - var buildCommand = new BuildCommand() - .WithProjectDirectory(instance.Root); - - using (iteration.StartMeasurement()) - { - buildCommand.Execute() - .Should().Pass(); - } - - TouchSource(instance.Root); - } - } - - [Benchmark] - public void IncrementalSkipSingleProject_SingleTargetApp() => IncrementalSkipSingleProject(CreateTestInstance(SingleTargetApp)); - - [Benchmark] - public void IncrementalSkipSingleProject_TwoTargetApp() => IncrementalSkipSingleProject(CreateTestInstance(TwoTargetApp)); - - public void IncrementalSkipSingleProject(TestAssetInstance instance) - { - new BuildCommand() - .WithProjectDirectory(instance.Root) - .Execute() - .Should().Pass(); - - foreach (var iteration in Benchmark.Iterations) - { - var buildCommand = new BuildCommand() - .WithProjectDirectory(instance.Root); - - using (iteration.StartMeasurement()) - { - buildCommand - .Execute() - .Should().Pass(); - } - } - } - - [Benchmark] - public void BuildAllInGraph_SingleTargetGraph() => BuildAllInGraph(CreateTestInstances(SingleTargetGraph)); - - [Benchmark] - public void BuildAllInGraph_TwoTargetGraph() => BuildAllInGraph(CreateTestInstances(TwoTargetGraph)); - - [Benchmark] - public void BuildAllInGraph_TwoTargetGraphLarge() => BuildAllInGraph(CreateTestInstances(TwoTargetGraphLarge)); - - public void BuildAllInGraph(TestAssetInstance[] instances) - { - var instance = instances[0]; - - foreach (var iteration in Benchmark.Iterations) - { - var buildCommand = new BuildCommand() - .WithProjectDirectory(instance.Root); - - using (iteration.StartMeasurement()) - { - buildCommand - .Execute() - .Should().Pass(); - } - - foreach (var i in instances) - { - TouchSource(i.Root); - } - } - } - - [Benchmark] - public void IncrementalSkipAllInGraph_SingleTargetGraph() => - IncrementalSkipAllInGraph(CreateTestInstances(SingleTargetGraph)); - - [Benchmark] - public void IncrementalSkipAllInGraph_TwoTargetGraph() => - IncrementalSkipAllInGraph(CreateTestInstances(TwoTargetGraph)); - - [Benchmark] - public void IncrementalSkipAllInGraphh_TwoTargetGraphLarge() => - IncrementalSkipAllInGraph(CreateTestInstances(TwoTargetGraphLarge)); - - public void IncrementalSkipAllInGraph(TestAssetInstance[] instances) - { - var instance = instances[0]; - - new BuildCommand() - .WithProjectDirectory(instance.Root) - .Execute() - .Should().Pass(); - - foreach (var iteration in Benchmark.Iterations) - { - var buildCommand = new BuildCommand() - .WithProjectDirectory(instance.Root); - - using (iteration.StartMeasurement()) - { - buildCommand - .Execute() - .Should().Pass(); - } - } - } - - [Benchmark] - public void IncrementalRebuildWithRootChangedInGraph_SingleTargetGraph() => - IncrementalRebuildWithRootChangedInGraph(CreateTestInstances(SingleTargetGraph)); - - [Benchmark] - public void IncrementalRebuildWithRootChangedInGraph_TwoTargetGraph() => - IncrementalRebuildWithRootChangedInGraph(CreateTestInstances(TwoTargetGraph)); - - [Benchmark] - public void IncrementalRebuildWithRootChangedInGraph_TwoTargetGraphLarge() => - IncrementalRebuildWithRootChangedInGraph(CreateTestInstances(TwoTargetGraphLarge)); - - public void IncrementalRebuildWithRootChangedInGraph(TestAssetInstance[] instances) - { - var instance = instances[0]; - new BuildCommand() - .WithProjectDirectory(instance.Root) - .Execute() - .Should().Pass(); - - foreach (var iteration in Benchmark.Iterations) - { - var buildCommand = new BuildCommand() - .WithProjectDirectory(instance.Root); - - using (iteration.StartMeasurement()) - { - buildCommand - .Execute() - .Should().Pass(); - } - - TouchSource(instance.Root); - } - } - - [Benchmark] - public void IncrementalRebuildWithLastChangedInGraph_SingleTargetGraph() => - IncrementalRebuildWithLastChangedInGraph(CreateTestInstances(SingleTargetGraph)); - - [Benchmark] - public void IncrementalRebuildWithLastChangedInGraph_TwoTargetGraph() => - IncrementalRebuildWithLastChangedInGraph(CreateTestInstances(TwoTargetGraph)); - - [Benchmark] - public void IncrementalRebuildWithLastChangedInGraph_TwoTargetGraphLarge() => - IncrementalRebuildWithLastChangedInGraph(CreateTestInstances(TwoTargetGraphLarge)); - - public void IncrementalRebuildWithLastChangedInGraph(TestAssetInstance[] instances) - { - var instance = instances[0]; - - new BuildCommand() - .WithProjectDirectory(instance.Root) - .Execute() - .Should().Pass(); - - foreach (var iteration in Benchmark.Iterations) - { - var buildCommand = new BuildCommand() - .WithProjectDirectory(instance.Root); - - using (iteration.StartMeasurement()) - { - buildCommand - .Execute() - .Should().Pass(); - } - - TouchSource(instances.Last().Root); - } - } - - - [Benchmark] - public void IncrementalSkipAllNoDependenciesInGraph_SingleTargetGraph() => - IncrementalSkipAllNoDependenciesInGraph(CreateTestInstances(SingleTargetGraph)); - - [Benchmark] - public void IncrementalSkipAllNoDependenciesInGraph_TwoTargetGraph() => - IncrementalSkipAllNoDependenciesInGraph(CreateTestInstances(TwoTargetGraph)); - - [Benchmark] - public void IncrementalSkipAllNoDependenciesInGraph_TwoTargetGraphLarge() => - IncrementalSkipAllNoDependenciesInGraph(CreateTestInstances(TwoTargetGraphLarge)); - - public void IncrementalSkipAllNoDependenciesInGraph(TestAssetInstance[] instances) - { - var instance = instances[0]; - - new BuildCommand() - .WithProjectDirectory(instance.Root) - .Execute() - .Should().Pass(); - - foreach (var iteration in Benchmark.Iterations) - { - var commands = new List(); - - foreach (var i in instances.Reverse()) - { - var buildCommand = new BuildCommand() - .WithProjectDirectory(instance.Root) - .WithFramework(NuGet.Frameworks.FrameworkConstants.CommonFrameworks.NetCoreApp10) - .WithNoDependencies(); - - commands.Add(buildCommand); - } - - using (iteration.StartMeasurement()) - { - foreach (var buildCommand in commands) - { - buildCommand - .Execute() - .Should().Pass(); - } - } - } - } - [Benchmark] - public void BuildAllNoDependenciesInGraph_SingleTargetGraph() => - BuildAllNoDependenciesInGraph(CreateTestInstances(SingleTargetGraph)); - - [Benchmark] - public void BuildAllNoDependenciesInGraph_TwoTargetGraph() => - BuildAllNoDependenciesInGraph(CreateTestInstances(TwoTargetGraph)); - - [Benchmark] - public void BuildAllNoDependenciesInGraph_TwoTargetGraphLarge() => - BuildAllNoDependenciesInGraph(CreateTestInstances(TwoTargetGraphLarge)); - - public void BuildAllNoDependenciesInGraph(TestAssetInstance[] instances) - { - foreach (var iteration in Benchmark.Iterations) - { - var commands = new List(); - - foreach (var i in instances.Reverse()) - { - var buildCommand = new BuildCommand() - .WithProjectDirectory(i.Root) - .WithFramework(NuGet.Frameworks.FrameworkConstants.CommonFrameworks.NetCoreApp10) - .WithNoDependencies(); - - commands.Add(buildCommand); - } - - using (iteration.StartMeasurement()) - { - foreach (var buildCommand in commands) - { - buildCommand.Execute().Should().Pass(); - } - } - - foreach (var instance in instances) - { - TouchSource(instance.Root); - } - } - } - - protected void TouchSource(DirectoryInfo projectDir) - { - var sourceFile = projectDir.GetFiles("*.cs", SearchOption.AllDirectories).FirstOrDefault(); - - if (sourceFile == null) - { - throw new InvalidOperationException($"'.cs' files not found in {projectDir.FullName}"); - } - - sourceFile.LastWriteTime = DateTime.Now; - } - - protected TestAssetInstance[] CreateTestInstances(string[] testProjectNames, [CallerMemberName] string callingMethod = "") - { - return testProjectNames.Select(testProjectName => - { - return CreateTestInstance(testProjectName, callingMethod); - }).ToArray(); - } - - protected TestAssetInstance CreateTestInstance(string testProjectName, [CallerMemberName] string callingMethod = "") - { - return TestAssets.Get(Path.Combine("PerformanceTestProjects", testProjectName)) - .CreateInstance(callingMethod) - .WithSourceFiles() - .WithRestoreFiles(); - } - } -} diff --git a/test/Performance/HelloWorld.cs b/test/Performance/HelloWorld.cs deleted file mode 100644 index 4ff927437..000000000 --- a/test/Performance/HelloWorld.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.IO; -using Microsoft.DotNet.Tools.Test.Utilities; -using Microsoft.Xunit.Performance; - -namespace Microsoft.DotNet.Tests.Performance -{ - public class HelloWorld : TestBase - { - private static readonly string s_testdirName = "helloworldtestroot"; - private static readonly string s_testProject = $"{s_testdirName}.csproj"; - private static readonly string s_outputdirName = "test space/bin"; - - private static string AssetsRoot { get; set; } - private static string RestoredTestProjectDirectory { get; set; } - - private string ProjectPath { get; set; } - private string TestDirectory { get; set; } - private string OutputDirectory { get; set; } - - static HelloWorld() - { - HelloWorld.SetupStaticTestProject(); - } - - public HelloWorld() - { - } - - [Benchmark] - public void MeasureDotNetBuild() - { - foreach (var iter in Benchmark.Iterations) - { - // Setup a new instance of the test project. - TestInstanceSetup(); - - // Setup the build command. - var buildCommand = new BuildCommand(); - using (iter.StartMeasurement()) - { - // Execute the build command. - buildCommand.Execute($"{ProjectPath} --output \"{OutputDirectory}\" --framework {DefaultFramework}"); - } - } - } - - private void TestInstanceSetup() - { - var root = Temp.CreateDirectory(); - - var testInstanceDir = root.CopyDirectory(RestoredTestProjectDirectory); - - TestDirectory = testInstanceDir.Path; - OutputDirectory = Path.Combine(TestDirectory, s_outputdirName); - ProjectPath = Path.Combine(TestDirectory, s_testProject); - } - - private static void SetupStaticTestProject() - { - AssetsRoot = Path.Combine(AppContext.BaseDirectory, "bin"); - RestoredTestProjectDirectory = Path.Combine(AssetsRoot, s_testdirName); - - // Ignore Delete Failure - try - { - Directory.Delete(RestoredTestProjectDirectory, true); - } - catch (Exception) { } - - Directory.CreateDirectory(RestoredTestProjectDirectory); - - // Todo: this is a hack until corefx is on nuget.org remove this After RC 2 Release - NuGetConfig.Write(RestoredTestProjectDirectory); - - var newCommand = new NewCommand(); - newCommand.WorkingDirectory = RestoredTestProjectDirectory; - newCommand.Execute().Should().Pass(); - - var restoreCommand = new RestoreCommand(); - restoreCommand.WorkingDirectory = RestoredTestProjectDirectory; - restoreCommand.Execute("/p:SkipInvalidConfigurations=true") - .Should().Pass(); - } - } -} diff --git a/test/Performance/Performance.csproj b/test/Performance/Performance.csproj deleted file mode 100644 index 71c2123ca..000000000 --- a/test/Performance/Performance.csproj +++ /dev/null @@ -1,55 +0,0 @@ - - - - - netcoreapp1.0 - true - Performance - $(PackageTargetFallback);dotnet5.4;portable-net451+win8 - - - - - - - true - - - true - - - - - - true - - - - - - 15.0.0-preview-20161024-02 - - - 2.2.0-beta4-build1194 - - - 1.0.3 - - - 4.1.1 - - - 2.2.0-beta4-build3444 - - - 1.0.0-prerelease-00206 - - - 1.0.0-alpha-build0028 - - - - - $(DefineConstants);RELEASE - - diff --git a/test/Performance/README.md b/test/Performance/README.md deleted file mode 100644 index 7a23147a9..000000000 --- a/test/Performance/README.md +++ /dev/null @@ -1,54 +0,0 @@ -Running Performance Tests -========================= - -Pre-Requisites --------------- - -* Python 2.7+ or 3.5+ -* msbuild.exe (must be on `PATH`) - -Single Perf Run ---------------- - -1. Build the CLI repo to get dotnet.exe, or otherwise source the CLI. For - meaningful perf results, be sure to use release mode. - -2. `cd /test/Performance` - -3. `python run-perftests.py --name - --xunit-perf-path ` - where: - * `` is the path to the dotnet binary whose perf you want to - measure. - * `` should point either to an non-existent directory, or to - the root of a local clone of xunit-performance. If a non-existent - directory is specified, the repo will automatically be cloned. - - NOTE: You can also set the environment variable - `XUNIT_PERFORMANCE_PATH` to avoid having to pass this variable every - time. - -4. View the `*.csv` / `*.xml` results in the current directory. - -Comparison Run --------------- - -In general, follow the same steps as for a single perf run. The following -additional steps are required: - -1. In addition to the dotnet.exe that you're testing, be sure to also build or - otherwise source the baseline dotnet.exe. This could be the "stage0" exe, or - the exe from the last nightly build, or the exe built from sources prior to - changes you made, etc. - -2. When invoking `run-perftests.py`, add an additional parameter: `--base - `, which points to the baseline dotnet.exe mentioned in step 1. - -3. View the `*.html` file generated for the perf comparison analysis. - -Debugging Issues ----------------- - -The output of commands invoked by `run-perftests` is hidden by default. You can -see the output after an error by looking in the `logs/run-perftests` directory. -Alternatively, you can rerun `run-perftests` with `--verbose`, which will print -all output to the console instead of piping it to log files. diff --git a/test/Performance/run-perftests.py b/test/Performance/run-perftests.py deleted file mode 100644 index c19c2cd1c..000000000 --- a/test/Performance/run-perftests.py +++ /dev/null @@ -1,249 +0,0 @@ -#!/usr/bin/env python - -import argparse -import glob -import os -import re -import subprocess -import sys - -SCRIPT_ROOT_PATH = os.path.dirname(os.path.realpath(__file__)) -PERFTEST_JSON_PATH = os.path.join(SCRIPT_ROOT_PATH, 'project.json') -XUNITPERF_REPO_URL = 'https://github.com/microsoft/xunit-performance.git' - -script_args = None - -class FatalError(Exception): - def __init__(self, message): - self.message = message - -def check_requirements(): - try: - run_command('git', '--version', quiet = True) - except: - raise FatalError("git not found, please make sure that it's installed and on path.") - - try: - run_command('msbuild', '-version', quiet = True) - except: - raise FatalError("msbuild not found, please make sure that it's installed and on path.") - - if script_args.xunit_perf_path == None: - raise FatalError("Don't know where to clone xunit-performance. Please specify --xunit-perf-path . " + - "You can also set/export XUNIT_PERFORMANCE_PATH to not have to set the value every time.") - -def process_arguments(): - parser = argparse.ArgumentParser( - description = "Runs CLI perf tests. Requires 'git' and 'msbuild' to be on the PATH.", - ) - - parser.add_argument( - 'test_cli', - help = "full path to the dotnet.exe under test", - ) - parser.add_argument( - '--runid', '--name', '-n', - help = "unique ID for this run", - required = True, - ) - parser.add_argument( - '--base', '--baseline', '-b', - help = "full path to the baseline dotnet.exe", - metavar = 'baseline_cli', - dest = 'base_cli', - ) - parser.add_argument( - '--xunit-perf-path', '-x', - help = """Path to local copy of the xunit-performance repository. - Required unless the environment variable XUNIT_PERFORMANCE_PATH is defined.""", - default = os.environ.get('XUNIT_PERFORMANCE_PATH'), - metavar = 'path', - ) - parser.add_argument( - '--rebuild', '--rebuild-tools', '-r', - help = "Rebuilds the test tools from scratch.", - action = 'store_true', - ) - parser.add_argument( - '--verbose', '-v', - help = "Shows the output of all commands run by this script", - action = 'store_true', - ) - - global script_args - script_args = parser.parse_args() - -def run_command(*vargs, **kwargs): - title = kwargs['title'] if 'title' in kwargs else None - from_dir = kwargs['from_dir'] if 'from_dir' in kwargs else None - quiet = kwargs['quiet'] if 'quiet' in kwargs else False - - quoted_args = map(lambda x: '"{x}"'.format(x=x) if ' ' in x else x, vargs) - cmd_line = ' '.join(quoted_args) - should_log = not script_args.verbose and title != None - redirect_args = { 'stderr': subprocess.STDOUT } - - nullfile = None - logfile = None - cwd = None - - try: - if should_log: - log_name = '-'.join(re.sub(r'\W', ' ', title).lower().split()) + '.log' - log_path = os.path.join(SCRIPT_ROOT_PATH, 'logs', 'run-perftests', log_name) - log_dir = os.path.dirname(log_path) - if not os.path.exists(log_dir): - os.makedirs(log_dir) - cmd_line += ' > "{log}"'.format(log = log_path) - logfile = open(log_path, 'w') - redirect_args['stdout'] = logfile - - elif quiet or not script_args.verbose: - nullfile = open(os.devnull, 'w') - redirect_args['stdout'] = nullfile - - prefix = '' - if not quiet and title != None: - print('# {msg}...'.format(msg = title)) - prefix = ' $ ' - - if from_dir != None: - cwd = os.getcwd() - if not quiet: print('{pref}cd "{dir}"'.format(pref = prefix, dir = from_dir)) - os.chdir(from_dir) - - if not quiet: print(prefix + cmd_line) - returncode = subprocess.call(vargs, **redirect_args) - - if returncode != 0: - logmsg = " See '{log}' for details.".format(log = log_path) if should_log else '' - raise FatalError("Command `{cmd}` returned with error code {e}.{log}".format(cmd = cmd_line, e = returncode, log = logmsg)) - - finally: - if logfile != None: logfile.close() - if nullfile != None: nullfile.close() - if cwd != None: os.chdir(cwd) - -def clone_repo(repo_url, local_path): - if os.path.exists(local_path): - # For now, we just assume that if the path exists, it's already the correct repo - print("# xunit-performance repo was detected at '{path}', skipping git clone".format(path = local_path)) - return - run_command( - 'git', 'clone', repo_url, local_path, - title = "Clone the xunit-performance repo", - ) - -def get_xunitperf_dotnet_path(xunitperf_src_path): - return os.path.join(xunitperf_src_path, 'tools', 'bin', 'dotnet') - -def get_xunitperf_runner_src_path(xunitperf_src_path): - return os.path.join(xunitperf_src_path, 'src', 'cli', 'Microsoft.DotNet.xunit.performance.runner.cli') - -def get_xunitperf_analyzer_path(xunitperf_src_path): - return os.path.join(xunitperf_src_path, 'src', 'xunit.performance.analysis', 'bin', 'Release', 'xunit.performance.analysis') - -def make_xunit_perf(xunitperf_src_path): - dotnet_path = get_xunitperf_dotnet_path(xunitperf_src_path) - dotnet_base_path = os.path.dirname(dotnet_path) - analyzer_base_path = os.path.dirname(get_xunitperf_analyzer_path(xunitperf_src_path)) - runner_src_path = get_xunitperf_runner_src_path(xunitperf_src_path) - - if script_args.rebuild or not os.path.exists(dotnet_base_path) or not os.path.exists(analyzer_base_path): - run_command( - 'CiBuild.cmd', '/release', - title = "Build xunit-performance", - from_dir = xunitperf_src_path, - ) - run_command( - dotnet_path, 'publish', '-c', 'Release', runner_src_path, - title = "Build Microsoft.DotNet.xunit.performance.runner.cli", - ) - else: - print("# xunit-performance at '{path}' was already built, skipping CiBuild. Use --rebuild to force rebuild.".format(path = xunitperf_src_path)) - -def run_perf_test(runid, cli_path, xunitperf_src_path): - cli_path = os.path.realpath(cli_path) - dotnet_path = get_xunitperf_dotnet_path(xunitperf_src_path) - runner_src_path = get_xunitperf_runner_src_path(xunitperf_src_path) - result_xml_path = os.path.join(SCRIPT_ROOT_PATH, '{}.xml'.format(runid)) - project_lock_path = os.path.join(SCRIPT_ROOT_PATH, 'project.lock.json') - - saved_path = os.environ.get('PATH') - print("# Prepending {dir} to PATH".format(dir = os.path.dirname(cli_path))) - os.environ['PATH'] = os.path.dirname(cli_path) + ';' + os.environ.get('PATH') - try: - if os.path.exists(project_lock_path): - print("# Deleting {file}".format(file = project_lock_path)) - os.remove(project_lock_path) - run_command( - cli_path, 'restore', '-f', 'https://dotnet.myget.org/f/dotnet-core', - title = "Dotnet restore using \"{cli}\"".format(cli = cli_path), - from_dir = SCRIPT_ROOT_PATH, - ) - run_command( - dotnet_path, 'run', '-p', runner_src_path, '-c', 'Release', '--', - '-runner', cli_path, '-runid', runid, - '-runnerargs', 'test {json} -c Release'.format(json = PERFTEST_JSON_PATH), - title = "Run {id}".format(id = runid), - from_dir = SCRIPT_ROOT_PATH, - ) - if not os.path.exists(result_xml_path): - raise FatalError("Running {id} seems to have failed: {xml} was not generated".format( - id = runid, xml = result_xml_path - )) - finally: - print("# Reverting PATH") - os.environ['PATH'] = saved_path - -def compare_results(base_id, test_id, out_html, xunitperf_src_path): - analyzer_path = get_xunitperf_analyzer_path(xunitperf_src_path) - - # Make sure there aren't any stale XMLs in the target dir - for xml in glob.glob(os.path.join(SCRIPT_ROOT_PATH, '*.xml')): - if not os.path.basename(xml) in [base_id + '.xml', test_id + '.xml']: - os.rename(xml, xml + '.bak') - - try: - run_command( - analyzer_path, SCRIPT_ROOT_PATH, '-compare', base_id, test_id, '-html', out_html, - title = "Generate comparison report", - from_dir = SCRIPT_ROOT_PATH, - ) - if os.path.exists(out_html): - print("# Comparison finished, please see \"{report}\" for details.".format(report = out_html)) - else: - raise FatalError("Failed to genererate comparison report: \"{report}\" not found.".format(report = out_html)) - - finally: - # Revert the renamed XMLs - for xml in glob.glob(os.path.join(SCRIPT_ROOT_PATH, '*.xml.bak')): - os.rename(xml, xml[0:-4]) - -def main(): - try: - process_arguments() - check_requirements() - - script_args.xunit_perf_path = os.path.realpath(script_args.xunit_perf_path) - - clone_repo(XUNITPERF_REPO_URL, script_args.xunit_perf_path) - make_xunit_perf(script_args.xunit_perf_path) - - base_runid = script_args.runid + '.base' - test_runid = script_args.runid + '.test' - out_html = os.path.join(SCRIPT_ROOT_PATH, script_args.runid + '.html') - - run_perf_test(test_runid, script_args.test_cli, script_args.xunit_perf_path) - if script_args.base_cli != None: - run_perf_test(base_runid, script_args.base_cli, script_args.xunit_perf_path) - compare_results(base_runid, test_runid, out_html, script_args.xunit_perf_path) - - return 0 - - except FatalError as error: - print("! ERROR: {msg}".format(msg = error.message)) - return 1 - -if __name__ == "__main__": - sys.exit(main()) diff --git a/test/binding-redirects.Tests/binding-redirects.Tests.csproj b/test/binding-redirects.Tests/binding-redirects.Tests.csproj index fd3d71cc1..9b619c83f 100644 --- a/test/binding-redirects.Tests/binding-redirects.Tests.csproj +++ b/test/binding-redirects.Tests/binding-redirects.Tests.csproj @@ -1,57 +1,22 @@ - + - net46 + netcoreapp1.0 true binding-redirects.Tests - win7-x64;win7-x86 + $(PackageTargetFallback);dotnet5.4;portable-net451+win8 - - true - - - true - - - true - - - - - - true - - - 4.0.0 - - - - - - 15.0.0-preview-20161024-02 - - - 2.2.0-beta4-build1194 - - - 2.2.0-beta4-build3444 - - - 1.0.1 - - - 1.0.1-beta-000933 - + + + + + - - - $(DefineConstants);RELEASE - diff --git a/test/dotnet-migrate.Tests/GivenThatAnAppWasMigrated.cs b/test/dotnet-migrate.Tests/GivenThatAnAppWasMigrated.cs index c9f5ad342..a76e765bc 100644 --- a/test/dotnet-migrate.Tests/GivenThatAnAppWasMigrated.cs +++ b/test/dotnet-migrate.Tests/GivenThatAnAppWasMigrated.cs @@ -15,11 +15,13 @@ namespace Microsoft.DotNet.Migration.Tests [InlineData("TestAppWithLibrary")] public void WhenProjectMigrationSucceedsThenProjectJsonArtifactsGetMovedToBackup(string testProjectName) { - var testRoot = TestAssetsManager - .CreateTestInstance(testProjectName) - .Path; + var testRoot = TestAssets + .GetProjectJson(testProjectName) + .CreateInstance() + .WithSourceFiles() + .Root; - var backupRoot = Path.Combine(testRoot, "backup"); + var backupRoot = testRoot.GetDirectory("backup"); var migratableArtifacts = GetProjectJsonArtifacts(testRoot); @@ -32,20 +34,22 @@ namespace Microsoft.DotNet.Migration.Tests backupArtifacts.Should().Equal(migratableArtifacts, "Because all of and only these artifacts should have been moved"); - new DirectoryInfo(testRoot).Should().NotHaveFiles(backupArtifacts.Keys); + testRoot.Should().NotHaveFiles(backupArtifacts.Keys); - new DirectoryInfo(backupRoot).Should().HaveTextFiles(backupArtifacts); + backupRoot.Should().HaveTextFiles(backupArtifacts); } [Theory] [InlineData("PJTestAppSimple")] public void WhenFolderMigrationSucceedsThenProjectJsonArtifactsGetMovedToBackup(string testProjectName) { - var testRoot = TestAssetsManager - .CreateTestInstance(testProjectName) - .Path; + var testRoot = TestAssets + .GetProjectJson(testProjectName) + .CreateInstance() + .WithSourceFiles() + .Root; - var backupRoot = Path.Combine(testRoot, "backup"); + var backupRoot = testRoot.GetDirectory("backup"); var migratableArtifacts = GetProjectJsonArtifacts(testRoot); @@ -58,20 +62,22 @@ namespace Microsoft.DotNet.Migration.Tests backupArtifacts.Should().Equal(migratableArtifacts, "Because all of and only these artifacts should have been moved"); - new DirectoryInfo(testRoot).Should().NotHaveFiles(backupArtifacts.Keys); + testRoot.Should().NotHaveFiles(backupArtifacts.Keys); - new DirectoryInfo(backupRoot).Should().HaveTextFiles(backupArtifacts); + backupRoot.Should().HaveTextFiles(backupArtifacts); } [Theory] [InlineData("TestAppWithLibraryAndMissingP2P")] public void WhenMigrationFailsThenProjectJsonArtifactsDoNotGetMovedToBackup(string testProjectName) { - var testRoot = new TestAssetsManager(Path.Combine(RepoRoot, "TestAssets", "NonRestoredTestProjects")) - .CreateTestInstance(testProjectName, identifier: testProjectName) - .Path; + var testRoot = TestAssets + .GetProjectJson(TestAssetKinds.NonRestoredTestProjects, testProjectName) + .CreateInstance(identifier: testProjectName) + .WithSourceFiles() + .Root; - var backupRoot = Path.Combine(testRoot, "backup"); + var backupRoot = testRoot.GetDirectory("backup"); var migratableArtifacts = GetProjectJsonArtifacts(testRoot); @@ -80,19 +86,23 @@ namespace Microsoft.DotNet.Migration.Tests .Execute() .Should().Fail(); - new DirectoryInfo(backupRoot).Should().NotExist("Because migration failed and therefore no backup is needed."); + backupRoot.Should().NotExist("Because migration failed and therefore no backup is needed."); - new DirectoryInfo(testRoot).Should().HaveTextFiles(migratableArtifacts, "Because migration failed so nothing was moved to backup."); + testRoot.Should().HaveTextFiles(migratableArtifacts, "Because migration failed so nothing was moved to backup."); } [Theory] [InlineData("PJTestAppSimple")] public void WhenSkipbackupSpecifiedThenProjectJsonArtifactsDoNotGetMovedToBackup(string testProjectName) { - var testRoot = TestAssetsManager.CreateTestInstance(testProjectName, identifier: testProjectName).Path; - - var backupRoot = Path.Combine(testRoot, "backup"); - + var testRoot = TestAssets + .GetProjectJson(testProjectName) + .CreateInstance(identifier: testProjectName) + .WithSourceFiles() + .Root; + + var backupRoot = testRoot.GetDirectory("backup"); + var migratableArtifacts = GetProjectJsonArtifacts(testRoot); new MigrateCommand() @@ -100,12 +110,12 @@ namespace Microsoft.DotNet.Migration.Tests .Execute("--skip-backup") .Should().Pass(); - new DirectoryInfo(backupRoot).Should().NotExist("Because --skip-backup was specified."); + backupRoot.Should().NotExist("Because --skip-backup was specified."); - new DirectoryInfo(testRoot).Should().HaveTextFiles(migratableArtifacts, "Because --skip-backup was specified."); + testRoot.Should().HaveTextFiles(migratableArtifacts, "Because --skip-backup was specified."); } - private Dictionary GetProjectJsonArtifacts(string rootPath) + private Dictionary GetProjectJsonArtifacts(DirectoryInfo root) { var catalog = new Dictionary(); @@ -113,23 +123,19 @@ namespace Microsoft.DotNet.Migration.Tests foreach (var pattern in patterns) { - AddArtifactsToCatalog(catalog, rootPath, pattern); + AddArtifactsToCatalog(catalog, root, pattern); } return catalog; } - private void AddArtifactsToCatalog(Dictionary catalog, string basePath, string pattern) + private void AddArtifactsToCatalog(Dictionary catalog, DirectoryInfo root, string pattern) { - basePath = PathUtility.EnsureTrailingSlash(basePath); - - var baseDirectory = new DirectoryInfo(basePath); - - var files = baseDirectory.GetFiles(pattern, SearchOption.AllDirectories); + var files = root.GetFiles(pattern, SearchOption.AllDirectories); foreach (var file in files) { - var key = PathUtility.GetRelativePath(basePath, file.FullName); + var key = PathUtility.GetRelativePath(root, file); catalog.Add(key, File.ReadAllText(file.FullName)); } } diff --git a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateAppsUsingGlobalJson.cs b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateAppsUsingGlobalJson.cs index dc6652124..3f7fea788 100644 --- a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateAppsUsingGlobalJson.cs +++ b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateAppsUsingGlobalJson.cs @@ -14,13 +14,17 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void ItMigratesWhenBeingPassedAFullPathToGlobalJson() { - var solutionDirectory = - TestAssetsManager.CreateTestInstance("AppWithPackageNamedAfterFolder").Path; - var globalJsonPath = Path.Combine(solutionDirectory, "global.json"); + var solutionDirectory = TestAssets + .GetProjectJson("AppWithPackageNamedAfterFolder") + .CreateInstance() + .WithSourceFiles() + .Root; + + var globalJsonPath = solutionDirectory.GetFile("global.json"); new TestCommand("dotnet") .WithForwardingToConsole() - .Execute($"migrate {globalJsonPath}") + .Execute($"migrate {globalJsonPath.FullName}") .Should() .Pass(); } @@ -28,17 +32,21 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void WhenUsingGlobalJsonItOnlyMigratesProjectsInTheGlobalJsonNode() { - var solutionDirectory = - TestAssetsManager.CreateTestInstance("AppWithPackageNamedAfterFolder").Path; - var globalJsonPath = Path.Combine(solutionDirectory, "global.json"); + var solutionDirectory = TestAssets + .GetProjectJson("AppWithPackageNamedAfterFolder") + .CreateInstance() + .WithSourceFiles() + .Root; + + var globalJsonPath = solutionDirectory.GetFile("global.json"); new TestCommand("dotnet") .WithForwardingToConsole() - .Execute($"migrate {globalJsonPath}") + .Execute($"migrate {globalJsonPath.FullName}") .Should() .Pass(); - new DirectoryInfo(solutionDirectory) + solutionDirectory .Should().HaveFiles(new [] { Path.Combine("src", "App", "App.csproj"), @@ -46,15 +54,20 @@ namespace Microsoft.DotNet.Migration.Tests Path.Combine("TestAssets", "TestAsset", "project.json") }); - new DirectoryInfo(solutionDirectory) + solutionDirectory .Should().NotHaveFile(Path.Combine("TestAssets", "TestAsset", "TestAsset.csproj")); } [Fact] public void ItMigratesWhenBeingPassedJustGlobalJson() { - var solutionDirectory = - TestAssetsManager.CreateTestInstance("AppWithPackageNamedAfterFolder").Path; + var solutionDirectory = TestAssets + .GetProjectJson("AppWithPackageNamedAfterFolder") + .CreateInstance() + .WithSourceFiles() + .Root; + + var globalJsonPath = solutionDirectory.GetFile("global.json"); new TestCommand("dotnet") .WithWorkingDirectory(solutionDirectory) diff --git a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs index 6d45d2f44..095518dae 100644 --- a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs +++ b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateSolutions.cs @@ -25,8 +25,8 @@ namespace Microsoft.DotNet.Migration.Tests string minVisualStudioVersion) { var projectDirectory = TestAssets - .Get("NonRestoredTestProjects", projectName) - .CreateInstance() + .GetProjectJson(TestAssetKinds.NonRestoredTestProjects, projectName) + .CreateInstance(identifier: projectName) .WithSourceFiles() .Root; @@ -55,7 +55,7 @@ namespace Microsoft.DotNet.Migration.Tests public void ItOnlyMigratesProjectsInTheSlnFile() { var projectDirectory = TestAssets - .Get("NonRestoredTestProjects", "PJAppWithSlnAndXprojRefs") + .GetProjectJson(TestAssetKinds.NonRestoredTestProjects, "PJAppWithSlnAndXprojRefs") .CreateInstance() .WithSourceFiles() .Root; @@ -67,7 +67,7 @@ namespace Microsoft.DotNet.Migration.Tests .Execute($"migrate \"{solutionRelPath}\"") .Should().Pass(); - new DirectoryInfo(projectDirectory.FullName) + projectDirectory .Should().HaveFiles(new [] { Path.Combine("TestApp", "TestApp.csproj"), @@ -76,7 +76,7 @@ namespace Microsoft.DotNet.Migration.Tests Path.Combine("TestApp", "TestAssets", "TestAsset", "project.json") }); - new DirectoryInfo(projectDirectory.FullName) + projectDirectory .Should().NotHaveFile(Path.Combine("TestApp", "TestAssets", "TestAsset", "TestAsset.csproj")); } @@ -100,39 +100,50 @@ namespace Microsoft.DotNet.Migration.Tests public void WhenSolutionContainsACsprojFileItGetsMovedToBackup() { var projectDirectory = TestAssets - .Get("NonRestoredTestProjects", "PJAppWithSlnAndOneAlreadyMigratedCsproj") + .GetProjectJson("NonRestoredTestProjects", "PJAppWithSlnAndOneAlreadyMigratedCsproj") .CreateInstance() .WithSourceFiles() - .Root - .FullName; + .Root; var solutionRelPath = Path.Combine("TestApp", "TestApp.sln"); + var cmd = new DotnetCommand() .WithWorkingDirectory(projectDirectory) .ExecuteWithCapturedOutput($"migrate \"{solutionRelPath}\""); + cmd.Should().Pass(); - File.Exists(Path.Combine(projectDirectory, "TestLibrary", "TestLibrary.csproj")) - .Should().BeTrue(); - File.Exists(Path.Combine(projectDirectory, "TestLibrary", "TestLibrary.csproj.migration_in_place_backup")) - .Should().BeFalse(); - File.Exists(Path.Combine(projectDirectory, "backup", "TestLibrary", "TestLibrary.csproj")) - .Should().BeTrue(); + projectDirectory + .GetDirectory("TestLibrary") + .GetFile("TestLibrary.csproj") + .Should().Exist(); + + projectDirectory + .GetDirectory("TestLibrary") + .GetFile("TestLibrary.csproj.migration_in_place_backup") + .Should().NotExist(); + + projectDirectory + .GetDirectory("backup", "TestLibrary") + .GetFile("TestLibrary.csproj") + .Should().Exist(); } [Fact] public void WhenSolutionContainsACsprojFileItDoesNotTryToAddItAgain() { var projectDirectory = TestAssets - .Get("NonRestoredTestProjects", "PJAppWithSlnAndOneAlreadyMigratedCsproj") + .GetProjectJson(TestAssetKinds.NonRestoredTestProjects, "PJAppWithSlnAndOneAlreadyMigratedCsproj") .CreateInstance() .WithSourceFiles() .Root; var solutionRelPath = Path.Combine("TestApp", "TestApp.sln"); + var cmd = new DotnetCommand() .WithWorkingDirectory(projectDirectory) .ExecuteWithCapturedOutput($"migrate \"{solutionRelPath}\""); + cmd.Should().Pass(); cmd.StdOut.Should().NotContain("already contains project"); cmd.StdErr.Should().BeEmpty(); @@ -165,6 +176,7 @@ namespace Microsoft.DotNet.Migration.Tests // .Should().Pass(); SlnFile slnFile = SlnFile.Read(Path.Combine(projectDirectory.FullName, solutionRelPath)); + var nonSolutionFolderProjects = slnFile.Projects .Where(p => p.TypeGuid != ProjectTypeGuids.SolutionFolderGuid); diff --git a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs index a80e6fd5b..c569c6cc6 100644 --- a/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs +++ b/test/dotnet-migrate.Tests/GivenThatIWantToMigrateTestApps.cs @@ -29,9 +29,12 @@ namespace Microsoft.DotNet.Migration.Tests [InlineData("TestAppWithEmbeddedResources")] public void ItMigratesApps(string projectName) { - var projectDirectory = TestAssetsManager.CreateTestInstance(projectName, identifier: projectName) - .WithLockFiles() - .Path; + var projectDirectory = TestAssets + .GetProjectJson(projectName) + .CreateInstance(identifier: projectName) + .WithSourceFiles() + .WithRestoreFiles() + .Root; CleanBinObj(projectDirectory); @@ -49,9 +52,10 @@ namespace Microsoft.DotNet.Migration.Tests VerifyAllMSBuildOutputsRunnable(projectDirectory); - var outputCsProj = Path.Combine(projectDirectory, projectName + ".csproj"); - var csproj = File.ReadAllText(outputCsProj); - csproj.EndsWith("\n").Should().Be(true); + var outputCsProj = projectDirectory.GetFile(projectName + ".csproj"); + + outputCsProj.ReadAllText() + .Should().EndWith("\n"); } [WindowsOnlyTheory] @@ -59,13 +63,16 @@ namespace Microsoft.DotNet.Migration.Tests [InlineData("TestAppWithMultipleFullFrameworksOnly", "net461")] public void ItMigratesAppsWithFullFramework(string projectName, string framework) { - var projectDirectory = TestAssetsManager.CreateTestInstance( - projectName, - identifier: projectName).WithLockFiles().Path; + var projectDirectory = TestAssets + .GetProjectJson(projectName) + .CreateInstance(identifier: projectName) + .WithSourceFiles() + .WithRestoreFiles() + .Root; CleanBinObj(projectDirectory); - MigrateProject(new [] { projectDirectory }); + MigrateProject(new [] { projectDirectory.FullName }); Restore(projectDirectory); @@ -75,7 +82,12 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void ItMigratesSignedApps() { - var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppWithSigning").WithLockFiles().Path; + var projectDirectory = TestAssets + .GetProjectJson("TestAppWithSigning") + .CreateInstance() + .WithSourceFiles() + .WithRestoreFiles() + .Root; CleanBinObj(projectDirectory); @@ -99,10 +111,11 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void ItMigratesDotnetNewConsoleWithIdenticalOutputs() { - var testInstance = TestAssetsManager - .CreateTestInstance("ProjectJsonConsoleTemplate"); - - var projectDirectory = testInstance.Path; + var projectDirectory = TestAssets + .GetProjectJson("ProjectJsonConsoleTemplate") + .CreateInstance() + .WithSourceFiles() + .Root; var outputComparisonData = GetComparisonData(projectDirectory); @@ -122,14 +135,14 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void ItMigratesOldDotnetNewWebWithoutToolsWithOutputsContainingProjectJsonOutputs() { - var testInstance = TestAssetsManager - .CreateTestInstance("ProjectJsonWebTemplate") - .WithLockFiles(); + var projectDirectory = TestAssets + .GetProjectJson("ProjectJsonWebTemplate") + .CreateInstance() + .WithSourceFiles() + .WithRestoreFiles() + .Root; - var projectDirectory = testInstance.Path; - - var globalDirectory = Path.Combine(projectDirectory, ".."); - var projectJsonFile = Path.Combine(projectDirectory, "project.json"); + var globalDirectory = projectDirectory.Parent; WriteGlobalJson(globalDirectory); @@ -149,16 +162,17 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void ItMigratesAndPublishesWebApp() { - const string projectName = "WebAppWithMissingFileInPublishOptions"; - var testInstance = TestAssets.Get(projectName) - .CreateInstance() - .WithSourceFiles(); + var projectName = "WebAppWithMissingFileInPublishOptions"; - var projectDirectory = testInstance.Root.FullName; + var projectDirectory = TestAssets + .GetProjectJson(projectName) + .CreateInstance() + .WithSourceFiles() + .Root; - File.Copy("NuGet.tempaspnetpatch.config", Path.Combine(projectDirectory, "NuGet.Config")); + File.Copy("NuGet.tempaspnetpatch.config", projectDirectory.GetFile("NuGet.Config").FullName); - MigrateProject(new [] { projectDirectory }); + MigrateProject(new [] { projectDirectory.FullName }); Restore(projectDirectory); PublishMSBuild(projectDirectory, projectName); @@ -167,13 +181,20 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void ItMigratesAPackageReferenceAsSuchEvenIfAFolderWithTheSameNameExistsInTheRepo() { - var solutionDirectory = - TestAssetsManager.CreateTestInstance("AppWithPackageNamedAfterFolder").Path; - var appProject = Path.Combine(solutionDirectory, "src", "App", "App.csproj"); + var solutionDirectory = TestAssets + .GetProjectJson("AppWithPackageNamedAfterFolder") + .CreateInstance() + .WithSourceFiles() + .Root; - MigrateProject(solutionDirectory); + var appProject = solutionDirectory + .GetDirectory("src", "App") + .GetFile("App.csproj"); + + MigrateProject(solutionDirectory.FullName); + + var projectRootElement = ProjectRootElement.Open(appProject.FullName); - var projectRootElement = ProjectRootElement.Open(appProject); projectRootElement.Items.Where( i => i.Include == "EntityFramework" && i.ItemType == "PackageReference") .Should().HaveCount(2); @@ -184,38 +205,47 @@ namespace Microsoft.DotNet.Migration.Tests const string dependentProject = "ProjectA"; const string dependencyProject = "ProjectB"; - var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph").Path; + var projectDirectory = TestAssets + .GetProjectJson("TestAppDependencyGraph") + .CreateInstance() + .WithSourceFiles() + .Root; - MigrateProject(Path.Combine(projectDirectory, dependencyProject)); + MigrateProject(projectDirectory.GetDirectory(dependencyProject).FullName); - MigrateProject("--skip-project-references", Path.Combine(projectDirectory, dependentProject)); + MigrateProject("--skip-project-references", projectDirectory.GetDirectory(dependentProject).FullName); } [Fact] public void ItAddsMicrosoftNetWebSdkToTheSdkAttributeOfAWebApp() { - var testInstance = TestAssetsManager - .CreateTestInstance("ProjectJsonWebTemplate") - .WithLockFiles(); + var projectDirectory = TestAssets + .Get("ProjectJsonWebTemplate") + .CreateInstance() + .WithSourceFiles() + .WithRestoreFiles() + .Root; - var projectDirectory = testInstance.Path; - - var globalDirectory = Path.Combine(projectDirectory, ".."); - var projectJsonFile = Path.Combine(projectDirectory, "project.json"); + var globalDirectory = projectDirectory.Parent; + var projectJsonFile = projectDirectory.GetFile("project.json"); - MigrateProject(new [] { projectDirectory }); + MigrateProject(new [] { projectDirectory.FullName }); - var csProj = Path.Combine(projectDirectory, $"{new DirectoryInfo(projectDirectory).Name}.csproj"); + var csProj = projectDirectory.GetFile($"{projectDirectory.Name}.csproj"); - File.ReadAllText(csProj).Should().Contain(@"Sdk=""Microsoft.NET.Sdk.Web"""); + csProj.ReadAllText().Should().Contain(@"Sdk=""Microsoft.NET.Sdk.Web"""); } [Theory] [InlineData("TestLibraryWithTwoFrameworks")] public void ItMigratesProjectsWithMultipleTFMs(string projectName) { - var projectDirectory = - TestAssetsManager.CreateTestInstance(projectName, identifier: projectName).WithLockFiles().Path; + var projectDirectory = TestAssets + .GetProjectJson(projectName) + .CreateInstance(identifier: projectName) + .WithSourceFiles() + .WithRestoreFiles() + .Root; var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, projectName); @@ -234,8 +264,13 @@ namespace Microsoft.DotNet.Migration.Tests public void ItMigratesLibraryWithMultipleTFMsAndFullFramework() { var projectName = "PJLibWithMultipleFrameworks"; - var projectDirectory = - TestAssetsManager.CreateTestInstance(projectName, identifier: projectName).WithLockFiles().Path; + + var projectDirectory = TestAssets + .GetProjectJson(projectName) + .CreateInstance(identifier: projectName) + .WithSourceFiles() + .WithRestoreFiles() + .Root; var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, projectName); @@ -256,13 +291,20 @@ namespace Microsoft.DotNet.Migration.Tests [InlineData("PJTestLibraryWithConfiguration")] public void ItMigratesALibrary(string projectName) { - var projectDirectory = - TestAssetsManager.CreateTestInstance(projectName, identifier: projectName).WithLockFiles().Path; + var projectDirectory = TestAssets + .GetProjectJson(projectName) + .CreateInstance(identifier: projectName) + .WithSourceFiles() + .WithRestoreFiles() + .Root; - var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, Path.GetFileNameWithoutExtension(projectName)); + var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild( + projectDirectory, + Path.GetFileNameWithoutExtension(projectName)); - var outputsIdentical = - outputComparisonData.ProjectJsonBuildOutputs.SetEquals(outputComparisonData.MSBuildBuildOutputs); + var outputsIdentical = outputComparisonData + .ProjectJsonBuildOutputs + .SetEquals(outputComparisonData.MSBuildBuildOutputs); if (!outputsIdentical) { @@ -280,12 +322,13 @@ namespace Microsoft.DotNet.Migration.Tests [InlineData("ProjectE", "ProjectE")] public void ItMigratesRootProjectAndReferences(string projectName, string expectedProjects) { - var projectDirectory = - TestAssetsManager.CreateTestInstance( - "TestAppDependencyGraph", - identifier: $"{projectName}.RefsTest").Path; + var projectDirectory = TestAssets + .GetProjectJson("TestAppDependencyGraph") + .CreateInstance(identifier: $"{projectName}.RefsTest") + .WithSourceFiles() + .Root; - MigrateProject(new [] { Path.Combine(projectDirectory, projectName) }); + MigrateProject(new [] { projectDirectory.GetDirectory(projectName).FullName }); string[] migratedProjects = expectedProjects.Split(new char[] { ',' }); @@ -300,10 +343,13 @@ namespace Microsoft.DotNet.Migration.Tests [InlineData("ProjectE")] public void ItMigratesRootProjectAndSkipsReferences(string projectName) { - var projectDirectory = - TestAssetsManager.CreateTestInstance("TestAppDependencyGraph", identifier: $"{projectName}.SkipRefsTest").Path; - - MigrateProject(new [] { Path.Combine(projectDirectory, projectName), "--skip-project-references" }); + var projectDirectory = TestAssets + .GetProjectJson("TestAppDependencyGraph") + .CreateInstance($"{projectName}.SkipRefsTest") + .WithSourceFiles() + .Root; + + MigrateProject(new [] { projectDirectory.GetDirectory(projectName).FullName, "--skip-project-references" }); VerifyMigration(Enumerable.Repeat(projectName, 1), projectDirectory); } @@ -313,15 +359,19 @@ namespace Microsoft.DotNet.Migration.Tests [InlineData(false)] public void ItMigratesAllProjectsInGivenDirectory(bool skipRefs) { - var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph", callingMethod: $"MigrateDirectory.SkipRefs.{skipRefs}").Path; + var projectDirectory = TestAssets + .GetProjectJson("TestAppDependencyGraph") + .CreateInstance(callingMethod: $"MigrateDirectory.SkipRefs.{skipRefs}") + .WithSourceFiles() + .Root; if (skipRefs) { - MigrateProject(new [] { projectDirectory, "--skip-project-references" }); + MigrateProject(new [] { projectDirectory.FullName, "--skip-project-references" }); } else { - MigrateProject(new [] { projectDirectory }); + MigrateProject(new [] { projectDirectory.FullName }); } string[] migratedProjects = new string[] { "ProjectA", "ProjectB", "ProjectC", "ProjectD", "ProjectE", "ProjectF", "ProjectG", "ProjectH", "ProjectI", "ProjectJ" }; @@ -332,11 +382,17 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void ItMigratesGivenProjectJson() { - var projectDirectory = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph").Path; + var projectDirectory = TestAssets + .GetProjectJson("TestAppDependencyGraph") + .CreateInstance() + .WithSourceFiles() + .Root; - var project = Path.Combine(projectDirectory, "ProjectA", "project.json"); + var project = projectDirectory + .GetDirectory("ProjectA") + .GetFile("project.json"); - MigrateProject(new [] { project }); + MigrateProject(new [] { project.FullName }); string[] migratedProjects = new string[] { "ProjectA", "ProjectB", "ProjectC", "ProjectD", "ProjectE" }; @@ -347,17 +403,22 @@ namespace Microsoft.DotNet.Migration.Tests // regression test for https://github.com/dotnet/cli/issues/4269 public void ItMigratesAndBuildsP2PReferences() { - var assetsDir = TestAssetsManager.CreateTestInstance("TestAppDependencyGraph").WithLockFiles().Path; + var assetsDir = TestAssets + .GetProjectJson("TestAppDependencyGraph") + .CreateInstance() + .WithSourceFiles() + .WithRestoreFiles() + .Root; - var projectDirectory = Path.Combine(assetsDir, "ProjectF"); + var projectDirectory = assetsDir.GetDirectory("ProjectF"); - var restoreDirectories = new string[] + var restoreDirectories = new DirectoryInfo[] { projectDirectory, - Path.Combine(assetsDir, "ProjectG") + assetsDir.GetDirectory("ProjectG") }; - var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, "ProjectF", new [] { projectDirectory }, restoreDirectories); + var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, "ProjectF", new [] { projectDirectory.FullName }, restoreDirectories); var outputsIdentical = outputComparisonData.ProjectJsonBuildOutputs .SetEquals(outputComparisonData.MSBuildBuildOutputs); @@ -373,27 +434,33 @@ namespace Microsoft.DotNet.Migration.Tests } [Theory] - [InlineData("src", "ProjectH")] - [InlineData("src with spaces", "ProjectJ")] - public void ItMigratesAndBuildsProjectsInGlobalJson(string path, string projectName) + [InlineData("src", "H")] + [InlineData("src with spaces", "J")] + public void ItMigratesAndBuildsProjectsInGlobalJson(string path, string projectNameSuffix) { - var assetsDir = TestAssetsManager.CreateTestInstance(Path.Combine("TestAppDependencyGraph", "ProjectsWithGlobalJson"), - callingMethod: $"ProjectsWithGlobalJson.{projectName}") - .WithLockFiles().Path; - var globalJson = Path.Combine(assetsDir, "global.json"); + var assetsDir = TestAssets + .GetProjectJson("ProjectsWithGlobalJson") + .CreateInstance(identifier: projectNameSuffix) + .WithSourceFiles() + .WithRestoreFiles() + .Root; - var restoreDirectories = new string[] + var projectName = $"Project{projectNameSuffix}"; + + var globalJson = assetsDir.GetFile("global.json"); + + var restoreDirectories = new DirectoryInfo[] { - Path.Combine(assetsDir, "src", "ProjectH"), - Path.Combine(assetsDir, "src", "ProjectI"), - Path.Combine(assetsDir, "src with spaces", "ProjectJ") + assetsDir.GetDirectory("src", "ProjectH"), + assetsDir.GetDirectory("src", "ProjectI"), + assetsDir.GetDirectory("src with spaces", "ProjectJ") }; - var projectDirectory = Path.Combine(assetsDir, path, projectName); + var projectDirectory = assetsDir.GetDirectory(path, projectName); var outputComparisonData = BuildProjectJsonMigrateBuildMSBuild(projectDirectory, projectName, - new [] { globalJson }, + new [] { globalJson.FullName }, restoreDirectories); var outputsIdentical = outputComparisonData.ProjectJsonBuildOutputs @@ -414,7 +481,7 @@ namespace Microsoft.DotNet.Migration.Tests [InlineData(false)] public void MigrationOutputsErrorWhenNoProjectsFound(bool useGlobalJson) { - var projectDirectory = TestAssetsManager.CreateTestDirectory("Migration_outputs_error_when_no_projects_found"); + var projectDirectory = TestAssets.CreateTestDirectory("Migration_outputs_error_when_no_projects_found"); string argstr = string.Empty; @@ -422,31 +489,28 @@ namespace Microsoft.DotNet.Migration.Tests if (useGlobalJson) { - var globalJsonPath = Path.Combine(projectDirectory.Path, "global.json"); + var globalJson = projectDirectory.GetFile("global.json"); - using (FileStream fs = File.Create(globalJsonPath)) + using (StreamWriter sw = globalJson.CreateText()) { - using (StreamWriter sw = new StreamWriter(fs)) - { - sw.WriteLine("{"); - sw.WriteLine("\"projects\": [ \".\" ]"); - sw.WriteLine("}"); - } + sw.WriteLine("{"); + sw.WriteLine("\"projects\": [ \".\" ]"); + sw.WriteLine("}"); } - argstr = globalJsonPath; + argstr = globalJson.FullName; errorMessage = "Unable to find any projects in global.json"; } else { - argstr = projectDirectory.Path; + argstr = projectDirectory.FullName; - errorMessage = $"No project.json file found in '{projectDirectory.Path}'"; + errorMessage = $"No project.json file found in '{projectDirectory.FullName}'"; } var result = new TestCommand("dotnet") - .WithWorkingDirectory(projectDirectory.Path) + .WithWorkingDirectory(projectDirectory) .ExecuteWithCapturedOutput($"migrate {argstr}"); // Expecting an error exit code. @@ -454,18 +518,21 @@ namespace Microsoft.DotNet.Migration.Tests // Verify the error messages. Note that debug builds also show the call stack, so we search // for the error strings that should be present (rather than an exact match). - result.StdErr.Should().Contain(errorMessage); - result.StdErr.Should().Contain("Migration failed."); + result.StdErr + .Should().Contain(errorMessage) + .And.Contain("Migration failed."); } [Fact] public void ItMigratesAndPublishesProjectsWithRuntimes() { var projectName = "PJTestAppSimple"; - var projectDirectory = TestAssetsManager - .CreateTestInstance(projectName) - .WithLockFiles() - .Path; + var projectDirectory = TestAssets + .GetProjectJson(projectName) + .CreateInstance() + .WithSourceFiles() + .WithRestoreFiles() + .Root; CleanBinObj(projectDirectory); BuildProjectJsonMigrateBuildMSBuild(projectDirectory, projectName); @@ -478,11 +545,16 @@ namespace Microsoft.DotNet.Migration.Tests public void ItAutoAddDesktopReferencesDuringMigrate(string testGroup, string projectName, bool isDesktopApp) { var runtime = DotnetLegacyRuntimeIdentifiers.InferLegacyRestoreRuntimeIdentifier(); - var testAssetManager = GetTestGroupTestAssetsManager(testGroup); - var projectDirectory = testAssetManager.CreateTestInstance(projectName).WithLockFiles().Path; - + + var projectDirectory = TestAssets + .GetProjectJson(testGroup, projectName) + .CreateInstance() + .WithSourceFiles() + .WithRestoreFiles() + .Root; + CleanBinObj(projectDirectory); - MigrateProject(new string[] { projectDirectory }); + MigrateProject(new string[] { projectDirectory.FullName }); Restore(projectDirectory, runtime: runtime); BuildMSBuild(projectDirectory, projectName, runtime:runtime); VerifyAutoInjectedDesktopReferences(projectDirectory, projectName, isDesktopApp); @@ -493,12 +565,19 @@ namespace Microsoft.DotNet.Migration.Tests public void ItBuildsAMigratedAppWithAnIndirectDependency() { const string projectName = "ProjectA"; - var solutionDirectory = - TestAssetsManager.CreateTestInstance("TestAppDependencyGraph").Path; - var projectDirectory = Path.Combine(solutionDirectory, projectName); - MigrateProject(new string[] { projectDirectory }); + var solutionDirectory = TestAssets + .GetProjectJson("TestAppDependencyGraph") + .CreateInstance() + .WithSourceFiles() + .Root; + + var projectDirectory = solutionDirectory.GetDirectory(projectName); + + MigrateProject(new string[] { projectDirectory.FullName }); + Restore(projectDirectory); + BuildMSBuild(projectDirectory, projectName); VerifyAllMSBuildOutputsRunnable(projectDirectory); @@ -507,35 +586,42 @@ namespace Microsoft.DotNet.Migration.Tests [Fact] public void ItMigratesProjectWithOutputName() { - string projectName = "AppWithOutputAssemblyName"; - string expectedOutputName = "MyApp"; + var projectName = "AppWithOutputAssemblyName"; + var expectedOutputName = "MyApp"; - var projectDirectory = TestAssetsManager.CreateTestInstance(projectName, callingMethod: $"It_migrates_{projectName}") - .WithLockFiles() - .Path; - - string expectedCsprojPath = Path.Combine(projectDirectory, $"{projectName}.csproj"); - if (File.Exists(expectedCsprojPath)) + var projectDirectory = TestAssets + .GetProjectJson(projectName) + .CreateInstance() + .WithSourceFiles() + .WithRestoreFiles() + .Root; + + var expectedCsprojPath = projectDirectory.GetFile($"{projectName}.csproj"); + + if (expectedCsprojPath.Exists) { - File.Delete(expectedCsprojPath); + expectedCsprojPath.Delete(); } CleanBinObj(projectDirectory); - MigrateProject(projectDirectory); - File.Exists(expectedCsprojPath).Should().BeTrue(); + MigrateProject(projectDirectory.FullName); + + expectedCsprojPath.Refresh(); + + expectedCsprojPath.Should().Exist(); + Restore(projectDirectory, projectName); BuildMSBuild(projectDirectory, projectName); - Directory.EnumerateFiles( - Path.Combine(projectDirectory, "bin"), - $"{expectedOutputName}.pdb", - SearchOption.AllDirectories) + projectDirectory + .GetDirectory("bin") + .EnumerateFiles($"{expectedOutputName}.pdb", SearchOption.AllDirectories) .Count().Should().Be(1); PackMSBuild(projectDirectory, projectName); - Directory.EnumerateFiles( - Path.Combine(projectDirectory, "bin"), - $"{projectName}.1.0.0.nupkg", - SearchOption.AllDirectories) + + projectDirectory + .GetDirectory("bin") + .EnumerateFiles($"{projectName}.1.0.0.nupkg", SearchOption.AllDirectories) .Count().Should().Be(1); } @@ -544,24 +630,31 @@ namespace Microsoft.DotNet.Migration.Tests [InlineData("LibraryWithNetStandardLibRef")] public void ItMigratesAndBuildsLibrary(string projectName) { - var projectDirectory = TestAssetsManager.CreateTestInstance( - projectName, - identifier: $"{projectName}").Path; + var projectDirectory = TestAssets + .GetProjectJson(projectName) + .CreateInstance(identifier: projectName) + .WithSourceFiles() + .Root; - MigrateProject(projectDirectory); + MigrateProject(projectDirectory.FullName); Restore(projectDirectory, projectName); BuildMSBuild(projectDirectory, projectName); } - private void VerifyAutoInjectedDesktopReferences(string projectDirectory, string projectName, bool shouldBePresent) + private void VerifyAutoInjectedDesktopReferences(DirectoryInfo projectDirectory, string projectName, bool shouldBePresent) { if (projectName != null) { projectName = projectName + ".csproj"; } - var root = ProjectRootElement.Open(Path.Combine(projectDirectory, projectName)); - var autoInjectedReferences = root.Items.Where(i => i.ItemType == "Reference" && (i.Include == "System" || i.Include == "Microsoft.CSharp")); + var root = ProjectRootElement.Open(projectDirectory.GetFile(projectName).FullName); + + var autoInjectedReferences = root + .Items + .Where(i => i.ItemType == "Reference" + && (i.Include == "System" || i.Include == "Microsoft.CSharp")); + if (shouldBePresent) { autoInjectedReferences.Should().HaveCount(2); @@ -572,54 +665,56 @@ namespace Microsoft.DotNet.Migration.Tests } } - private void VerifyMigration(IEnumerable expectedProjects, string rootDir) + private void VerifyMigration(IEnumerable expectedProjects, DirectoryInfo rootDir) { - var backupDir = Path.Combine(rootDir, "backup"); + var backupDir = rootDir.GetDirectory("backup"); - var migratedProjects = Directory.EnumerateFiles(rootDir, "*.csproj", SearchOption.AllDirectories) - .Where(s => !PathUtility.IsChildOfDirectory(backupDir, s)) - .Where(s => Directory.EnumerateFiles(Path.GetDirectoryName(s), "*.csproj").Count() == 1) - .Where(s => Path.GetFileName(Path.GetDirectoryName(s)).Contains("Project")) - .Select(s => Path.GetFileName(Path.GetDirectoryName(s))); + var migratedProjects = rootDir.EnumerateFiles("*.csproj", SearchOption.AllDirectories) + .Where(s => !PathUtility.IsChildOfDirectory(backupDir.FullName, s.FullName)) + .Where(s => Directory.EnumerateFiles(Path.GetDirectoryName(s.FullName), "*.csproj").Count() == 1) + .Where(s => Path.GetFileName(Path.GetDirectoryName(s.FullName)).Contains("Project")) + .Select(s => Path.GetFileName(Path.GetDirectoryName(s.FullName))); migratedProjects.Should().BeEquivalentTo(expectedProjects); } - private MigratedBuildComparisonData GetComparisonData(string projectDirectory) + private MigratedBuildComparisonData GetComparisonData(DirectoryInfo projectDirectory) { - File.Copy("NuGet.tempaspnetpatch.config", Path.Combine(projectDirectory, "NuGet.Config")); + File.Copy("NuGet.tempaspnetpatch.config", projectDirectory.GetFile("NuGet.Config").FullName); RestoreProjectJson(projectDirectory); var outputComparisonData = - BuildProjectJsonMigrateBuildMSBuild(projectDirectory, Path.GetFileNameWithoutExtension(projectDirectory)); + BuildProjectJsonMigrateBuildMSBuild(projectDirectory, Path.GetFileNameWithoutExtension(projectDirectory.FullName)); return outputComparisonData; } - private void VerifyAllMSBuildOutputsRunnable(string projectDirectory) + private void VerifyAllMSBuildOutputsRunnable(DirectoryInfo projectDirectory) { - var dllFileName = Path.GetFileName(projectDirectory) + ".dll"; + var dllFileName = Path.GetFileName(projectDirectory.FullName) + ".dll"; - var runnableDlls = Directory.EnumerateFiles(Path.Combine(projectDirectory, "bin"), dllFileName, - SearchOption.AllDirectories); + var runnableDlls = projectDirectory + .GetDirectory("bin") + .GetFiles(dllFileName, SearchOption.AllDirectories); foreach (var dll in runnableDlls) { - new TestCommand("dotnet").ExecuteWithCapturedOutput($"\"{dll}\"").Should().Pass(); + new TestCommand("dotnet").ExecuteWithCapturedOutput($"\"{dll.FullName}\"").Should().Pass(); } } - private void VerifyAllMSBuildOutputsAreSigned(string projectDirectory) + private void VerifyAllMSBuildOutputsAreSigned(DirectoryInfo projectDirectory) { - var dllFileName = Path.GetFileName(projectDirectory) + ".dll"; + var dllFileName = Path.GetFileName(projectDirectory.FullName) + ".dll"; - var runnableDlls = Directory.EnumerateFiles(Path.Combine(projectDirectory, "bin"), dllFileName, - SearchOption.AllDirectories); + var runnableDlls = projectDirectory + .GetDirectory("bin") + .EnumerateFiles(dllFileName, SearchOption.AllDirectories); foreach (var dll in runnableDlls) { - var assemblyName = AssemblyLoadContext.GetAssemblyName(dll); + var assemblyName = AssemblyLoadContext.GetAssemblyName(dll.FullName); var token = assemblyName.GetPublicKeyToken(); @@ -627,30 +722,30 @@ namespace Microsoft.DotNet.Migration.Tests } } - private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(string projectDirectory, + private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(DirectoryInfo projectDirectory, string projectName) { return BuildProjectJsonMigrateBuildMSBuild(projectDirectory, projectName, - new [] { projectDirectory }, + new [] { projectDirectory.FullName }, new [] { projectDirectory }); } - private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(string projectDirectory, + private MigratedBuildComparisonData BuildProjectJsonMigrateBuildMSBuild(DirectoryInfo projectDirectory, string projectName, string[] migrateArgs, - string[] restoreDirectories) + DirectoryInfo[] restoreDirectories) { BuildProjectJson(projectDirectory); - var projectJsonBuildOutputs = new HashSet(CollectBuildOutputs(projectDirectory)); + var projectJsonBuildOutputs = new HashSet(CollectBuildOutputs(projectDirectory.FullName)); CleanBinObj(projectDirectory); // Remove lock file for migration foreach(var dir in restoreDirectories) { - File.Delete(Path.Combine(dir, "project.lock.json")); + dir.GetFile("project.lock.json").Delete(); } MigrateProject(migrateArgs); @@ -664,7 +759,7 @@ namespace Microsoft.DotNet.Migration.Tests BuildMSBuild(projectDirectory, projectName); - var msbuildBuildOutputs = new HashSet(CollectBuildOutputs(projectDirectory)); + var msbuildBuildOutputs = new HashSet(CollectBuildOutputs(projectDirectory.FullName)); return new MigratedBuildComparisonData(projectJsonBuildOutputs, msbuildBuildOutputs); } @@ -677,41 +772,24 @@ namespace Microsoft.DotNet.Migration.Tests .Select(p => Path.GetFullPath(p).Substring(fullBinPath.Length)); } - private static void DeleteDirectory(string dir) + private void CleanBinObj(DirectoryInfo projectDirectory) { - foreach (string directory in Directory.EnumerateDirectories(dir)) - { - DeleteDirectory(directory); - } - - try - { - Directory.Delete(dir, true); - } - catch - { - // retry, if still doesn't delete then throw - Directory.Delete(dir, true); - } - } - - private void CleanBinObj(string projectDirectory) - { - var dirs = new string[] { Path.Combine(projectDirectory, "bin"), Path.Combine(projectDirectory, "obj") }; + var dirs = new DirectoryInfo[] { projectDirectory.GetDirectory("bin"), projectDirectory.GetDirectory("obj") }; foreach (var dir in dirs) { - if(Directory.Exists(dir)) + if(dir.Exists) { - DeleteDirectory(dir); + dir.Delete(true); } } } - private void BuildProjectJson(string projectDirectory) + private void BuildProjectJson(DirectoryInfo projectDirectory) { Console.WriteLine(projectDirectory); - var projectFile = "\"" + Path.Combine(projectDirectory, "project.json") + "\""; + + var projectFile = $"\"{projectDirectory.GetFile("project.json").FullName}\""; var result = new BuildPJCommand() .WithCapturedOutput() @@ -730,15 +808,15 @@ namespace Microsoft.DotNet.Migration.Tests .Pass(); } - private void RestoreProjectJson(string projectDirectory) + private void RestoreProjectJson(DirectoryInfo projectDirectory) { - var projectFile = "\"" + Path.Combine(projectDirectory, "project.json") + "\""; + var projectFile = $"\"{projectDirectory.GetFile("project.json").FullName}\""; new RestoreProjectJsonCommand() .Execute(projectFile) .Should().Pass(); } - private void Restore(string projectDirectory, string projectName=null, string runtime=null) + private void Restore(DirectoryInfo projectDirectory, string projectName=null, string runtime=null) { var command = new RestoreCommand() .WithWorkingDirectory(projectDirectory) @@ -761,7 +839,7 @@ namespace Microsoft.DotNet.Migration.Tests } private string BuildMSBuild( - string projectDirectory, + DirectoryInfo projectDirectory, string projectName, string configuration="Debug", string runtime=null, @@ -787,7 +865,7 @@ namespace Microsoft.DotNet.Migration.Tests } private string PublishMSBuild( - string projectDirectory, + DirectoryInfo projectDirectory, string projectName, string runtime = null, string configuration = "Debug") @@ -809,7 +887,7 @@ namespace Microsoft.DotNet.Migration.Tests return result.StdOut; } - private string PackMSBuild(string projectDirectory, string projectName) + private string PackMSBuild(DirectoryInfo projectDirectory, string projectName) { if (projectName != null && !Path.HasExtension(projectName)) { @@ -825,13 +903,13 @@ namespace Microsoft.DotNet.Migration.Tests return result.StdOut; } - private void DeleteXproj(string projectDirectory) + private void DeleteXproj(DirectoryInfo projectDirectory) { - var xprojFiles = Directory.EnumerateFiles(projectDirectory, "*.xproj"); + var xprojFiles = projectDirectory.EnumerateFiles("*.xproj"); foreach (var xprojFile in xprojFiles) { - File.Delete(xprojFile); + xprojFile.Delete(); } } @@ -868,10 +946,11 @@ namespace Microsoft.DotNet.Migration.Tests } } - private void WriteGlobalJson(string globalDirectory) + private void WriteGlobalJson(DirectoryInfo globalDirectory) { - var file = Path.Combine(globalDirectory, "global.json"); - File.WriteAllText(file, @" + var file = globalDirectory.GetFile("global.json"); + + File.WriteAllText(file.FullName, @" { ""projects"": [ ] }"); diff --git a/test/dotnet.Tests/¬/.dotnet/optimizationdata/1.0.0-rc4-004536/osx.10.11-x64/dotnet b/test/dotnet.Tests/¬/.dotnet/optimizationdata/1.0.0-rc4-004536/osx.10.11-x64/dotnet new file mode 100644 index 0000000000000000000000000000000000000000..30393cb6d3d0ac546f8ec8c1021af9d891103b72 GIT binary patch literal 64 PcmZ=@U|>vTARhn#C@BD^ literal 0 HcmV?d00001