diff --git a/Microsoft.DotNet.Cli.sln b/Microsoft.DotNet.Cli.sln index 7840b9296..bcc98ea83 100644 --- a/Microsoft.DotNet.Cli.sln +++ b/Microsoft.DotNet.Cli.sln @@ -172,6 +172,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "dotnet-msbuild.Tests", "tes EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "dotnet-publish3.Tests", "test\dotnet-publish3.Tests\dotnet-publish3.Tests.xproj", "{FBE4F1D6-BA4C-46D9-8286-4EE4B032D01E}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "dotnet-test3.Tests", "test\dotnet-test3.Tests\dotnet-test3.Tests.xproj", "{90236A80-4B84-41D3-A161-AA20709776B1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1000,6 +1002,22 @@ Global {FBE4F1D6-BA4C-46D9-8286-4EE4B032D01E}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU {FBE4F1D6-BA4C-46D9-8286-4EE4B032D01E}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU {FBE4F1D6-BA4C-46D9-8286-4EE4B032D01E}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {90236A80-4B84-41D3-A161-AA20709776B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {90236A80-4B84-41D3-A161-AA20709776B1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {90236A80-4B84-41D3-A161-AA20709776B1}.Debug|x64.ActiveCfg = Debug|Any CPU + {90236A80-4B84-41D3-A161-AA20709776B1}.Debug|x64.Build.0 = Debug|Any CPU + {90236A80-4B84-41D3-A161-AA20709776B1}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {90236A80-4B84-41D3-A161-AA20709776B1}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {90236A80-4B84-41D3-A161-AA20709776B1}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {90236A80-4B84-41D3-A161-AA20709776B1}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {90236A80-4B84-41D3-A161-AA20709776B1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {90236A80-4B84-41D3-A161-AA20709776B1}.Release|Any CPU.Build.0 = Release|Any CPU + {90236A80-4B84-41D3-A161-AA20709776B1}.Release|x64.ActiveCfg = Release|Any CPU + {90236A80-4B84-41D3-A161-AA20709776B1}.Release|x64.Build.0 = Release|Any CPU + {90236A80-4B84-41D3-A161-AA20709776B1}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {90236A80-4B84-41D3-A161-AA20709776B1}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {90236A80-4B84-41D3-A161-AA20709776B1}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {90236A80-4B84-41D3-A161-AA20709776B1}.RelWithDebInfo|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1064,5 +1082,6 @@ Global {9F5AE280-A040-4160-9799-6504D907742D} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} {2FFCBDF0-BA36-4393-8DDB-1AE04AEA3CD6} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} {FBE4F1D6-BA4C-46D9-8286-4EE4B032D01E} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} + {90236A80-4B84-41D3-A161-AA20709776B1} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} EndGlobalSection EndGlobal diff --git a/TestAssets/TestProjects/VSTestDotNetCoreProject/Tests.cs b/TestAssets/TestProjects/VSTestDotNetCoreProject/Tests.cs index 06cf2371b..afb3b28a2 100644 --- a/TestAssets/TestProjects/VSTestDotNetCoreProject/Tests.cs +++ b/TestAssets/TestProjects/VSTestDotNetCoreProject/Tests.cs @@ -2,6 +2,14 @@ namespace TestNamespace { + public class Program + { + public static void Main(string[] args) + { + + } + } + [TestClass] public class VSTestTests { @@ -9,11 +17,11 @@ namespace TestNamespace public void VSTestPassTest() { } - - [TestMethod] + + [TestMethod] public void VSTestFailTest() { - Assert.Fail(); + Assert.Fail(); } } } \ No newline at end of file diff --git a/TestAssets/TestProjects/VSTestDotNetCoreProject/VSTestDotNetCoreProject.csproj b/TestAssets/TestProjects/VSTestDotNetCoreProject/VSTestDotNetCoreProject.csproj index 0e6ff1a91..cff28dab7 100644 --- a/TestAssets/TestProjects/VSTestDotNetCoreProject/VSTestDotNetCoreProject.csproj +++ b/TestAssets/TestProjects/VSTestDotNetCoreProject/VSTestDotNetCoreProject.csproj @@ -3,14 +3,13 @@ - Library + Exe netcoreapp1.0 bin\$(Configuration) - @@ -21,20 +20,15 @@ 1.0.0-alpha-20161010-1 All - - 1.0.3-preview - - + 1.0.4-preview + + + 1.1.3-preview + + + 15.0.0-preview-20161005-01 - - - - - - - - \ No newline at end of file diff --git a/resources/MSBuildImports/15.0/Microsoft.Common.targets/ImportAfter/Microsoft.TestPlatform.ImportAfter.targets b/resources/MSBuildImports/15.0/Microsoft.Common.targets/ImportAfter/Microsoft.TestPlatform.ImportAfter.targets new file mode 100644 index 000000000..97f203482 --- /dev/null +++ b/resources/MSBuildImports/15.0/Microsoft.Common.targets/ImportAfter/Microsoft.TestPlatform.ImportAfter.targets @@ -0,0 +1,19 @@ + + + + + + $(MSBuildExtensionsPath)\Microsoft.TestPlatform.targets + + + diff --git a/src/dotnet/Program.cs b/src/dotnet/Program.cs index 7a8d64ac5..27582cea7 100644 --- a/src/dotnet/Program.cs +++ b/src/dotnet/Program.cs @@ -29,6 +29,7 @@ using Microsoft.DotNet.Tools.Restore3; using Microsoft.DotNet.Tools.Run; using Microsoft.DotNet.Tools.Test; using Microsoft.DotNet.Tools.VSTest; +using Microsoft.DotNet.Tools.Test3; using NuGet.Frameworks; namespace Microsoft.DotNet.Cli @@ -54,6 +55,7 @@ namespace Microsoft.DotNet.Cli ["restore3"] = Restore3Command.Run, ["publish3"] = Publish3Command.Run, ["vstest"] = VSTestCommand.Run, + ["test3"] = Test3Command.Run, ["pack3"] = Pack3Command.Run, ["migrate"] = MigrateCommand.Run, ["projectmodel-server"] = ProjectModelServerCommand.Run, diff --git a/src/dotnet/commands/dotnet-test3/Program.cs b/src/dotnet/commands/dotnet-test3/Program.cs new file mode 100644 index 000000000..fe76e9e73 --- /dev/null +++ b/src/dotnet/commands/dotnet-test3/Program.cs @@ -0,0 +1,229 @@ +// 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 Microsoft.DotNet.Cli.CommandLine; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.Tools.MSBuild; +using System.IO; +using System.Text.RegularExpressions; + +namespace Microsoft.DotNet.Tools.Test3 +{ + public class Test3Command + { + public static int Run(string[] args) + { + DebugHelper.HandleDebugSwitch(ref args); + + var cmd = new CommandLineApplication(throwOnUnexpectedArg: false) + { + Name = "dotnet test3", + FullName = ".NET Test Driver", + Description = "Test Driver for the .NET Platform" + }; + + cmd.HelpOption("-h|--help"); + + var argRoot = cmd.Argument( + "", + "The project to test, defaults to the current directory.", + multipleValues: false); + + var settingOption = cmd.Option( + "-s|--settings ", + "Settings to use when running tests.", + CommandOptionType.SingleValue); + + var listTestsOption = cmd.Option( + "-lt|--listTests", + @"Lists discovered tests", + CommandOptionType.NoValue); + + var testCaseFilterOption = cmd.Option( + "-tcf|--testCaseFilter ", + @"Run tests that match the given expression. + Examples: + --testCaseFilter:""Priority = 1"" + --testCaseFilter: ""(FullyQualifiedName~Nightly | Name = MyTestMethod)""", + CommandOptionType.SingleValue); + + var testAdapterPathOption = cmd.Option( + "-tap|--testAdapterPath", + @"Use custom adapters from the given path in the test run. + Example: --testAdapterPath:", + CommandOptionType.SingleValue); + + var loggerOption = cmd.Option( + "-l|--logger ", + @"Specify a logger for test results. + Example: --logger:trx", + CommandOptionType.SingleValue); + + var configurationOption = cmd.Option( + "-c|--Configuration ", + @"Configuration under which to build, i.e. Debug/Release", + CommandOptionType.SingleValue); + + var frameworkOption = cmd.Option( + "-f|--framework ", + @"Looks for test binaries for a specific framework", + CommandOptionType.SingleValue); + + var outputOption = cmd.Option( + "-o|--output ", + @"Directory in which to find the binaries to be run", + CommandOptionType.SingleValue); + + var noBuildtOption = cmd.Option( + "--noBuild", + @"Do not build project before testing.", + CommandOptionType.NoValue); + + cmd.OnExecute(() => + { + var msbuildArgs = new List() + { + "/t:VSTest" + }; + + msbuildArgs.Add("/verbosity:quiet"); + msbuildArgs.Add("/nologo"); + + if (settingOption.HasValue()) + { + msbuildArgs.Add($"/p:VSTestSetting={settingOption.Value()}"); + } + + if (listTestsOption.HasValue()) + { + msbuildArgs.Add($"/p:VSTestListTests=true"); + } + + if (testCaseFilterOption.HasValue()) + { + msbuildArgs.Add($"/p:VSTestTestCaseFilter={testCaseFilterOption.Value()}"); + } + + if (testAdapterPathOption.HasValue()) + { + msbuildArgs.Add($"/p:VSTestTestAdapterPath={testAdapterPathOption.Value()}"); + } + + if (loggerOption.HasValue()) + { + msbuildArgs.Add($"/p:VSTestLogger={string.Join(";", loggerOption.Values)}"); + } + + if (configurationOption.HasValue()) + { + msbuildArgs.Add($"/p:Configuration={configurationOption.Value()}"); + } + + if (frameworkOption.HasValue()) + { + msbuildArgs.Add($"/p:TargetFramework={frameworkOption.Value()}"); + } + + if (outputOption.HasValue()) + { + msbuildArgs.Add($"/p:OutputPath={outputOption.Value()}"); + } + + if (noBuildtOption.HasValue()) + { + msbuildArgs.Add($"/p:VSTestNoBuild=true"); + } + + string defaultproject = GetSingleTestProjectToRunTestIfNotProvided(argRoot.Value, cmd.RemainingArguments); + + if(!string.IsNullOrEmpty(defaultproject)) + { + msbuildArgs.Add(defaultproject); + } + + if (!string.IsNullOrEmpty(argRoot.Value)) + { + msbuildArgs.Add(argRoot.Value); + } + + // Add remaining arguments that the parser did not understand, + msbuildArgs.AddRange(cmd.RemainingArguments); + + return new MSBuildForwardingApp(msbuildArgs).Execute(); + }); + + return cmd.Execute(args); + } + + private static string GetSingleTestProjectToRunTestIfNotProvided(string args, List remainingArguments) + { + string result = string.Empty; + int projectFound = NumberOfTestProjectInRemainingArgs(remainingArguments) + NumberOfTestProjectInArgsRoot(args); + + if (projectFound > 1) + { + throw new GracefulException( + $"Specify a single project file to run tests from."); + } + else if (projectFound == 0) + { + result = GetDefaultTestProject(); + } + + return result; + } + + private static int NumberOfTestProjectInArgsRoot(string args) + { + Regex pattern = new Regex(@"^.*\..*proj$"); + + if (!string.IsNullOrEmpty(args)) + { + return pattern.IsMatch(args) ? 1 : 0; + } + + return 0; + } + + private static int NumberOfTestProjectInRemainingArgs(List remainingArguments) + { + int count = 0; + if (remainingArguments.Count != 0) + { + Regex pattern = new Regex(@"^.*\..*proj$"); + + foreach (var x in remainingArguments) + { + if (pattern.IsMatch(x)) + { + count++; + } + } + } + + return count; + } + + private static string GetDefaultTestProject() + { + string directory = Directory.GetCurrentDirectory(); + string[] projectFiles = Directory.GetFiles(directory, "*.*proj"); + + if (projectFiles.Length == 0) + { + throw new GracefulException( + $"Couldn't find a project to run test from. Ensure a project exists in {directory}." + Environment.NewLine + + "Or pass the path to the project"); + } + else if (projectFiles.Length > 1) + { + throw new GracefulException( + $"Specify which project file to use because this '{directory}' contains more than one project file."); + } + + return projectFiles[0]; + } + } +} diff --git a/src/redist/project.json b/src/redist/project.json index 1c0d1e373..4f372691f 100644 --- a/src/redist/project.json +++ b/src/redist/project.json @@ -23,7 +23,8 @@ "Microsoft.CodeAnalysis.Build.Tasks": "2.0.0-beta6-60922-08", "System.Runtime.Serialization.Xml": "4.1.1", "NuGet.Build.Tasks": "3.6.0-rc-1979", - "Microsoft.TestPlatform.CLI": "15.0.0-preview-20160915-01" + "Microsoft.TestPlatform.CLI": "15.0.0-preview-20161005-01", + "Microsoft.TestPlatform.Build": "15.0.0-preview-20161005-01" }, "frameworks": { "netcoreapp1.0": { diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/Test3Command.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/Test3Command.cs new file mode 100644 index 000000000..985bc2061 --- /dev/null +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/Test3Command.cs @@ -0,0 +1,27 @@ +// 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 Microsoft.DotNet.Cli.Utils; + +namespace Microsoft.DotNet.Tools.Test.Utilities +{ + public sealed class Test3Command : TestCommand + { + public Test3Command() + : base("dotnet") + { + } + + public override CommandResult Execute(string args = "") + { + args = $"test3 {args}"; + return base.Execute(args); + } + + public override CommandResult ExecuteWithCapturedOutput(string args = "") + { + args = $"test3 {args}"; + return base.ExecuteWithCapturedOutput(args); + } + } +} diff --git a/test/dotnet-test3.Tests/GivenDotnetTest3BuildsAndRunsTestfromCsproj.cs b/test/dotnet-test3.Tests/GivenDotnetTest3BuildsAndRunsTestfromCsproj.cs new file mode 100644 index 000000000..f737027d2 --- /dev/null +++ b/test/dotnet-test3.Tests/GivenDotnetTest3BuildsAndRunsTestfromCsproj.cs @@ -0,0 +1,39 @@ +// 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 Microsoft.DotNet.Tools.Test.Utilities; +using Xunit; +using FluentAssertions; +using Microsoft.DotNet.TestFramework; +using Microsoft.DotNet.Cli.Utils; + +namespace Microsoft.DotNet.Cli.Test3.Tests +{ + public class GivenDotnetTest3BuildsAndRunsTestfromCsproj : TestBase + { + [Fact] + public void TestsFromAGivenProjectShouldRunWithExpectedOutput() + { + // Copy DotNetCoreTestProject project in output directory of project dotnet-vstest.Tests + string testAppName = "VSTestDotNetCoreProject"; + TestInstance testInstance = TestAssetsManager.CreateTestInstance(testAppName); + + string testProjectDirectory = testInstance.TestRoot; + + // Restore project VSTestDotNetCoreProject + new Restore3Command() + .WithWorkingDirectory(testProjectDirectory) + .Execute() + .Should() + .Pass(); + + // Call test3 + CommandResult result = new Test3Command().WithWorkingDirectory(testProjectDirectory).ExecuteWithCapturedOutput("/p:TargetFramework=netcoreapp1.0"); + + // Verify + result.StdOut.Should().Contain("Total tests: 2. Passed: 1. Failed: 1. Skipped: 0."); + result.StdOut.Should().Contain("Passed TestNamespace.VSTestTests.VSTestPassTest"); + result.StdOut.Should().Contain("Failed TestNamespace.VSTestTests.VSTestFailTest"); + } + } +} \ No newline at end of file diff --git a/test/dotnet-test3.Tests/dotnet-test3.Tests.xproj b/test/dotnet-test3.Tests/dotnet-test3.Tests.xproj new file mode 100644 index 000000000..6417b9f10 --- /dev/null +++ b/test/dotnet-test3.Tests/dotnet-test3.Tests.xproj @@ -0,0 +1,21 @@ + + + + 14.0.23107 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 90236a80-4b84-41d3-a161-aa20709776b1 + Microsoft.DotNet.Cli.Test3.Tests + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin + + + 2.0 + + + + + + \ No newline at end of file diff --git a/test/dotnet-test3.Tests/project.json b/test/dotnet-test3.Tests/project.json new file mode 100644 index 000000000..7b59006f9 --- /dev/null +++ b/test/dotnet-test3.Tests/project.json @@ -0,0 +1,24 @@ +{ + "version": "1.0.0-*", + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.0" + }, + "System.Runtime.Serialization.Primitives": "4.1.1", + "Microsoft.DotNet.Tools.Tests.Utilities": { + "target": "project" + }, + "xunit": "2.2.0-beta3-build3330", + "dotnet-test-xunit": "1.0.0-rc2-330423-54" + }, + "frameworks": { + "netcoreapp1.0": { + "imports": [ + "dotnet5.4", + "portable-net451+win8" + ] + } + }, + "testRunner": "xunit" +} \ No newline at end of file diff --git a/test/dotnet-vstest.Tests/VSTestTests.cs b/test/dotnet-vstest.Tests/VSTestTests.cs index 09fd80827..029ec3a36 100644 --- a/test/dotnet-vstest.Tests/VSTestTests.cs +++ b/test/dotnet-vstest.Tests/VSTestTests.cs @@ -11,24 +11,25 @@ using Microsoft.DotNet.Cli.Utils; namespace Microsoft.DotNet.Cli.VSTest.Tests { - public class VSTestTests: TestBase + public class VSTestTests : TestBase { [Fact] public void TestsFromAGivenContainerShouldRunWithExpectedOutput() { // Copy DotNetCoreTestProject project in output directory of project dotnet-vstest.Tests string testAppName = "VSTestDotNetCoreProject"; - TestInstance testInstance = TestAssetsManager.CreateTestInstance(testAppName).WithLockFiles(); + TestInstance testInstance = TestAssetsManager.CreateTestInstance(testAppName); string testProjectDirectory = testInstance.TestRoot; + // Restore project VSTestDotNetCoreProject new Restore3Command() .WithWorkingDirectory(testProjectDirectory) .Execute() .Should() .Pass(); - // Build project DotNetCoreTestProject + // Build project VSTestDotNetCoreProject new Build3Command() .WithWorkingDirectory(testProjectDirectory) .Execute() @@ -39,7 +40,7 @@ namespace Microsoft.DotNet.Cli.VSTest.Tests string configuration = Environment.GetEnvironmentVariable("CONFIGURATION") ?? "Debug"; string testAdapterPath = Path.Combine(testProjectDirectory, "bin", configuration, "netcoreapp1.0"); string outputDll = Path.Combine(testAdapterPath, $"{testAppName}.dll"); - string argsForVstest = string.Concat("\"", outputDll, "\"", " --TestAdapterPath:", "\"", testAdapterPath, "\""); + string argsForVstest = string.Concat("\"", outputDll, "\""); // Call vstest CommandResult result = new VSTestCommand().ExecuteWithCapturedOutput(argsForVstest);