diff --git a/.gitignore b/.gitignore
index f1732c2e0..9af9fe15f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -151,6 +151,7 @@ _ReSharper*/
*.DotSettings.user
.idea/
*.iml
+*.DotSettings
# JustCode is a .NET coding add-in
.JustCode
diff --git a/Microsoft.DotNet.Cli.sln b/Microsoft.DotNet.Cli.sln
index cc51d090f..fff392f3b 100644
--- a/Microsoft.DotNet.Cli.sln
+++ b/Microsoft.DotNet.Cli.sln
@@ -26,8 +26,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{17735A9D-B
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{0722D325-24C8-4E83-B5AF-0A083E7F0749}"
EndProject
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MultiProjectValidator", "tools\MultiProjectValidator\MultiProjectValidator.xproj", "{08A68C6A-86F6-4ED2-89A7-B166D33E9F85}"
-EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "EndToEnd", "test\EndToEnd\EndToEnd.xproj", "{65741CB1-8AEE-4C66-8198-10A7EA0E4258}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestProjects", "TestProjects", "{713CBFBB-5392-438D-B766-A9A585EF1BB8}"
@@ -106,8 +104,6 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "update-dependencies", "buil
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.ProjectModel.Loader", "src\Microsoft.DotNet.ProjectModel.Loader\Microsoft.DotNet.ProjectModel.Loader.xproj", "{1C599FFD-FB52-4279-A8E5-465D3EC499E1}"
EndProject
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.ProjectModel.Loader.Tests", "test\Microsoft.DotNet.ProjectModel.Loader.Tests\Microsoft.DotNet.ProjectModel.Loader.Tests.xproj", "{5DF6C9DA-6909-4EC0-909E-6913580BB4A4}"
-EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Configurer", "src\Microsoft.DotNet.Configurer\Microsoft.DotNet.Configurer.xproj", "{E5ED47EF-BF25-4DA9-A7FE-290C642CBF0F}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Configurer.UnitTests", "test\Microsoft.DotNet.Configurer.UnitTests\Microsoft.DotNet.Configurer.UnitTests.xproj", "{4C3B06D5-B6D5-4E5B-A44F-3EBE52A1C759}"
@@ -160,6 +156,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "publish", "publish", "{27B1
build\publish\PublishContent.targets = build\publish\PublishContent.targets
EndProjectSection
EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Tools.Test", "src\Microsoft.DotNet.Tools.Test\Microsoft.DotNet.Tools.Test.xproj", "{6D028154-5518-4A56-BAD6-938A90E5BCF6}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -252,22 +250,6 @@ Global
{DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
{DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
- {688870C8-9843-4F9E-8576-D39290AD0F25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {688870C8-9843-4F9E-8576-D39290AD0F25}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {688870C8-9843-4F9E-8576-D39290AD0F25}.Debug|x64.ActiveCfg = Debug|Any CPU
- {688870C8-9843-4F9E-8576-D39290AD0F25}.Debug|x64.Build.0 = Debug|Any CPU
- {688870C8-9843-4F9E-8576-D39290AD0F25}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
- {688870C8-9843-4F9E-8576-D39290AD0F25}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
- {688870C8-9843-4F9E-8576-D39290AD0F25}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
- {688870C8-9843-4F9E-8576-D39290AD0F25}.MinSizeRel|x64.Build.0 = Debug|Any CPU
- {688870C8-9843-4F9E-8576-D39290AD0F25}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {688870C8-9843-4F9E-8576-D39290AD0F25}.Release|Any CPU.Build.0 = Release|Any CPU
- {688870C8-9843-4F9E-8576-D39290AD0F25}.Release|x64.ActiveCfg = Release|Any CPU
- {688870C8-9843-4F9E-8576-D39290AD0F25}.Release|x64.Build.0 = Release|Any CPU
- {688870C8-9843-4F9E-8576-D39290AD0F25}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
- {688870C8-9843-4F9E-8576-D39290AD0F25}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
- {688870C8-9843-4F9E-8576-D39290AD0F25}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
- {688870C8-9843-4F9E-8576-D39290AD0F25}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
{65741CB1-8AEE-4C66-8198-10A7EA0E4258}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{65741CB1-8AEE-4C66-8198-10A7EA0E4258}.Debug|Any CPU.Build.0 = Debug|Any CPU
{65741CB1-8AEE-4C66-8198-10A7EA0E4258}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -796,22 +778,6 @@ Global
{1C599FFD-FB52-4279-A8E5-465D3EC499E1}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{1C599FFD-FB52-4279-A8E5-465D3EC499E1}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
{1C599FFD-FB52-4279-A8E5-465D3EC499E1}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
- {5DF6C9DA-6909-4EC0-909E-6913580BB4A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {5DF6C9DA-6909-4EC0-909E-6913580BB4A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {5DF6C9DA-6909-4EC0-909E-6913580BB4A4}.Debug|x64.ActiveCfg = Debug|Any CPU
- {5DF6C9DA-6909-4EC0-909E-6913580BB4A4}.Debug|x64.Build.0 = Debug|Any CPU
- {5DF6C9DA-6909-4EC0-909E-6913580BB4A4}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU
- {5DF6C9DA-6909-4EC0-909E-6913580BB4A4}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU
- {5DF6C9DA-6909-4EC0-909E-6913580BB4A4}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU
- {5DF6C9DA-6909-4EC0-909E-6913580BB4A4}.MinSizeRel|x64.Build.0 = Debug|Any CPU
- {5DF6C9DA-6909-4EC0-909E-6913580BB4A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {5DF6C9DA-6909-4EC0-909E-6913580BB4A4}.Release|Any CPU.Build.0 = Release|Any CPU
- {5DF6C9DA-6909-4EC0-909E-6913580BB4A4}.Release|x64.ActiveCfg = Release|Any CPU
- {5DF6C9DA-6909-4EC0-909E-6913580BB4A4}.Release|x64.Build.0 = Release|Any CPU
- {5DF6C9DA-6909-4EC0-909E-6913580BB4A4}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU
- {5DF6C9DA-6909-4EC0-909E-6913580BB4A4}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
- {5DF6C9DA-6909-4EC0-909E-6913580BB4A4}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
- {5DF6C9DA-6909-4EC0-909E-6913580BB4A4}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
{E5ED47EF-BF25-4DA9-A7FE-290C642CBF0F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E5ED47EF-BF25-4DA9-A7FE-290C642CBF0F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E5ED47EF-BF25-4DA9-A7FE-290C642CBF0F}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -908,6 +874,22 @@ Global
{E4F46EAB-B5A5-4E60-9B9D-40A1FADBF45C}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU
{E4F46EAB-B5A5-4E60-9B9D-40A1FADBF45C}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU
{E4F46EAB-B5A5-4E60-9B9D-40A1FADBF45C}.RelWithDebInfo|x64.Build.0 = Release|Any CPU
+ {6D028154-5518-4A56-BAD6-938A90E5BCF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6D028154-5518-4A56-BAD6-938A90E5BCF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6D028154-5518-4A56-BAD6-938A90E5BCF6}.Debug|x64.ActiveCfg = Debug|x64
+ {6D028154-5518-4A56-BAD6-938A90E5BCF6}.Debug|x64.Build.0 = Debug|x64
+ {6D028154-5518-4A56-BAD6-938A90E5BCF6}.MinSizeRel|Any CPU.ActiveCfg = MinSizeRel|Any CPU
+ {6D028154-5518-4A56-BAD6-938A90E5BCF6}.MinSizeRel|Any CPU.Build.0 = MinSizeRel|Any CPU
+ {6D028154-5518-4A56-BAD6-938A90E5BCF6}.MinSizeRel|x64.ActiveCfg = MinSizeRel|x64
+ {6D028154-5518-4A56-BAD6-938A90E5BCF6}.MinSizeRel|x64.Build.0 = MinSizeRel|x64
+ {6D028154-5518-4A56-BAD6-938A90E5BCF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6D028154-5518-4A56-BAD6-938A90E5BCF6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6D028154-5518-4A56-BAD6-938A90E5BCF6}.Release|x64.ActiveCfg = Release|x64
+ {6D028154-5518-4A56-BAD6-938A90E5BCF6}.Release|x64.Build.0 = Release|x64
+ {6D028154-5518-4A56-BAD6-938A90E5BCF6}.RelWithDebInfo|Any CPU.ActiveCfg = RelWithDebInfo|Any CPU
+ {6D028154-5518-4A56-BAD6-938A90E5BCF6}.RelWithDebInfo|Any CPU.Build.0 = RelWithDebInfo|Any CPU
+ {6D028154-5518-4A56-BAD6-938A90E5BCF6}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64
+ {6D028154-5518-4A56-BAD6-938A90E5BCF6}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -918,7 +900,6 @@ Global
{A16958E1-24C7-4F1E-B317-204AD91625DD} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
{BD7833F8-3209-4682-BF75-B4BCA883E279} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
{DCDFE282-03DE-4DBC-B90C-CC3CE3EC8162} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
- {688870C8-9843-4F9E-8576-D39290AD0F25} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
{65741CB1-8AEE-4C66-8198-10A7EA0E4258} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
{713CBFBB-5392-438D-B766-A9A585EF1BB8} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
{60CF7E6C-D6C8-439D-B7B7-D8A27E29BE2C} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
@@ -957,7 +938,6 @@ Global
{B768BD29-12BF-4C7C-B093-03193FE244D1} = {88278B81-7649-45DC-8A6A-D3A645C5AFC3}
{A28BD8AC-DF15-4F58-8299-98A9AE2B8726} = {88278B81-7649-45DC-8A6A-D3A645C5AFC3}
{1C599FFD-FB52-4279-A8E5-465D3EC499E1} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
- {5DF6C9DA-6909-4EC0-909E-6913580BB4A4} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
{E5ED47EF-BF25-4DA9-A7FE-290C642CBF0F} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
{4C3B06D5-B6D5-4E5B-A44F-3EBE52A1C759} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
{35B19F22-B8C0-4849-9C35-3F809B7588B8} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
@@ -968,5 +948,6 @@ Global
{FF498306-2DE2-47F6-8C35-3CF0589CF2B8} = {89905EC4-BC0F-443B-8ADF-691321F10108}
{E4F46EAB-B5A5-4E60-9B9D-40A1FADBF45C} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7}
{27B12960-ABB0-4903-9C60-5E9157E659C8} = {89905EC4-BC0F-443B-8ADF-691321F10108}
+ {6D028154-5518-4A56-BAD6-938A90E5BCF6} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F}
EndGlobalSection
EndGlobal
diff --git a/build/package/Microsoft.DotNet.Cli.Nupkg.targets b/build/package/Microsoft.DotNet.Cli.Nupkg.targets
index 6f48f9bec..adf734121 100644
--- a/build/package/Microsoft.DotNet.Cli.Nupkg.targets
+++ b/build/package/Microsoft.DotNet.Cli.Nupkg.targets
@@ -43,6 +43,10 @@
Microsoft.Extensions.Testing.Abstractions
$(SdkNugetVersion)
+
+ Microsoft.DotNet.Tools.Test
+ $(SdkNugetVersion)
+
diff --git a/src/Microsoft.DotNet.Cli.Utils/Command.cs b/src/Microsoft.DotNet.Cli.Utils/Command.cs
index 631c508db..083bd5139 100644
--- a/src/Microsoft.DotNet.Cli.Utils/Command.cs
+++ b/src/Microsoft.DotNet.Cli.Utils/Command.cs
@@ -56,22 +56,20 @@ namespace Microsoft.DotNet.Cli.Utils
/// array will be present in the corresponding argument array
/// in the command's process.
///
- ///
- ///
- ///
- ///
public static Command Create(
string commandName,
IEnumerable args,
NuGetFramework framework = null,
string configuration = Constants.DefaultConfiguration,
- string outputPath = null)
+ string outputPath = null,
+ string applicationName = null)
{
var commandSpec = CommandResolver.TryResolveCommandSpec(commandName,
args,
framework,
configuration: configuration,
- outputPath: outputPath);
+ outputPath: outputPath,
+ applicationName: applicationName);
if (commandSpec == null)
{
diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/CommandResolverArguments.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/CommandResolverArguments.cs
index e43b377b5..dca62db0a 100644
--- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/CommandResolverArguments.cs
+++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/CommandResolverArguments.cs
@@ -1,8 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Microsoft.DotNet.ProjectModel;
-using Microsoft.DotNet.ProjectModel.Graph;
+using System.Collections.Generic;
using NuGet.Frameworks;
namespace Microsoft.DotNet.Cli.Utils
@@ -26,5 +22,7 @@ namespace Microsoft.DotNet.Cli.Utils
public string BuildBasePath { get; set; }
public string DepsJsonFile { get; set; }
+
+ public string ApplicationName { get; set; }
}
}
diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/DefaultCommandResolverPolicy.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/DefaultCommandResolverPolicy.cs
index fbd093e6a..f7357af8e 100644
--- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/DefaultCommandResolverPolicy.cs
+++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/DefaultCommandResolverPolicy.cs
@@ -8,6 +8,7 @@ namespace Microsoft.DotNet.Cli.Utils
{
var environment = new EnvironmentProvider();
var packagedCommandSpecFactory = new PackagedCommandSpecFactory();
+ var publishedPathCommandSpecFactory = new PublishPathCommandSpecFactory();
var platformCommandSpecFactory = default(IPlatformCommandSpecFactory);
if (RuntimeEnvironment.OperatingSystemPlatform == Platform.Windows)
@@ -19,13 +20,18 @@ namespace Microsoft.DotNet.Cli.Utils
platformCommandSpecFactory = new GenericPlatformCommandSpecFactory();
}
- return CreateDefaultCommandResolver(environment, packagedCommandSpecFactory, platformCommandSpecFactory);
+ return CreateDefaultCommandResolver(
+ environment,
+ packagedCommandSpecFactory,
+ platformCommandSpecFactory,
+ publishedPathCommandSpecFactory);
}
public static CompositeCommandResolver CreateDefaultCommandResolver(
IEnvironmentProvider environment,
IPackagedCommandSpecFactory packagedCommandSpecFactory,
- IPlatformCommandSpecFactory platformCommandSpecFactory)
+ IPlatformCommandSpecFactory platformCommandSpecFactory,
+ IPublishedPathCommandSpecFactory publishedPathCommandSpecFactory)
{
var compositeCommandResolver = new CompositeCommandResolver();
@@ -33,8 +39,12 @@ namespace Microsoft.DotNet.Cli.Utils
compositeCommandResolver.AddCommandResolver(new RootedCommandResolver());
compositeCommandResolver.AddCommandResolver(new ProjectToolsCommandResolver(packagedCommandSpecFactory));
compositeCommandResolver.AddCommandResolver(new AppBaseDllCommandResolver());
- compositeCommandResolver.AddCommandResolver(new AppBaseCommandResolver(environment, platformCommandSpecFactory));
- compositeCommandResolver.AddCommandResolver(new PathCommandResolver(environment, platformCommandSpecFactory));
+ compositeCommandResolver.AddCommandResolver(
+ new AppBaseCommandResolver(environment, platformCommandSpecFactory));
+ compositeCommandResolver.AddCommandResolver(
+ new PathCommandResolver(environment, platformCommandSpecFactory));
+ compositeCommandResolver.AddCommandResolver(
+ new PublishedPathCommandResolver(environment, publishedPathCommandSpecFactory));
return compositeCommandResolver;
}
diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs
index 3c5316456..24e82fa6c 100644
--- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs
+++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPackagedCommandSpecFactory.cs
@@ -1,10 +1,5 @@
-using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.ProjectModel.Graph;
-using Microsoft.DotNet.ProjectModel.Compilation;
namespace Microsoft.DotNet.Cli.Utils
{
diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPublishedPathCommandSpecFactory.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPublishedPathCommandSpecFactory.cs
new file mode 100644
index 000000000..115f9c352
--- /dev/null
+++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/IPublishedPathCommandSpecFactory.cs
@@ -0,0 +1,17 @@
+// 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.Collections.Generic;
+
+namespace Microsoft.DotNet.Cli.Utils
+{
+ public interface IPublishedPathCommandSpecFactory
+ {
+ CommandSpec CreateCommandSpecFromPublishFolder(
+ string commandPath,
+ IEnumerable commandArguments,
+ CommandResolutionStrategy commandResolutionStrategy,
+ string depsFilePath,
+ string runtimeConfigPath);
+ }
+}
diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/OutputPathCommandResolver.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/OutputPathCommandResolver.cs
index 231de29c2..f3dcb968b 100644
--- a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/OutputPathCommandResolver.cs
+++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/OutputPathCommandResolver.cs
@@ -51,7 +51,8 @@ namespace Microsoft.DotNet.Cli.Utils
return null;
}
- var buildOutputPath = projectContext.GetOutputPaths(configuration, buildBasePath, outputPath).RuntimeFiles.BasePath;
+ var buildOutputPath =
+ projectContext.GetOutputPaths(configuration, buildBasePath, outputPath).RuntimeFiles.BasePath;
if (! Directory.Exists(buildOutputPath))
{
diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PublishPathCommandSpecFactory.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PublishPathCommandSpecFactory.cs
new file mode 100644
index 000000000..54a9c68f2
--- /dev/null
+++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PublishPathCommandSpecFactory.cs
@@ -0,0 +1,96 @@
+// 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 Microsoft.DotNet.ProjectModel;
+
+namespace Microsoft.DotNet.Cli.Utils
+{
+ public class PublishPathCommandSpecFactory : IPublishedPathCommandSpecFactory
+ {
+ public CommandSpec CreateCommandSpecFromPublishFolder(
+ string commandPath,
+ IEnumerable commandArguments,
+ CommandResolutionStrategy commandResolutionStrategy,
+ string depsFilePath,
+ string runtimeConfigPath)
+ {
+ return CreateCommandSpecWrappingWithMuxerIfDll(
+ commandPath,
+ commandArguments,
+ depsFilePath,
+ commandResolutionStrategy,
+ runtimeConfigPath);
+ }
+
+ private CommandSpec CreateCommandSpecWrappingWithMuxerIfDll(
+ string commandPath,
+ IEnumerable commandArguments,
+ string depsFilePath,
+ CommandResolutionStrategy commandResolutionStrategy,
+ string runtimeConfigPath)
+ {
+ var commandExtension = Path.GetExtension(commandPath);
+
+ if (commandExtension == FileNameSuffixes.DotNet.DynamicLib)
+ {
+ return CreatePackageCommandSpecUsingMuxer(
+ commandPath,
+ commandArguments,
+ depsFilePath,
+ commandResolutionStrategy,
+ runtimeConfigPath);
+ }
+
+ return CreateCommandSpec(commandPath, commandArguments, commandResolutionStrategy);
+ }
+ private CommandSpec CreatePackageCommandSpecUsingMuxer(
+ string commandPath,
+ IEnumerable commandArguments,
+ string depsFilePath,
+ CommandResolutionStrategy commandResolutionStrategy,
+ string runtimeConfigPath)
+ {
+ var arguments = new List();
+
+ var muxer = new Muxer();
+
+ var host = muxer.MuxerPath;
+ if (host == null)
+ {
+ throw new Exception("Unable to locate dotnet multiplexer");
+ }
+
+ arguments.Add("exec");
+
+ if (runtimeConfigPath != null)
+ {
+ arguments.Add("--runtimeconfig");
+ arguments.Add(runtimeConfigPath);
+ }
+
+ if (depsFilePath != null)
+ {
+ arguments.Add("--depsfile");
+ arguments.Add(depsFilePath);
+ }
+
+ arguments.Add(commandPath);
+ arguments.AddRange(commandArguments);
+
+ return CreateCommandSpec(host, arguments, commandResolutionStrategy);
+ }
+
+ private CommandSpec CreateCommandSpec(
+ string commandPath,
+ IEnumerable commandArguments,
+ CommandResolutionStrategy commandResolutionStrategy)
+ {
+ var escapedArgs = ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart(commandArguments);
+
+ return new CommandSpec(commandPath, escapedArgs, commandResolutionStrategy);
+ }
+ }
+}
diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PublishedPathCommandResolver.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PublishedPathCommandResolver.cs
new file mode 100644
index 000000000..eda1e99e1
--- /dev/null
+++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolution/PublishedPathCommandResolver.cs
@@ -0,0 +1,72 @@
+// 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.IO;
+
+namespace Microsoft.DotNet.Cli.Utils
+{
+ public class PublishedPathCommandResolver : ICommandResolver
+ {
+ private readonly IEnvironmentProvider _environment;
+ private readonly IPublishedPathCommandSpecFactory _commandSpecFactory;
+
+ public PublishedPathCommandResolver(
+ IEnvironmentProvider environment,
+ IPublishedPathCommandSpecFactory commandSpecFactory)
+ {
+ _environment = environment;
+ _commandSpecFactory = commandSpecFactory;
+ }
+
+ public CommandSpec Resolve(CommandResolverArguments commandResolverArguments)
+ {
+ var publishDirectory = commandResolverArguments.OutputPath;
+ var commandName = commandResolverArguments.CommandName;
+ var applicationName = commandResolverArguments.ApplicationName;
+
+ if (publishDirectory == null || commandName == null || applicationName == null)
+ {
+ return null;
+ }
+
+ var commandPath = ResolveCommandPath(publishDirectory, commandName);
+
+ if (commandPath == null)
+ {
+ return null;
+ }
+
+ var depsFilePath = Path.Combine(publishDirectory, $"{applicationName}.deps.json");
+ if (!File.Exists(depsFilePath))
+ {
+ Reporter.Verbose.WriteLine($"PublishedPathCommandResolver: {depsFilePath} does not exist");
+ return null;
+ }
+
+ var runtimeConfigPath = Path.Combine(publishDirectory, $"{applicationName}.runtimeconfig.json");
+ if (!File.Exists(runtimeConfigPath))
+ {
+ Reporter.Verbose.WriteLine($"projectdependenciescommandresolver: {runtimeConfigPath} does not exist");
+ return null;
+ }
+
+ return _commandSpecFactory.CreateCommandSpecFromPublishFolder(
+ commandPath,
+ commandResolverArguments.CommandArguments.OrEmptyIfNull(),
+ CommandResolutionStrategy.OutputPath,
+ depsFilePath,
+ runtimeConfigPath);
+ }
+
+ private string ResolveCommandPath(string publishDirectory, string commandName)
+ {
+ if (!Directory.Exists(publishDirectory))
+ {
+ Reporter.Verbose.WriteLine($"publishedpathresolver: {publishDirectory} does not exist");
+ return null;
+ }
+
+ return _environment.GetCommandPathFromRootPath(publishDirectory, commandName, ".dll");
+ }
+ }
+}
diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolver.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolver.cs
index 35f2f3cd5..d929c8cad 100644
--- a/src/Microsoft.DotNet.Cli.Utils/CommandResolver.cs
+++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolver.cs
@@ -12,7 +12,8 @@ namespace Microsoft.DotNet.Cli.Utils
IEnumerable args,
NuGetFramework framework = null,
string configuration = Constants.DefaultConfiguration,
- string outputPath = null)
+ string outputPath = null,
+ string applicationName = null)
{
var commandResolverArgs = new CommandResolverArguments
{
@@ -21,7 +22,8 @@ namespace Microsoft.DotNet.Cli.Utils
Framework = framework,
ProjectDirectory = Directory.GetCurrentDirectory(),
Configuration = configuration,
- OutputPath = outputPath
+ OutputPath = outputPath,
+ ApplicationName = applicationName
};
var defaultCommandResolver = DefaultCommandResolverPolicy.Create();
diff --git a/src/Microsoft.DotNet.Cli.Utils/PublishedPathCommandFactory.cs b/src/Microsoft.DotNet.Cli.Utils/PublishedPathCommandFactory.cs
new file mode 100644
index 000000000..24fac7d35
--- /dev/null
+++ b/src/Microsoft.DotNet.Cli.Utils/PublishedPathCommandFactory.cs
@@ -0,0 +1,29 @@
+// 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.Collections.Generic;
+using NuGet.Frameworks;
+
+namespace Microsoft.DotNet.Cli.Utils
+{
+ public class PublishedPathCommandFactory : ICommandFactory
+ {
+ private readonly string _publishDirectory;
+ private readonly string _applicationName;
+
+ public PublishedPathCommandFactory(string publishDirectory, string applicationName)
+ {
+ _publishDirectory = publishDirectory;
+ _applicationName = applicationName;
+ }
+
+ public ICommand Create(
+ string commandName,
+ IEnumerable args,
+ NuGetFramework framework = null,
+ string configuration = Constants.DefaultConfiguration)
+ {
+ return Command.Create(commandName, args, framework, configuration, _publishDirectory, _applicationName);
+ }
+ }
+}
diff --git a/src/Microsoft.DotNet.InternalAbstractions/DirectoryWrapper.cs b/src/Microsoft.DotNet.InternalAbstractions/DirectoryWrapper.cs
index a86187822..591462989 100644
--- a/src/Microsoft.DotNet.InternalAbstractions/DirectoryWrapper.cs
+++ b/src/Microsoft.DotNet.InternalAbstractions/DirectoryWrapper.cs
@@ -1,6 +1,7 @@
// 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.Collections.Generic;
using System.IO;
using Microsoft.DotNet.InternalAbstractions;
@@ -17,5 +18,29 @@ namespace Microsoft.Extensions.EnvironmentAbstractions
{
return new TemporaryDirectory();
}
+
+ public IEnumerable GetFiles(string path, string searchPattern)
+ {
+ return Directory.GetFiles(path, searchPattern);
+ }
+
+ public string GetDirectoryFullName(string path)
+ {
+ var directoryFullName = string.Empty;
+ if (Exists(path))
+ {
+ directoryFullName = new DirectoryInfo(path).FullName;
+ }
+ else
+ {
+ var fileInfo = new FileInfo(path);
+ if (fileInfo.Directory != null)
+ {
+ directoryFullName = fileInfo.Directory.FullName;
+ }
+ }
+
+ return directoryFullName;
+ }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.InternalAbstractions/IDirectory.cs b/src/Microsoft.DotNet.InternalAbstractions/IDirectory.cs
index 0fed21865..95464df21 100644
--- a/src/Microsoft.DotNet.InternalAbstractions/IDirectory.cs
+++ b/src/Microsoft.DotNet.InternalAbstractions/IDirectory.cs
@@ -1,6 +1,8 @@
// 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.Collections.Generic;
+
namespace Microsoft.Extensions.EnvironmentAbstractions
{
internal interface IDirectory
@@ -8,5 +10,9 @@ namespace Microsoft.Extensions.EnvironmentAbstractions
bool Exists(string path);
ITemporaryDirectory CreateTemporaryDirectory();
+
+ IEnumerable GetFiles(string path, string searchPattern);
+
+ string GetDirectoryFullName(string path);
}
}
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.InternalAbstractions/Properties/Properties.cs b/src/Microsoft.DotNet.InternalAbstractions/Properties/Properties.cs
index ceccc63e7..a062d0c47 100644
--- a/src/Microsoft.DotNet.InternalAbstractions/Properties/Properties.cs
+++ b/src/Microsoft.DotNet.InternalAbstractions/Properties/Properties.cs
@@ -7,4 +7,6 @@ using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.Extensions.DependencyModel.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.DotNet.Configurer, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.DotNet.Configurer.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
-[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
\ No newline at end of file
+[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
+[assembly: InternalsVisibleTo("dotnet-test.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100039ac461fa5c82c7dd2557400c4fd4e9dcdf7ac47e3d572548c04cd4673e004916610f4ea5cbf86f2b1ca1cb824f2a7b3976afecfcf4eb72d9a899aa6786effa10c30399e6580ed848231fec48374e41b3acf8811931343fc2f73acf72dae745adbcb7063cc4b50550618383202875223fc75401351cd89c44bf9b50e7fa3796")]
+[assembly: InternalsVisibleTo("Microsoft.DotNet.Tools.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
diff --git a/src/Microsoft.DotNet.ProjectModel/IProjectReader.cs b/src/Microsoft.DotNet.ProjectModel/IProjectReader.cs
new file mode 100644
index 000000000..981ecbc36
--- /dev/null
+++ b/src/Microsoft.DotNet.ProjectModel/IProjectReader.cs
@@ -0,0 +1,10 @@
+// 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.
+
+namespace Microsoft.DotNet.ProjectModel
+{
+ public interface IProjectReader
+ {
+ Project ReadProject(string projectPath, ProjectReaderSettings settings = null);
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.ProjectModel/ProjectReader.cs b/src/Microsoft.DotNet.ProjectModel/ProjectReader.cs
index 87bee7ea5..6e4e466e7 100644
--- a/src/Microsoft.DotNet.ProjectModel/ProjectReader.cs
+++ b/src/Microsoft.DotNet.ProjectModel/ProjectReader.cs
@@ -15,7 +15,7 @@ using NuGet.Versioning;
namespace Microsoft.DotNet.ProjectModel
{
- public class ProjectReader
+ public class ProjectReader : IProjectReader
{
public static bool TryGetProject(string path, out Project project, ProjectReaderSettings settings = null)
{
@@ -63,6 +63,11 @@ namespace Microsoft.DotNet.ProjectModel
}
public static Project GetProject(string projectPath, ProjectReaderSettings settings = null)
+ {
+ return new ProjectReader().ReadProject(projectPath, settings);
+ }
+
+ public Project ReadProject(string projectPath, ProjectReaderSettings settings)
{
projectPath = ProjectPathHelper.NormalizeProjectFilePath(projectPath);
@@ -70,7 +75,7 @@ namespace Microsoft.DotNet.ProjectModel
using (var stream = new FileStream(projectPath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
- return new ProjectReader().ReadProject(stream, name, projectPath, settings);
+ return ReadProject(stream, name, projectPath, settings);
}
}
diff --git a/src/Microsoft.DotNet.ProjectModel/Properties/AssemblyInfo.cs b/src/Microsoft.DotNet.ProjectModel/Properties/AssemblyInfo.cs
index 736765643..8004866db 100644
--- a/src/Microsoft.DotNet.ProjectModel/Properties/AssemblyInfo.cs
+++ b/src/Microsoft.DotNet.ProjectModel/Properties/AssemblyInfo.cs
@@ -27,3 +27,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyMetadataAttribute("Serviceable", "True")]
[assembly: InternalsVisibleTo("Microsoft.DotNet.ProjectModel.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100039ac461fa5c82c7dd2557400c4fd4e9dcdf7ac47e3d572548c04cd4673e004916610f4ea5cbf86f2b1ca1cb824f2a7b3976afecfcf4eb72d9a899aa6786effa10c30399e6580ed848231fec48374e41b3acf8811931343fc2f73acf72dae745adbcb7063cc4b50550618383202875223fc75401351cd89c44bf9b50e7fa3796")]
+[assembly:
+ InternalsVisibleTo(
+ "dotnet-test.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100039ac461fa5c82c7dd2557400c4fd4e9dcdf7ac47e3d572548c04cd4673e004916610f4ea5cbf86f2b1ca1cb824f2a7b3976afecfcf4eb72d9a899aa6786effa10c30399e6580ed848231fec48374e41b3acf8811931343fc2f73acf72dae745adbcb7063cc4b50550618383202875223fc75401351cd89c44bf9b50e7fa3796"
+ )]
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.Tools.Test/AssemblyTestRunnerDecorator.cs b/src/Microsoft.DotNet.Tools.Test/AssemblyTestRunnerDecorator.cs
new file mode 100644
index 000000000..c6d9836b7
--- /dev/null
+++ b/src/Microsoft.DotNet.Tools.Test/AssemblyTestRunnerDecorator.cs
@@ -0,0 +1,32 @@
+// 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.Cli.Utils;
+
+namespace Microsoft.DotNet.Tools.Test
+{
+ public class AssemblyTestRunnerDecorator : IDotnetTestRunner
+ {
+ private readonly Func _nextRunner;
+
+ public AssemblyTestRunnerDecorator(Func nextRunner)
+ {
+ _nextRunner = nextRunner;
+ }
+
+ public int RunTests(DotnetTestParams dotnetTestParams)
+ {
+ var assembly = new FileInfo(dotnetTestParams.ProjectOrAssemblyPath);
+ var publishDirectory = assembly.Directory.FullName;
+ var applicationName = Path.GetFileNameWithoutExtension(dotnetTestParams.ProjectOrAssemblyPath);
+
+ var commandFactory = new PublishedPathCommandFactory(publishDirectory, applicationName);
+
+ var assemblyUnderTest = dotnetTestParams.ProjectOrAssemblyPath;
+
+ return _nextRunner(commandFactory, assemblyUnderTest).RunTests(dotnetTestParams);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/dotnet/commands/dotnet-test/AssemblyUnderTest.cs b/src/Microsoft.DotNet.Tools.Test/AssemblyUnderTest.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/AssemblyUnderTest.cs
rename to src/Microsoft.DotNet.Tools.Test/AssemblyUnderTest.cs
diff --git a/src/dotnet/commands/dotnet-test/CommandTestRunnerExtensions.cs b/src/Microsoft.DotNet.Tools.Test/CommandTestRunnerExtensions.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/CommandTestRunnerExtensions.cs
rename to src/Microsoft.DotNet.Tools.Test/CommandTestRunnerExtensions.cs
diff --git a/src/Microsoft.DotNet.Tools.Test/ConsoleTestRunner.cs b/src/Microsoft.DotNet.Tools.Test/ConsoleTestRunner.cs
new file mode 100644
index 000000000..fa8a6b00e
--- /dev/null
+++ b/src/Microsoft.DotNet.Tools.Test/ConsoleTestRunner.cs
@@ -0,0 +1,55 @@
+// 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.Collections.Generic;
+using Microsoft.DotNet.Cli.Utils;
+using NuGet.Frameworks;
+
+namespace Microsoft.DotNet.Tools.Test
+{
+ public class ConsoleTestRunner : IDotnetTestRunner
+ {
+ private readonly ITestRunnerNameResolver _testRunnerNameResolver;
+
+ private readonly ICommandFactory _commandFactory;
+
+ private readonly string _assemblyUnderTest;
+
+ private readonly NuGetFramework _framework;
+
+ public ConsoleTestRunner(
+ ITestRunnerNameResolver testRunnerNameResolver,
+ ICommandFactory commandFactory,
+ string assemblyUnderTest,
+ NuGetFramework framework = null)
+ {
+ _testRunnerNameResolver = testRunnerNameResolver;
+ _commandFactory = commandFactory;
+ _assemblyUnderTest = assemblyUnderTest;
+ _framework = framework;
+ }
+
+ public int RunTests(DotnetTestParams dotnetTestParams)
+ {
+ return _commandFactory.Create(
+ _testRunnerNameResolver.ResolveTestRunner(),
+ GetCommandArgs(dotnetTestParams),
+ _framework,
+ dotnetTestParams.Config)
+ .Execute()
+ .ExitCode;
+ }
+
+ private IEnumerable GetCommandArgs(DotnetTestParams dotnetTestParams)
+ {
+ var commandArgs = new List
+ {
+ _assemblyUnderTest
+ };
+
+ commandArgs.AddRange(dotnetTestParams.RemainingArguments);
+
+ return commandArgs;
+ }
+ }
+}
diff --git a/src/dotnet/commands/dotnet-test/DesignTimeRunner.cs b/src/Microsoft.DotNet.Tools.Test/DesignTimeRunner.cs
similarity index 58%
rename from src/dotnet/commands/dotnet-test/DesignTimeRunner.cs
rename to src/Microsoft.DotNet.Tools.Test/DesignTimeRunner.cs
index 9ccf7ca7d..8d3d37ded 100644
--- a/src/dotnet/commands/dotnet-test/DesignTimeRunner.cs
+++ b/src/Microsoft.DotNet.Tools.Test/DesignTimeRunner.cs
@@ -3,44 +3,49 @@
using System;
using Microsoft.DotNet.Cli.Utils;
-using Microsoft.DotNet.ProjectModel;
namespace Microsoft.DotNet.Tools.Test
{
- public class DesignTimeRunner : BaseDotnetTestRunner
+ public class DesignTimeRunner : IDotnetTestRunner
{
- internal override int DoRunTests(ProjectContext projectContext, DotnetTestParams dotnetTestParams)
+ private readonly ITestRunnerNameResolver _testRunnerNameResolver;
+
+ private readonly ICommandFactory _commandFactory;
+
+ private readonly string _assemblyUnderTest;
+
+ public DesignTimeRunner(
+ ITestRunnerNameResolver testRunnerNameResolver,
+ ICommandFactory commandFactory,
+ string assemblyUnderTest)
+ {
+ _testRunnerNameResolver = testRunnerNameResolver;
+ _commandFactory = commandFactory;
+ _assemblyUnderTest = assemblyUnderTest;
+ }
+
+ public int RunTests(DotnetTestParams dotnetTestParams)
{
Console.WriteLine("Listening on port {0}", dotnetTestParams.Port.Value);
- HandleDesignTimeMessages(projectContext, dotnetTestParams);
+ HandleDesignTimeMessages(dotnetTestParams);
return 0;
}
- private static void HandleDesignTimeMessages(
- ProjectContext projectContext,
- DotnetTestParams dotnetTestParams)
+ private void HandleDesignTimeMessages(DotnetTestParams dotnetTestParams)
{
var reportingChannelFactory = new ReportingChannelFactory();
var adapterChannel = reportingChannelFactory.CreateAdapterChannel(dotnetTestParams.Port.Value);
try
{
- var pathToAssemblyUnderTest = new AssemblyUnderTest(projectContext, dotnetTestParams).Path;
+ var pathToAssemblyUnderTest = _assemblyUnderTest;
var messages = new TestMessagesCollection();
using (var dotnetTest = new DotnetTest(messages, pathToAssemblyUnderTest))
{
- var commandFactory =
- new ProjectDependenciesCommandFactory(
- projectContext.TargetFramework,
- dotnetTestParams.Config,
- dotnetTestParams.Output,
- dotnetTestParams.BuildBasePath,
- projectContext.ProjectDirectory);
-
var testRunnerFactory =
- new TestRunnerFactory(GetCommandName(projectContext.ProjectFile.TestRunner), commandFactory);
+ new TestRunnerFactory(_testRunnerNameResolver.ResolveTestRunner(), _commandFactory);
dotnetTest
.AddNonSpecificMessageHandlers(messages, adapterChannel)
@@ -60,10 +65,5 @@ namespace Microsoft.DotNet.Tools.Test
adapterChannel.SendError(ex);
}
}
-
- private static string GetCommandName(string testRunner)
- {
- return $"test-{testRunner}";
- }
}
}
diff --git a/src/dotnet/commands/dotnet-test/DotnetTest.cs b/src/Microsoft.DotNet.Tools.Test/DotnetTest.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/DotnetTest.cs
rename to src/Microsoft.DotNet.Tools.Test/DotnetTest.cs
diff --git a/src/dotnet/commands/dotnet-test/DotnetTestExtensions.cs b/src/Microsoft.DotNet.Tools.Test/DotnetTestExtensions.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/DotnetTestExtensions.cs
rename to src/Microsoft.DotNet.Tools.Test/DotnetTestExtensions.cs
diff --git a/src/dotnet/commands/dotnet-test/DotnetTestParams.cs b/src/Microsoft.DotNet.Tools.Test/DotnetTestParams.cs
similarity index 76%
rename from src/dotnet/commands/dotnet-test/DotnetTestParams.cs
rename to src/Microsoft.DotNet.Tools.Test/DotnetTestParams.cs
index 312f59167..9bfdadff1 100644
--- a/src/dotnet/commands/dotnet-test/DotnetTestParams.cs
+++ b/src/Microsoft.DotNet.Tools.Test/DotnetTestParams.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.IO;
using Microsoft.DotNet.Cli.CommandLine;
using Microsoft.DotNet.Cli.Utils;
+using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.Tools.Common;
using NuGet.Frameworks;
using static System.Int32;
@@ -23,8 +24,9 @@ namespace Microsoft.DotNet.Tools.Test
private CommandOption _configurationOption;
private CommandOption _portOption;
private CommandOption _parentProcessIdOption;
- private CommandArgument _projectPath;
+ private CommandArgument _projectOrAssemblyPath;
private CommandOption _noBuildOption;
+ private CommandOption _testRunner;
public int? Port { get; set; }
@@ -38,7 +40,7 @@ namespace Microsoft.DotNet.Tools.Test
public string Output { get; set; }
- public string ProjectPath { get; set; }
+ public string ProjectOrAssemblyPath { get; set; }
public NuGetFramework Framework { get; set; }
@@ -50,6 +52,12 @@ namespace Microsoft.DotNet.Tools.Test
public bool Help { get; set; }
+ public string TestRunner { get; set; }
+
+ public bool HasTestRunner => !string.IsNullOrWhiteSpace(TestRunner);
+
+ public bool IsTestingAssembly => ProjectOrAssemblyPath.EndsWith(".dll");
+
public DotnetTestParams()
{
_app = new CommandLineApplication(false)
@@ -69,10 +77,10 @@ namespace Microsoft.DotNet.Tools.Test
_app.OnExecute(() =>
{
// Locate the project and get the name and full path
- ProjectPath = _projectPath.Value;
- if (string.IsNullOrEmpty(ProjectPath))
+ ProjectOrAssemblyPath = _projectOrAssemblyPath.Value;
+ if (string.IsNullOrEmpty(ProjectOrAssemblyPath))
{
- ProjectPath = Directory.GetCurrentDirectory();
+ ProjectOrAssemblyPath = Directory.GetCurrentDirectory();
}
if (_parentProcessIdOption.HasValue())
@@ -100,6 +108,16 @@ namespace Microsoft.DotNet.Tools.Test
Port = port;
}
+ if (_testRunner.HasValue())
+ {
+ if (!IsTestingAssembly)
+ {
+ throw new InvalidOperationException("You can only specify a test runner with a dll.");
+ }
+
+ TestRunner = _testRunner.Value();
+ }
+
UnparsedFramework = _frameworkOption.Value();
if (_frameworkOption.HasValue())
{
@@ -156,9 +174,16 @@ namespace Microsoft.DotNet.Tools.Test
CommandOptionType.SingleValue);
_noBuildOption =
_app.Option("--no-build", "Do not build project before testing", CommandOptionType.NoValue);
- _projectPath = _app.Argument(
- "",
- "The project to test, defaults to the current directory. Can be a path to a project.json or a project directory.");
+ _testRunner =
+ _app.Option(
+ "-t|--test-runner ",
+ "Test runner to be used to run the test when an assembly to test is specified. If this option " +
+ "is not provided, we will try to find a suitable runner collocated with the assembly",
+ CommandOptionType.SingleValue);
+ _projectOrAssemblyPath = _app.Argument(
+ "",
+ "The project or assembly to test, defaults to the current directory. Can be a path to a " +
+ "project.json, to a dll or a project directory.");
}
}
}
diff --git a/src/Microsoft.DotNet.Tools.Test/DotnetTestRunnerFactory.cs b/src/Microsoft.DotNet.Tools.Test/DotnetTestRunnerFactory.cs
new file mode 100644
index 000000000..bcef09d91
--- /dev/null
+++ b/src/Microsoft.DotNet.Tools.Test/DotnetTestRunnerFactory.cs
@@ -0,0 +1,56 @@
+// 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 Microsoft.DotNet.Cli.Utils;
+using NuGet.Frameworks;
+
+namespace Microsoft.DotNet.Tools.Test
+{
+ public class DotnetTestRunnerFactory : IDotnetTestRunnerFactory
+ {
+ private readonly DotnetTestRunnerResolverFactory _dotnetTestRunnerResolverFactory;
+
+ public DotnetTestRunnerFactory(DotnetTestRunnerResolverFactory dotnetTestRunnerResolverFactory)
+ {
+ _dotnetTestRunnerResolverFactory = dotnetTestRunnerResolverFactory;
+ }
+
+ public IDotnetTestRunner Create(DotnetTestParams dotnetTestParams)
+ {
+ Func nextTestRunner =
+ (commandFactory, assemblyUnderTest, framework) =>
+ {
+ var dotnetTestRunnerResolver = _dotnetTestRunnerResolverFactory.Create(dotnetTestParams);
+
+ IDotnetTestRunner testRunner =
+ new ConsoleTestRunner(dotnetTestRunnerResolver, commandFactory, assemblyUnderTest, framework);
+ if (dotnetTestParams.Port.HasValue)
+ {
+ testRunner = new DesignTimeRunner(dotnetTestRunnerResolver, commandFactory, assemblyUnderTest);
+ }
+
+ return testRunner;
+ };
+
+ return dotnetTestParams.IsTestingAssembly
+ ? CreateTestRunnerForAssembly(nextTestRunner)
+ : CreateTestRunnerForProjectJson(nextTestRunner);
+ }
+
+ private static IDotnetTestRunner CreateTestRunnerForAssembly(
+ Func nextTestRunner)
+ {
+ Func nextAssemblyTestRunner =
+ (commandFactory, assemblyUnderTest) => nextTestRunner(commandFactory, assemblyUnderTest, null);
+
+ return new AssemblyTestRunnerDecorator(nextAssemblyTestRunner);
+ }
+
+ private static IDotnetTestRunner CreateTestRunnerForProjectJson(
+ Func nextTestRunner)
+ {
+ return new ProjectJsonTestRunnerDecorator(nextTestRunner);
+ }
+ }
+}
diff --git a/src/dotnet/commands/dotnet-test/DotnetTestState.cs b/src/Microsoft.DotNet.Tools.Test/DotnetTestState.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/DotnetTestState.cs
rename to src/Microsoft.DotNet.Tools.Test/DotnetTestState.cs
diff --git a/src/dotnet/commands/dotnet-test/IDotnetTest.cs b/src/Microsoft.DotNet.Tools.Test/IDotnetTest.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/IDotnetTest.cs
rename to src/Microsoft.DotNet.Tools.Test/IDotnetTest.cs
diff --git a/src/dotnet/commands/dotnet-test/IDotnetTestRunner.cs b/src/Microsoft.DotNet.Tools.Test/IDotnetTestRunner.cs
similarity index 59%
rename from src/dotnet/commands/dotnet-test/IDotnetTestRunner.cs
rename to src/Microsoft.DotNet.Tools.Test/IDotnetTestRunner.cs
index 1466eb32d..2e40e335c 100644
--- a/src/dotnet/commands/dotnet-test/IDotnetTestRunner.cs
+++ b/src/Microsoft.DotNet.Tools.Test/IDotnetTestRunner.cs
@@ -1,13 +1,10 @@
// 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.ProjectModel;
-using Microsoft.DotNet.Cli.Utils;
-
namespace Microsoft.DotNet.Tools.Test
{
public interface IDotnetTestRunner
{
- int RunTests(ProjectContext projectContext, DotnetTestParams dotnetTestParams, BuildWorkspace workspace);
+ int RunTests(DotnetTestParams dotnetTestParams);
}
}
diff --git a/src/dotnet/commands/dotnet-test/IDotnetTestRunnerFactory.cs b/src/Microsoft.DotNet.Tools.Test/IDotnetTestRunnerFactory.cs
similarity index 80%
rename from src/dotnet/commands/dotnet-test/IDotnetTestRunnerFactory.cs
rename to src/Microsoft.DotNet.Tools.Test/IDotnetTestRunnerFactory.cs
index 8dfc9599f..ccb0dc47b 100644
--- a/src/dotnet/commands/dotnet-test/IDotnetTestRunnerFactory.cs
+++ b/src/Microsoft.DotNet.Tools.Test/IDotnetTestRunnerFactory.cs
@@ -5,6 +5,6 @@ namespace Microsoft.DotNet.Tools.Test
{
public interface IDotnetTestRunnerFactory
{
- IDotnetTestRunner Create(int? port);
+ IDotnetTestRunner Create(DotnetTestParams dotnetTestParams);
}
}
diff --git a/src/dotnet/commands/dotnet-test/ITestMessagesCollection.cs b/src/Microsoft.DotNet.Tools.Test/ITestMessagesCollection.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/ITestMessagesCollection.cs
rename to src/Microsoft.DotNet.Tools.Test/ITestMessagesCollection.cs
diff --git a/src/dotnet/commands/dotnet-test/MessageHandlers/GetTestRunnerProcessStartInfoMessageHandler.cs b/src/Microsoft.DotNet.Tools.Test/MessageHandlers/GetTestRunnerProcessStartInfoMessageHandler.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/MessageHandlers/GetTestRunnerProcessStartInfoMessageHandler.cs
rename to src/Microsoft.DotNet.Tools.Test/MessageHandlers/GetTestRunnerProcessStartInfoMessageHandler.cs
diff --git a/src/dotnet/commands/dotnet-test/MessageHandlers/IDotnetTestMessageHandler.cs b/src/Microsoft.DotNet.Tools.Test/MessageHandlers/IDotnetTestMessageHandler.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/MessageHandlers/IDotnetTestMessageHandler.cs
rename to src/Microsoft.DotNet.Tools.Test/MessageHandlers/IDotnetTestMessageHandler.cs
diff --git a/src/dotnet/commands/dotnet-test/MessageHandlers/TestDiscoveryStartMessageHandler.cs b/src/Microsoft.DotNet.Tools.Test/MessageHandlers/TestDiscoveryStartMessageHandler.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/MessageHandlers/TestDiscoveryStartMessageHandler.cs
rename to src/Microsoft.DotNet.Tools.Test/MessageHandlers/TestDiscoveryStartMessageHandler.cs
diff --git a/src/dotnet/commands/dotnet-test/MessageHandlers/TestMessageTypes.cs b/src/Microsoft.DotNet.Tools.Test/MessageHandlers/TestMessageTypes.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/MessageHandlers/TestMessageTypes.cs
rename to src/Microsoft.DotNet.Tools.Test/MessageHandlers/TestMessageTypes.cs
diff --git a/src/dotnet/commands/dotnet-test/MessageHandlers/TestRunnerResultMessageHandler.cs b/src/Microsoft.DotNet.Tools.Test/MessageHandlers/TestRunnerResultMessageHandler.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/MessageHandlers/TestRunnerResultMessageHandler.cs
rename to src/Microsoft.DotNet.Tools.Test/MessageHandlers/TestRunnerResultMessageHandler.cs
diff --git a/src/dotnet/commands/dotnet-test/MessageHandlers/TestRunnerTestCompletedMessageHandler.cs b/src/Microsoft.DotNet.Tools.Test/MessageHandlers/TestRunnerTestCompletedMessageHandler.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/MessageHandlers/TestRunnerTestCompletedMessageHandler.cs
rename to src/Microsoft.DotNet.Tools.Test/MessageHandlers/TestRunnerTestCompletedMessageHandler.cs
diff --git a/src/dotnet/commands/dotnet-test/MessageHandlers/TestRunnerTestFoundMessageHandler.cs b/src/Microsoft.DotNet.Tools.Test/MessageHandlers/TestRunnerTestFoundMessageHandler.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/MessageHandlers/TestRunnerTestFoundMessageHandler.cs
rename to src/Microsoft.DotNet.Tools.Test/MessageHandlers/TestRunnerTestFoundMessageHandler.cs
diff --git a/src/dotnet/commands/dotnet-test/MessageHandlers/TestRunnerTestResultMessageHandler.cs b/src/Microsoft.DotNet.Tools.Test/MessageHandlers/TestRunnerTestResultMessageHandler.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/MessageHandlers/TestRunnerTestResultMessageHandler.cs
rename to src/Microsoft.DotNet.Tools.Test/MessageHandlers/TestRunnerTestResultMessageHandler.cs
diff --git a/src/dotnet/commands/dotnet-test/MessageHandlers/TestRunnerTestStartedMessageHandler.cs b/src/Microsoft.DotNet.Tools.Test/MessageHandlers/TestRunnerTestStartedMessageHandler.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/MessageHandlers/TestRunnerTestStartedMessageHandler.cs
rename to src/Microsoft.DotNet.Tools.Test/MessageHandlers/TestRunnerTestStartedMessageHandler.cs
diff --git a/src/dotnet/commands/dotnet-test/MessageHandlers/TestRunnerWaitingCommandMessageHandler.cs b/src/Microsoft.DotNet.Tools.Test/MessageHandlers/TestRunnerWaitingCommandMessageHandler.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/MessageHandlers/TestRunnerWaitingCommandMessageHandler.cs
rename to src/Microsoft.DotNet.Tools.Test/MessageHandlers/TestRunnerWaitingCommandMessageHandler.cs
diff --git a/src/dotnet/commands/dotnet-test/MessageHandlers/TestSessionTerminateMessageHandler.cs b/src/Microsoft.DotNet.Tools.Test/MessageHandlers/TestSessionTerminateMessageHandler.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/MessageHandlers/TestSessionTerminateMessageHandler.cs
rename to src/Microsoft.DotNet.Tools.Test/MessageHandlers/TestSessionTerminateMessageHandler.cs
diff --git a/src/dotnet/commands/dotnet-test/MessageHandlers/UnknownMessageHandler.cs b/src/Microsoft.DotNet.Tools.Test/MessageHandlers/UnknownMessageHandler.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/MessageHandlers/UnknownMessageHandler.cs
rename to src/Microsoft.DotNet.Tools.Test/MessageHandlers/UnknownMessageHandler.cs
diff --git a/src/dotnet/commands/dotnet-test/MessageHandlers/VersionCheckMessageHandler.cs b/src/Microsoft.DotNet.Tools.Test/MessageHandlers/VersionCheckMessageHandler.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/MessageHandlers/VersionCheckMessageHandler.cs
rename to src/Microsoft.DotNet.Tools.Test/MessageHandlers/VersionCheckMessageHandler.cs
diff --git a/src/Microsoft.DotNet.Tools.Test/Microsoft.DotNet.Tools.Test.xproj b/src/Microsoft.DotNet.Tools.Test/Microsoft.DotNet.Tools.Test.xproj
new file mode 100644
index 000000000..0ead3698f
--- /dev/null
+++ b/src/Microsoft.DotNet.Tools.Test/Microsoft.DotNet.Tools.Test.xproj
@@ -0,0 +1,21 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+
+ 6D028154-5518-4A56-BAD6-938A90E5BCF6
+ dotnet_test_console
+ obj\$(MSBuildProjectName)
+ bin\$(MSBuildProjectName)\
+ v4.5.2
+
+
+
+ 2.0
+
+
+
diff --git a/src/Microsoft.DotNet.Tools.Test/ProjectJsonTestRunnerDecorator.cs b/src/Microsoft.DotNet.Tools.Test/ProjectJsonTestRunnerDecorator.cs
new file mode 100644
index 000000000..2d071fa59
--- /dev/null
+++ b/src/Microsoft.DotNet.Tools.Test/ProjectJsonTestRunnerDecorator.cs
@@ -0,0 +1,148 @@
+// 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.Cli.Utils;
+using Microsoft.DotNet.InternalAbstractions;
+using Microsoft.DotNet.ProjectModel;
+using System.Linq;
+using NuGet.Frameworks;
+
+namespace Microsoft.DotNet.Tools.Test
+{
+ public class ProjectJsonTestRunnerDecorator : IDotnetTestRunner
+ {
+ private readonly Func _nextRunner;
+ private readonly TestProjectBuilder _testProjectBuilder;
+
+ public ProjectJsonTestRunnerDecorator(
+ Func nextRunner)
+ {
+ _nextRunner = nextRunner;
+ _testProjectBuilder = new TestProjectBuilder();
+ }
+
+ public int RunTests(DotnetTestParams dotnetTestParams)
+ {
+ var projectPath = GetProjectPath(dotnetTestParams.ProjectOrAssemblyPath);
+ var runtimeIdentifiers = !string.IsNullOrEmpty(dotnetTestParams.Runtime)
+ ? new[] {dotnetTestParams.Runtime}
+ : RuntimeEnvironmentRidExtensions.GetAllCandidateRuntimeIdentifiers();
+ var exitCode = 0;
+
+ // Create a workspace
+ var workspace = new BuildWorkspace(ProjectReaderSettings.ReadFromEnvironment());
+
+ if (dotnetTestParams.Framework != null)
+ {
+ var projectContext = workspace.GetProjectContext(projectPath, dotnetTestParams.Framework);
+ if (projectContext == null)
+ {
+ Reporter.Error.WriteLine(
+ $"Project '{projectPath}' does not support framework: {dotnetTestParams.UnparsedFramework}");
+ return 1;
+ }
+ projectContext = workspace.GetRuntimeContext(projectContext, runtimeIdentifiers);
+
+ exitCode = RunTests(projectContext, dotnetTestParams);
+ }
+ else
+ {
+ var summary = new Summary();
+ var projectContexts = workspace.GetProjectContextCollection(projectPath)
+ .EnsureValid(projectPath)
+ .FrameworkOnlyContexts
+ .Select(c => workspace.GetRuntimeContext(c, runtimeIdentifiers))
+ .ToList();
+
+ // Execute for all TFMs the project targets.
+ foreach (var projectContext in projectContexts)
+ {
+ var result = RunTests(projectContext, dotnetTestParams);
+ if (result == 0)
+ {
+ summary.Passed++;
+ }
+ else
+ {
+ summary.Failed++;
+ if (exitCode == 0)
+ {
+ // If tests fail in more than one TFM, we'll have it use the result of the first one
+ // as the exit code.
+ exitCode = result;
+ }
+ }
+ }
+
+ summary.Print();
+ }
+
+ return exitCode;
+ }
+
+ private int RunTests(ProjectContext projectContext, DotnetTestParams dotnetTestParams)
+ {
+ var result = _testProjectBuilder.BuildTestProject(projectContext, dotnetTestParams);
+
+ if (result == 0)
+ {
+ var commandFactory =
+ new ProjectDependenciesCommandFactory(
+ projectContext.TargetFramework,
+ dotnetTestParams.Config,
+ dotnetTestParams.Output,
+ dotnetTestParams.BuildBasePath,
+ projectContext.ProjectDirectory);
+
+ var assemblyUnderTest = new AssemblyUnderTest(projectContext, dotnetTestParams);
+
+ var framework = projectContext.TargetFramework;
+
+ result = _nextRunner(commandFactory, assemblyUnderTest.Path, framework).RunTests(dotnetTestParams);
+ }
+
+ return result;
+ }
+
+ private static string GetProjectPath(string projectPath)
+ {
+ projectPath = projectPath ?? Directory.GetCurrentDirectory();
+
+ if (!projectPath.EndsWith(Project.FileName))
+ {
+ projectPath = Path.Combine(projectPath, Project.FileName);
+ }
+
+ if (!File.Exists(projectPath))
+ {
+ throw new InvalidOperationException($"{projectPath} does not exist.");
+ }
+
+ return projectPath;
+ }
+
+ private class Summary
+ {
+ public int Passed { get; set; }
+
+ public int Failed { get; set; }
+
+ private int Total => Passed + Failed;
+
+ public void Print()
+ {
+ var summaryMessage = $"SUMMARY: Total: {Total} targets, Passed: {Passed}, Failed: {Failed}.";
+ if (Failed > 0)
+ {
+ Reporter.Error.WriteLine(summaryMessage.Red());
+ }
+ else
+ {
+ Reporter.Output.WriteLine(summaryMessage);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.Tools.Test/Properties/AssemblyInfo.cs b/src/Microsoft.DotNet.Tools.Test/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..f0993d023
--- /dev/null
+++ b/src/Microsoft.DotNet.Tools.Test/Properties/AssemblyInfo.cs
@@ -0,0 +1,5 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: InternalsVisibleTo("dotnet-test.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100039ac461fa5c82c7dd2557400c4fd4e9dcdf7ac47e3d572548c04cd4673e004916610f4ea5cbf86f2b1ca1cb824f2a7b3976afecfcf4eb72d9a899aa6786effa10c30399e6580ed848231fec48374e41b3acf8811931343fc2f73acf72dae745adbcb7063cc4b50550618383202875223fc75401351cd89c44bf9b50e7fa3796")]
diff --git a/src/dotnet/commands/dotnet-test/README.md b/src/Microsoft.DotNet.Tools.Test/README.md
similarity index 83%
rename from src/dotnet/commands/dotnet-test/README.md
rename to src/Microsoft.DotNet.Tools.Test/README.md
index ab1d7cc27..a3b9dc64b 100644
--- a/src/dotnet/commands/dotnet-test/README.md
+++ b/src/Microsoft.DotNet.Tools.Test/README.md
@@ -8,20 +8,20 @@
## SYNOPSIS
-`dotnet test [--configuration]
+`dotnet test [--configuration]
[--output] [--build-base-path] [--framework] [--runtime]
[--no-build]
- [--parentProcessId] [--port]
- []`
+ [--parentProcessId] [--port]
+ []`
## DESCRIPTION
-The `dotnet test` command is used to execute unit tests in a given project. Unit tests are class library
-projects that have dependencies on the unit test framework (for example, NUnit or xUnit) and the
-dotnet test runner for that unit testing framework.
+The `dotnet test` command is used to execute unit tests in a given project. Unit tests are class library
+projects that have dependencies on the unit test framework (for example, NUnit or xUnit) and the
+dotnet test runner for that unit testing framework.
These are packaged as NuGet packages and are restored as ordinary dependencies for the project.
-Test projects also need to specify a test runner property in project.json using the "testRunner" node.
+Test projects also need to specify a test runner property in project.json using the "testRunner" node.
This value should contain the name of the unit test framework.
The following sample project.json shows the properties needed:
@@ -53,17 +53,17 @@ The following sample project.json shows the properties needed:
`dotnet test` supports two running modes:
1. Console: In console mode, `dotnet test` simply executes fully any command gets passed to it and outputs the results. Anytime you invoke `dotnet test` without passing --port, it runs in console mode, which in turn will cause the runner to run in console mode.
-2. Design time: used in the context of other tools, such as editors or Integrated Development Environments (IDEs). You can find out more about this mode in the [dotnet-test protocol](../../../../Documentation/dotnet-test-protocol.md) document.
+2. Design time: used in the context of other tools, such as editors or Integrated Development Environments (IDEs). You can find out more about this mode in the [dotnet-test protocol](../../../../Documentation/dotnet-test-protocol.md) document.
## OPTIONS
`[project]`
-
-Specifies a path to the test project. If omitted, it defaults to current directory.
+
+Specifies a path to the test project. If omitted, it defaults to current directory.
`-c`, `--configuration` [Debug|Release]
-Configuration under which to build. The default value is Release.
+Configuration under which to build. The default value is Release.
`-o`, `--output` [DIR]
@@ -81,9 +81,9 @@ Looks for test binaries for a specific framework.
Look for test binaries for a for the specified runtime.
-`--no-build`
+`--no-build`
-Does not build the test project prior to running it.
+Does not build the test project prior to running it.
--parentProcessId
@@ -97,8 +97,8 @@ Used by IDEs to specify a port number to listen for a connection.
`dotnet test`
-Runs the tests in the project in the current directory.
+Runs the tests in the project in the current directory.
`dotnet test /projects/test1/project.json`
-Runs the tests in the test1 project.
+Runs the tests in the test1 project.
diff --git a/src/dotnet/commands/dotnet-test/ReportingChannels/AdapterReportingChannel.cs b/src/Microsoft.DotNet.Tools.Test/ReportingChannels/AdapterReportingChannel.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/ReportingChannels/AdapterReportingChannel.cs
rename to src/Microsoft.DotNet.Tools.Test/ReportingChannels/AdapterReportingChannel.cs
diff --git a/src/dotnet/commands/dotnet-test/ReportingChannels/IReportingChannel.cs b/src/Microsoft.DotNet.Tools.Test/ReportingChannels/IReportingChannel.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/ReportingChannels/IReportingChannel.cs
rename to src/Microsoft.DotNet.Tools.Test/ReportingChannels/IReportingChannel.cs
diff --git a/src/dotnet/commands/dotnet-test/ReportingChannels/IReportingChannelFactory.cs b/src/Microsoft.DotNet.Tools.Test/ReportingChannels/IReportingChannelFactory.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/ReportingChannels/IReportingChannelFactory.cs
rename to src/Microsoft.DotNet.Tools.Test/ReportingChannels/IReportingChannelFactory.cs
diff --git a/src/dotnet/commands/dotnet-test/ReportingChannels/ReportingChannel.cs b/src/Microsoft.DotNet.Tools.Test/ReportingChannels/ReportingChannel.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/ReportingChannels/ReportingChannel.cs
rename to src/Microsoft.DotNet.Tools.Test/ReportingChannels/ReportingChannel.cs
diff --git a/src/dotnet/commands/dotnet-test/ReportingChannels/ReportingChannelFactory.cs b/src/Microsoft.DotNet.Tools.Test/ReportingChannels/ReportingChannelFactory.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/ReportingChannels/ReportingChannelFactory.cs
rename to src/Microsoft.DotNet.Tools.Test/ReportingChannels/ReportingChannelFactory.cs
diff --git a/src/dotnet/commands/dotnet-test/ReportingChannels/TestRunnerReportingChannel.cs b/src/Microsoft.DotNet.Tools.Test/ReportingChannels/TestRunnerReportingChannel.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/ReportingChannels/TestRunnerReportingChannel.cs
rename to src/Microsoft.DotNet.Tools.Test/ReportingChannels/TestRunnerReportingChannel.cs
diff --git a/src/Microsoft.DotNet.Tools.Test/TestCommand.cs b/src/Microsoft.DotNet.Tools.Test/TestCommand.cs
new file mode 100644
index 000000000..8d40829a0
--- /dev/null
+++ b/src/Microsoft.DotNet.Tools.Test/TestCommand.cs
@@ -0,0 +1,100 @@
+// 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;
+using System.IO;
+using System.Linq;
+using Microsoft.DotNet.Cli.Utils;
+using Microsoft.DotNet.InternalAbstractions;
+using Microsoft.DotNet.ProjectModel;
+
+namespace Microsoft.DotNet.Tools.Test
+{
+ public class TestCommand
+ {
+ private readonly IDotnetTestRunnerFactory _dotnetTestRunnerFactory;
+
+ public static int Run(string[] args)
+ {
+ var dotnetTestRunnerResolverFactory = new DotnetTestRunnerResolverFactory(new ProjectReader());
+ var testCommand = new TestCommand(new DotnetTestRunnerFactory(dotnetTestRunnerResolverFactory));
+
+ return testCommand.DoRun(args);
+ }
+
+ public TestCommand(IDotnetTestRunnerFactory testRunnerFactory)
+ {
+ _dotnetTestRunnerFactory = testRunnerFactory;
+ }
+
+ public int DoRun(string[] args)
+ {
+ DebugHelper.HandleDebugSwitch(ref args);
+
+ var dotnetTestParams = new DotnetTestParams();
+
+ try
+ {
+ dotnetTestParams.Parse(args);
+
+ if (dotnetTestParams.Help)
+ {
+ return 0;
+ }
+
+ // Register for parent process's exit event
+ if (dotnetTestParams.ParentProcessId.HasValue)
+ {
+ RegisterForParentProcessExit(dotnetTestParams.ParentProcessId.Value);
+ }
+
+ return RunTest(dotnetTestParams);
+ }
+ catch (InvalidOperationException ex)
+ {
+ TestHostTracing.Source.TraceEvent(TraceEventType.Error, 0, ex.ToString());
+ return -1;
+ }
+ catch (Exception ex) when (!(ex is GracefulException))
+ {
+ Console.WriteLine(ex.ToString());
+ TestHostTracing.Source.TraceEvent(TraceEventType.Error, 0, ex.ToString());
+ return -2;
+ }
+ }
+
+ private static void RegisterForParentProcessExit(int id)
+ {
+ var parentProcess = Process.GetProcesses().FirstOrDefault(p => p.Id == id);
+
+ if (parentProcess != null)
+ {
+ parentProcess.EnableRaisingEvents = true;
+ parentProcess.Exited += (sender, eventArgs) =>
+ {
+ TestHostTracing.Source.TraceEvent(
+ TraceEventType.Information,
+ 0,
+ "Killing the current process as parent process has exited.");
+
+ Process.GetCurrentProcess().Kill();
+ };
+ }
+ else
+ {
+ TestHostTracing.Source.TraceEvent(
+ TraceEventType.Information,
+ 0,
+ "Failed to register for parent process's exit event. " +
+ $"Parent process with id '{id}' was not found.");
+ }
+ }
+
+ private int RunTest(DotnetTestParams dotnetTestParams)
+ {
+ var dotnetTestRunner = _dotnetTestRunnerFactory.Create(dotnetTestParams);
+ return dotnetTestRunner.RunTests(dotnetTestParams);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/dotnet/commands/dotnet-test/TestHostTracing.cs b/src/Microsoft.DotNet.Tools.Test/TestHostTracing.cs
similarity index 95%
rename from src/dotnet/commands/dotnet-test/TestHostTracing.cs
rename to src/Microsoft.DotNet.Tools.Test/TestHostTracing.cs
index 65d9a440c..44299586b 100644
--- a/src/dotnet/commands/dotnet-test/TestHostTracing.cs
+++ b/src/Microsoft.DotNet.Tools.Test/TestHostTracing.cs
@@ -14,8 +14,8 @@ namespace Microsoft.DotNet.Tools.Test
static TestHostTracing()
{
- Source = Environment.GetEnvironmentVariable(TracingEnvironmentVariable) == "1"
- ? new TraceSource("dotnet-test", SourceLevels.Verbose)
+ Source = Environment.GetEnvironmentVariable(TracingEnvironmentVariable) == "1"
+ ? new TraceSource("dotnet-test", SourceLevels.Verbose)
: new TraceSource("dotnet-test", SourceLevels.Warning);
Source.Listeners.Add(new TextWriterTraceListener(Console.Error));
diff --git a/src/dotnet/commands/dotnet-test/TestMessagesCollection.cs b/src/Microsoft.DotNet.Tools.Test/TestMessagesCollection.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/TestMessagesCollection.cs
rename to src/Microsoft.DotNet.Tools.Test/TestMessagesCollection.cs
diff --git a/src/Microsoft.DotNet.Tools.Test/TestProjectBuilder.cs b/src/Microsoft.DotNet.Tools.Test/TestProjectBuilder.cs
new file mode 100644
index 000000000..ffaafbf70
--- /dev/null
+++ b/src/Microsoft.DotNet.Tools.Test/TestProjectBuilder.cs
@@ -0,0 +1,52 @@
+// 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.Collections.Generic;
+using Microsoft.DotNet.Cli.Utils;
+using Microsoft.DotNet.ProjectModel;
+
+namespace Microsoft.DotNet.Tools.Test
+{
+ public class TestProjectBuilder
+ {
+ public int BuildTestProject(ProjectContext projectContext, DotnetTestParams dotnetTestParams)
+ {
+ return dotnetTestParams.NoBuild ? 0 : DoBuildTestProject(projectContext, dotnetTestParams);
+ }
+
+ private int DoBuildTestProject(ProjectContext projectContext, DotnetTestParams dotnetTestParams)
+ {
+ var strings = new List
+ {
+ $"{dotnetTestParams.ProjectOrAssemblyPath}",
+ $"--configuration", dotnetTestParams.Config,
+ "--framework", projectContext.TargetFramework.ToString()
+ };
+
+ // Build the test specifically for the target framework \ rid of the ProjectContext.
+ // This avoids building the project for tfms that the user did not request.
+
+ if (!string.IsNullOrEmpty(dotnetTestParams.BuildBasePath))
+ {
+ strings.Add("--build-base-path");
+ strings.Add(dotnetTestParams.BuildBasePath);
+ }
+
+ if (!string.IsNullOrEmpty(dotnetTestParams.Output))
+ {
+ strings.Add("--output");
+ strings.Add(dotnetTestParams.Output);
+ }
+
+ if (!string.IsNullOrEmpty(projectContext.RuntimeIdentifier))
+ {
+ strings.Add("--runtime");
+ strings.Add(projectContext.RuntimeIdentifier);
+ }
+
+ var result = Command.CreateDotNet("build", strings).Execute().ExitCode;
+
+ return result;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Microsoft.DotNet.Tools.Test/TestRunners/AssemblyTestRunnerNameResolver.cs b/src/Microsoft.DotNet.Tools.Test/TestRunners/AssemblyTestRunnerNameResolver.cs
new file mode 100644
index 000000000..0b006f1a6
--- /dev/null
+++ b/src/Microsoft.DotNet.Tools.Test/TestRunners/AssemblyTestRunnerNameResolver.cs
@@ -0,0 +1,34 @@
+// 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.IO;
+using System.Linq;
+using Microsoft.Extensions.EnvironmentAbstractions;
+
+namespace Microsoft.DotNet.Tools.Test
+{
+ public class AssemblyTestRunnerNameResolver : ITestRunnerNameResolver
+ {
+ private readonly string _directoryOfAssemblyUnderTest;
+
+ private readonly IDirectory _directory;
+
+ public AssemblyTestRunnerNameResolver(string assemblyUnderTest) :
+ this(assemblyUnderTest, FileSystemWrapper.Default.Directory)
+ {
+ }
+
+ internal AssemblyTestRunnerNameResolver(string assemblyUnderTest, IDirectory directory)
+ {
+ _directoryOfAssemblyUnderTest = directory.GetDirectoryFullName(assemblyUnderTest);
+ _directory = directory;
+ }
+
+ public string ResolveTestRunner()
+ {
+ var testRunnerPath = _directory.GetFiles(_directoryOfAssemblyUnderTest, "dotnet-test-*").FirstOrDefault();
+
+ return Path.GetFileNameWithoutExtension(testRunnerPath);
+ }
+ }
+}
diff --git a/src/dotnet/commands/dotnet-test/TestRunners/DiscoverTestsArgumentsBuilder.cs b/src/Microsoft.DotNet.Tools.Test/TestRunners/DiscoverTestsArgumentsBuilder.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/TestRunners/DiscoverTestsArgumentsBuilder.cs
rename to src/Microsoft.DotNet.Tools.Test/TestRunners/DiscoverTestsArgumentsBuilder.cs
diff --git a/src/Microsoft.DotNet.Tools.Test/TestRunners/DotnetTestRunnerResolverFactory.cs b/src/Microsoft.DotNet.Tools.Test/TestRunners/DotnetTestRunnerResolverFactory.cs
new file mode 100644
index 000000000..efe9cc877
--- /dev/null
+++ b/src/Microsoft.DotNet.Tools.Test/TestRunners/DotnetTestRunnerResolverFactory.cs
@@ -0,0 +1,48 @@
+// 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.IO;
+using Microsoft.DotNet.ProjectModel;
+
+namespace Microsoft.DotNet.Tools.Test
+{
+ public class DotnetTestRunnerResolverFactory
+ {
+ private readonly IProjectReader _projectReader;
+
+ public DotnetTestRunnerResolverFactory(IProjectReader projectReader)
+ {
+ _projectReader = projectReader;
+ }
+
+ public ITestRunnerNameResolver Create(DotnetTestParams dotnetTestParams)
+ {
+ var testRunnerResolver = dotnetTestParams.IsTestingAssembly ?
+ GetAssemblyTestRunnerResolver(dotnetTestParams) :
+ GetProjectJsonTestRunnerResolver(dotnetTestParams);
+
+ return testRunnerResolver;
+ }
+
+ private ITestRunnerNameResolver GetAssemblyTestRunnerResolver(DotnetTestParams dotnetTestParams)
+ {
+ ITestRunnerNameResolver testRunnerNameResolver = null;
+ if (dotnetTestParams.HasTestRunner)
+ {
+ testRunnerNameResolver = new ParameterTestRunnerNameResolver(dotnetTestParams.TestRunner);
+ }
+ else
+ {
+ testRunnerNameResolver = new AssemblyTestRunnerNameResolver(dotnetTestParams.ProjectOrAssemblyPath);
+ }
+
+ return testRunnerNameResolver;
+ }
+
+ private ITestRunnerNameResolver GetProjectJsonTestRunnerResolver(DotnetTestParams dotnetTestParams)
+ {
+ var project = _projectReader.ReadProject(dotnetTestParams.ProjectOrAssemblyPath);
+ return new ProjectJsonTestRunnerNameResolver(project);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/dotnet/commands/dotnet-test/TestRunners/ITestRunner.cs b/src/Microsoft.DotNet.Tools.Test/TestRunners/ITestRunner.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/TestRunners/ITestRunner.cs
rename to src/Microsoft.DotNet.Tools.Test/TestRunners/ITestRunner.cs
diff --git a/src/dotnet/commands/dotnet-test/TestRunners/ITestRunnerArgumentsBuilder.cs b/src/Microsoft.DotNet.Tools.Test/TestRunners/ITestRunnerArgumentsBuilder.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/TestRunners/ITestRunnerArgumentsBuilder.cs
rename to src/Microsoft.DotNet.Tools.Test/TestRunners/ITestRunnerArgumentsBuilder.cs
diff --git a/src/dotnet/commands/dotnet-test/TestRunners/ITestRunnerFactory.cs b/src/Microsoft.DotNet.Tools.Test/TestRunners/ITestRunnerFactory.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/TestRunners/ITestRunnerFactory.cs
rename to src/Microsoft.DotNet.Tools.Test/TestRunners/ITestRunnerFactory.cs
diff --git a/src/Microsoft.DotNet.Tools.Test/TestRunners/ITestRunnerNameResolver.cs b/src/Microsoft.DotNet.Tools.Test/TestRunners/ITestRunnerNameResolver.cs
new file mode 100644
index 000000000..aa0d94243
--- /dev/null
+++ b/src/Microsoft.DotNet.Tools.Test/TestRunners/ITestRunnerNameResolver.cs
@@ -0,0 +1,10 @@
+// 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.
+
+namespace Microsoft.DotNet.Tools.Test
+{
+ public interface ITestRunnerNameResolver
+ {
+ string ResolveTestRunner();
+ }
+}
diff --git a/src/Microsoft.DotNet.Tools.Test/TestRunners/ParameterTestRunnerNameResolver.cs b/src/Microsoft.DotNet.Tools.Test/TestRunners/ParameterTestRunnerNameResolver.cs
new file mode 100644
index 000000000..7a393f0b8
--- /dev/null
+++ b/src/Microsoft.DotNet.Tools.Test/TestRunners/ParameterTestRunnerNameResolver.cs
@@ -0,0 +1,20 @@
+// 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.
+
+namespace Microsoft.DotNet.Tools.Test
+{
+ public class ParameterTestRunnerNameResolver : ITestRunnerNameResolver
+ {
+ private readonly string _testRunner;
+
+ public ParameterTestRunnerNameResolver(string testRunner)
+ {
+ _testRunner = testRunner;
+ }
+
+ public string ResolveTestRunner()
+ {
+ return $"dotnet-test-{_testRunner}";
+ }
+ }
+}
diff --git a/src/Microsoft.DotNet.Tools.Test/TestRunners/ProjectJsonTestRunnerNameResolver.cs b/src/Microsoft.DotNet.Tools.Test/TestRunners/ProjectJsonTestRunnerNameResolver.cs
new file mode 100644
index 000000000..2de3784c7
--- /dev/null
+++ b/src/Microsoft.DotNet.Tools.Test/TestRunners/ProjectJsonTestRunnerNameResolver.cs
@@ -0,0 +1,22 @@
+// 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.ProjectModel;
+
+namespace Microsoft.DotNet.Tools.Test
+{
+ public class ProjectJsonTestRunnerNameResolver : ITestRunnerNameResolver
+ {
+ private Project _project;
+
+ public ProjectJsonTestRunnerNameResolver(Project project)
+ {
+ _project = project;
+ }
+
+ public string ResolveTestRunner()
+ {
+ return string.IsNullOrEmpty(_project.TestRunner) ? null : $"dotnet-test-{_project.TestRunner}";
+ }
+ }
+}
diff --git a/src/dotnet/commands/dotnet-test/TestRunners/RunTestsArgumentsBuilder.cs b/src/Microsoft.DotNet.Tools.Test/TestRunners/RunTestsArgumentsBuilder.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/TestRunners/RunTestsArgumentsBuilder.cs
rename to src/Microsoft.DotNet.Tools.Test/TestRunners/RunTestsArgumentsBuilder.cs
diff --git a/src/dotnet/commands/dotnet-test/TestRunners/TestRunner.cs b/src/Microsoft.DotNet.Tools.Test/TestRunners/TestRunner.cs
similarity index 97%
rename from src/dotnet/commands/dotnet-test/TestRunners/TestRunner.cs
rename to src/Microsoft.DotNet.Tools.Test/TestRunners/TestRunner.cs
index 2ca95b678..6ef3474d5 100644
--- a/src/dotnet/commands/dotnet-test/TestRunners/TestRunner.cs
+++ b/src/Microsoft.DotNet.Tools.Test/TestRunners/TestRunner.cs
@@ -51,7 +51,7 @@ namespace Microsoft.DotNet.Tools.Test
var commandArgs = _argumentsBuilder.BuildArguments();
return _commandFactory.Create(
- $"dotnet-{_testRunner}",
+ $"{_testRunner}",
commandArgs,
null,
null);
diff --git a/src/dotnet/commands/dotnet-test/TestRunners/TestRunnerFactory.cs b/src/Microsoft.DotNet.Tools.Test/TestRunners/TestRunnerFactory.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/TestRunners/TestRunnerFactory.cs
rename to src/Microsoft.DotNet.Tools.Test/TestRunners/TestRunnerFactory.cs
diff --git a/src/dotnet/commands/dotnet-test/TestRunners/TestRunnerOperationFailedException.cs b/src/Microsoft.DotNet.Tools.Test/TestRunners/TestRunnerOperationFailedException.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/TestRunners/TestRunnerOperationFailedException.cs
rename to src/Microsoft.DotNet.Tools.Test/TestRunners/TestRunnerOperationFailedException.cs
diff --git a/src/dotnet/commands/dotnet-test/TestStartInfo.cs b/src/Microsoft.DotNet.Tools.Test/TestStartInfo.cs
similarity index 100%
rename from src/dotnet/commands/dotnet-test/TestStartInfo.cs
rename to src/Microsoft.DotNet.Tools.Test/TestStartInfo.cs
diff --git a/src/Microsoft.DotNet.Tools.Test/project.json b/src/Microsoft.DotNet.Tools.Test/project.json
new file mode 100644
index 000000000..ce9cf878e
--- /dev/null
+++ b/src/Microsoft.DotNet.Tools.Test/project.json
@@ -0,0 +1,38 @@
+{
+ "version": "1.0.0-featmsbuild-*",
+ "buildOptions": {
+ "keyFile": "../../tools/Key.snk",
+ "compile": {
+ "include": [
+ "**/*.cs",
+ "../dotnet/CommandLine/*.cs"
+ ]
+ }
+ },
+
+ "dependencies": {
+ "System.Diagnostics.TraceSource": "4.0.0",
+ "System.Diagnostics.TextWriterTraceListener": "4.0.0",
+ "Microsoft.DotNet.Cli.Utils": {
+ "target": "project"
+ },
+ "Microsoft.DotNet.ProjectModel": {
+ "target": "project"
+ },
+ "Microsoft.Extensions.Testing.Abstractions": {
+ "target": "project"
+ },
+ "Microsoft.DotNet.InternalAbstractions": {
+ "target": "project"
+ },
+ "Microsoft.DotNet.PlatformAbstractions": "1.0.1-beta-000919"
+ },
+
+ "frameworks": {
+ "netstandard1.6": {
+ "imports": [
+ "portable-net45+wp80+win8+wpa81+dnxcore50"
+ ]
+ }
+ }
+}
diff --git a/src/Microsoft.Extensions.Testing.Abstractions/Properties/AssemblyInfo.cs b/src/Microsoft.Extensions.Testing.Abstractions/Properties/AssemblyInfo.cs
index cdbb8074c..722c59c6b 100644
--- a/src/Microsoft.Extensions.Testing.Abstractions/Properties/AssemblyInfo.cs
+++ b/src/Microsoft.Extensions.Testing.Abstractions/Properties/AssemblyInfo.cs
@@ -5,4 +5,4 @@ using System.Reflection;
using System.Resources;
[assembly: AssemblyMetadata("Serviceable", "True")]
-[assembly: NeutralResourcesLanguage("en-us")]
\ No newline at end of file
+[assembly: NeutralResourcesLanguage("en-us")]
diff --git a/src/dotnet/commands/dotnet-test/BaseDotnetTestRunner.cs b/src/dotnet/commands/dotnet-test/BaseDotnetTestRunner.cs
deleted file mode 100644
index 64b2069ec..000000000
--- a/src/dotnet/commands/dotnet-test/BaseDotnetTestRunner.cs
+++ /dev/null
@@ -1,67 +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.Collections.Generic;
-using Microsoft.DotNet.ProjectModel;
-
-namespace Microsoft.DotNet.Tools.Test
-{
- public abstract class BaseDotnetTestRunner : IDotnetTestRunner
- {
- public int RunTests(ProjectContext projectContext, DotnetTestParams dotnetTestParams, BuildWorkspace workspace)
- {
- var result = BuildTestProject(projectContext, dotnetTestParams, workspace);
-
- return result == 0 ? DoRunTests(projectContext, dotnetTestParams) : result;
- }
-
- internal abstract int DoRunTests(ProjectContext projectContext, DotnetTestParams dotnetTestParams);
-
- private int BuildTestProject(ProjectContext projectContext, DotnetTestParams dotnetTestParams, BuildWorkspace workspace)
- {
- if (dotnetTestParams.NoBuild)
- {
- return 0;
- }
-
- return DoBuildTestProject(projectContext, dotnetTestParams, workspace);
- }
-
- private int DoBuildTestProject(ProjectContext projectContext, DotnetTestParams dotnetTestParams, BuildWorkspace workspace)
- {
- var strings = new List
- {
- $"--configuration",
- dotnetTestParams.Config,
- $"{dotnetTestParams.ProjectPath}"
- };
-
- // Build the test specifically for the target framework \ rid of the ProjectContext. This avoids building the project
- // for tfms that the user did not request.
- strings.Add("--framework");
- strings.Add(projectContext.TargetFramework.ToString());
-
- if (!string.IsNullOrEmpty(dotnetTestParams.BuildBasePath))
- {
- strings.Add("--build-base-path");
- strings.Add(dotnetTestParams.BuildBasePath);
- }
-
- if (!string.IsNullOrEmpty(dotnetTestParams.Output))
- {
- strings.Add("--output");
- strings.Add(dotnetTestParams.Output);
- }
-
- if (!string.IsNullOrEmpty(projectContext.RuntimeIdentifier))
- {
- strings.Add("--runtime");
- strings.Add(projectContext.RuntimeIdentifier);
- }
-
- var result = Build.BuildCommand.Run(strings.ToArray(), workspace);
-
- return result;
- }
- }
-}
diff --git a/src/dotnet/commands/dotnet-test/ConsoleTestRunner.cs b/src/dotnet/commands/dotnet-test/ConsoleTestRunner.cs
deleted file mode 100644
index 9277afe18..000000000
--- a/src/dotnet/commands/dotnet-test/ConsoleTestRunner.cs
+++ /dev/null
@@ -1,48 +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.Collections.Generic;
-using Microsoft.DotNet.Cli.Utils;
-using Microsoft.DotNet.ProjectModel;
-
-namespace Microsoft.DotNet.Tools.Test
-{
- public class ConsoleTestRunner : BaseDotnetTestRunner
- {
- internal override int DoRunTests(ProjectContext projectContext, DotnetTestParams dotnetTestParams)
- {
- var commandFactory =
- new ProjectDependenciesCommandFactory(
- projectContext.TargetFramework,
- dotnetTestParams.Config,
- dotnetTestParams.Output,
- dotnetTestParams.BuildBasePath,
- projectContext.ProjectDirectory);
-
- return commandFactory.Create(
- GetCommandName(projectContext.ProjectFile.TestRunner),
- GetCommandArgs(projectContext, dotnetTestParams),
- projectContext.TargetFramework,
- dotnetTestParams.Config)
- .Execute()
- .ExitCode;
- }
-
- private IEnumerable GetCommandArgs(ProjectContext projectContext, DotnetTestParams dotnetTestParams)
- {
- var commandArgs = new List
- {
- new AssemblyUnderTest(projectContext, dotnetTestParams).Path
- };
-
- commandArgs.AddRange(dotnetTestParams.RemainingArguments);
-
- return commandArgs;
- }
-
- private static string GetCommandName(string testRunner)
- {
- return $"dotnet-test-{testRunner}";
- }
- }
-}
diff --git a/src/dotnet/commands/dotnet-test/DotnetTestRunnerFactory.cs b/src/dotnet/commands/dotnet-test/DotnetTestRunnerFactory.cs
deleted file mode 100644
index 32ef694ec..000000000
--- a/src/dotnet/commands/dotnet-test/DotnetTestRunnerFactory.cs
+++ /dev/null
@@ -1,19 +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.
-
-namespace Microsoft.DotNet.Tools.Test
-{
- public class DotnetTestRunnerFactory : IDotnetTestRunnerFactory
- {
- public IDotnetTestRunner Create(int? port)
- {
- IDotnetTestRunner dotnetTestRunner = new ConsoleTestRunner();
- if (port.HasValue)
- {
- dotnetTestRunner = new DesignTimeRunner();
- }
-
- return dotnetTestRunner;
- }
- }
-}
diff --git a/src/dotnet/commands/dotnet-test/Program.cs b/src/dotnet/commands/dotnet-test/Program.cs
deleted file mode 100644
index 43a7e81bd..000000000
--- a/src/dotnet/commands/dotnet-test/Program.cs
+++ /dev/null
@@ -1,191 +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.Diagnostics;
-using System.IO;
-using System.Linq;
-using Microsoft.DotNet.Cli.Utils;
-using Microsoft.DotNet.InternalAbstractions;
-using Microsoft.DotNet.ProjectModel;
-
-namespace Microsoft.DotNet.Tools.Test
-{
- public class TestCommand
- {
- private readonly IDotnetTestRunnerFactory _dotnetTestRunnerFactory;
-
- public TestCommand(IDotnetTestRunnerFactory testRunnerFactory)
- {
- _dotnetTestRunnerFactory = testRunnerFactory;
- }
-
- public int DoRun(string[] args)
- {
- DebugHelper.HandleDebugSwitch(ref args);
-
- var dotnetTestParams = new DotnetTestParams();
-
- try
- {
- dotnetTestParams.Parse(args);
-
- if (dotnetTestParams.Help)
- {
- return 0;
- }
-
- // Register for parent process's exit event
- if (dotnetTestParams.ParentProcessId.HasValue)
- {
- RegisterForParentProcessExit(dotnetTestParams.ParentProcessId.Value);
- }
-
- var projectPath = GetProjectPath(dotnetTestParams.ProjectPath);
- var runtimeIdentifiers = !string.IsNullOrEmpty(dotnetTestParams.Runtime) ?
- new[] { dotnetTestParams.Runtime } :
- RuntimeEnvironmentRidExtensions.GetAllCandidateRuntimeIdentifiers();
- var exitCode = 0;
-
- // Create a workspace
- var workspace = new BuildWorkspace(ProjectReaderSettings.ReadFromEnvironment());
-
- if (dotnetTestParams.Framework != null)
- {
- var projectContext = workspace.GetProjectContext(projectPath, dotnetTestParams.Framework);
- if (projectContext == null)
- {
- Reporter.Error.WriteLine($"Project '{projectPath}' does not support framework: {dotnetTestParams.UnparsedFramework}");
- return 1;
- }
- projectContext = workspace.GetRuntimeContext(projectContext, runtimeIdentifiers);
-
- exitCode = RunTest(projectContext, dotnetTestParams, workspace);
- }
- else
- {
- var summary = new Summary();
- var projectContexts = workspace.GetProjectContextCollection(projectPath)
- .EnsureValid(projectPath)
- .FrameworkOnlyContexts
- .Select(c => workspace.GetRuntimeContext(c, runtimeIdentifiers))
- .ToList();
-
- // Execute for all TFMs the project targets.
- foreach (var projectContext in projectContexts)
- {
- var result = RunTest(projectContext, dotnetTestParams, workspace);
- if (result == 0)
- {
- summary.Passed++;
- }
- else
- {
- summary.Failed++;
- if (exitCode == 0)
- {
- // If tests fail in more than one TFM, we'll have it use the result of the first one
- // as the exit code.
- exitCode = result;
- }
- }
- }
-
- summary.Print();
- }
-
- return exitCode;
- }
- catch (InvalidOperationException ex)
- {
- TestHostTracing.Source.TraceEvent(TraceEventType.Error, 0, ex.ToString());
- return -1;
- }
- catch (Exception ex) when (!(ex is GracefulException))
- {
- TestHostTracing.Source.TraceEvent(TraceEventType.Error, 0, ex.ToString());
- return -2;
- }
- }
-
- public static int Run(string[] args)
- {
- var testCommand = new TestCommand(new DotnetTestRunnerFactory());
-
- return testCommand.DoRun(args);
- }
-
- private static void RegisterForParentProcessExit(int id)
- {
- var parentProcess = Process.GetProcesses().FirstOrDefault(p => p.Id == id);
-
- if (parentProcess != null)
- {
- parentProcess.EnableRaisingEvents = true;
- parentProcess.Exited += (sender, eventArgs) =>
- {
- TestHostTracing.Source.TraceEvent(
- TraceEventType.Information,
- 0,
- "Killing the current process as parent process has exited.");
-
- Process.GetCurrentProcess().Kill();
- };
- }
- else
- {
- TestHostTracing.Source.TraceEvent(
- TraceEventType.Information,
- 0,
- "Failed to register for parent process's exit event. " +
- $"Parent process with id '{id}' was not found.");
- }
- }
-
- private int RunTest(ProjectContext projectContext, DotnetTestParams dotnetTestParams, BuildWorkspace workspace)
- {
- var testRunner = projectContext.ProjectFile.TestRunner;
- var dotnetTestRunner = _dotnetTestRunnerFactory.Create(dotnetTestParams.Port);
- return dotnetTestRunner.RunTests(projectContext, dotnetTestParams, workspace);
- }
-
- private static string GetProjectPath(string projectPath)
- {
- projectPath = projectPath ?? Directory.GetCurrentDirectory();
-
- if (!projectPath.EndsWith(Project.FileName))
- {
- projectPath = Path.Combine(projectPath, Project.FileName);
- }
-
- if (!File.Exists(projectPath))
- {
- throw new InvalidOperationException($"{projectPath} does not exist.");
- }
-
- return projectPath;
- }
-
- private class Summary
- {
- public int Passed { get; set; }
-
- public int Failed { get; set; }
-
- public int Total => Passed + Failed;
-
- public void Print()
- {
- var summaryMessage = $"SUMMARY: Total: {Total} targets, Passed: {Passed}, Failed: {Failed}.";
- if (Failed > 0)
- {
- Reporter.Error.WriteLine(summaryMessage.Red());
- }
- else
- {
- Reporter.Output.WriteLine(summaryMessage);
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/dotnet/project.json b/src/dotnet/project.json
index 312ee242c..5757e67ea 100644
--- a/src/dotnet/project.json
+++ b/src/dotnet/project.json
@@ -47,6 +47,9 @@
"Microsoft.DotNet.Configurer": {
"target": "project"
},
+ "Microsoft.DotNet.Tools.Test": {
+ "target": "project"
+ },
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0"
diff --git a/test/Microsoft.DotNet.Cli.Utils.Tests/GivenADefaultCommandResolver.cs b/test/Microsoft.DotNet.Cli.Utils.Tests/GivenADefaultCommandResolver.cs
index 3a92bad95..b2e354e30 100644
--- a/test/Microsoft.DotNet.Cli.Utils.Tests/GivenADefaultCommandResolver.cs
+++ b/test/Microsoft.DotNet.Cli.Utils.Tests/GivenADefaultCommandResolver.cs
@@ -17,7 +17,7 @@ namespace Microsoft.DotNet.Cli.Utils.Tests
var resolvers = defaultCommandResolver.OrderedCommandResolvers;
- resolvers.Should().HaveCount(6);
+ resolvers.Should().HaveCount(7);
resolvers.Select(r => r.GetType())
.Should()
@@ -28,7 +28,8 @@ namespace Microsoft.DotNet.Cli.Utils.Tests
typeof(ProjectToolsCommandResolver),
typeof(AppBaseDllCommandResolver),
typeof(AppBaseCommandResolver),
- typeof(PathCommandResolver)
+ typeof(PathCommandResolver),
+ typeof(PublishedPathCommandResolver)
});
}
}
diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Mock/FileSystemMockBuilder.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Mock/FileSystemMockBuilder.cs
index 50537d20b..9176cc2d8 100644
--- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Mock/FileSystemMockBuilder.cs
+++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Mock/FileSystemMockBuilder.cs
@@ -118,6 +118,16 @@ namespace Microsoft.Extensions.DependencyModel.Tests
return _temporaryDirectory;
}
+ public IEnumerable GetFiles(string path, string searchPattern)
+ {
+ throw new NotImplementedException();
+ }
+
+ public string GetDirectoryFullName(string path)
+ {
+ throw new NotImplementedException();
+ }
+
public bool Exists(string path)
{
return _files.Keys.Any(k => k.StartsWith(path));
diff --git a/test/dotnet-test.Tests/GivenThatWeWantToRunTestsInTheConsole.cs b/test/dotnet-test.Tests/GivenThatWeWantToRunTestsInTheConsole.cs
index 93db4eff0..f34a44f6e 100644
--- a/test/dotnet-test.Tests/GivenThatWeWantToRunTestsInTheConsole.cs
+++ b/test/dotnet-test.Tests/GivenThatWeWantToRunTestsInTheConsole.cs
@@ -97,6 +97,20 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
result.Should().Pass();
}
+ [Fact]
+ public void It_runs_tests_for_an_assembly_passed_as_param()
+ {
+ var publishCommand = new PublishCommand(_projectFilePath);
+ var result = publishCommand.Execute();
+ result.Should().Pass();
+
+ var assemblyUnderTestPath = Path.Combine(publishCommand.GetOutputDirectory(true).FullName, publishCommand.GetPortableOutputName());
+
+ var testCommand = new DotnetTestCommand();
+ result = testCommand.Execute($"{assemblyUnderTestPath}");
+ result.Should().Pass();
+ }
+
[Theory]
[MemberData("ArgumentNames")]
public void It_fails_correctly_with_unspecified_arguments_with_long_form(string argument)
diff --git a/test/dotnet-test.Tests/project.json b/test/dotnet-test.Tests/project.json
index 873f6a070..569e67db7 100644
--- a/test/dotnet-test.Tests/project.json
+++ b/test/dotnet-test.Tests/project.json
@@ -15,6 +15,9 @@
"Microsoft.DotNet.ProjectModel": {
"target": "project"
},
+ "Microsoft.DotNet.InternalAbstractions": {
+ "target": "project"
+ },
"System.Net.NameResolution": "4.0.0",
"System.Net.Sockets": "4.1.0",
"System.Runtime.Serialization.Primitives": "4.1.1",
diff --git a/test/dotnet-test.UnitTests/GivenAParameterTestRunnerNameResolver.cs b/test/dotnet-test.UnitTests/GivenAParameterTestRunnerNameResolver.cs
new file mode 100644
index 000000000..b85637c98
--- /dev/null
+++ b/test/dotnet-test.UnitTests/GivenAParameterTestRunnerNameResolver.cs
@@ -0,0 +1,24 @@
+// 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.DotNet.Tools.Test;
+using Xunit;
+
+namespace Microsoft.Dotnet.Tools.Test.Tests
+{
+ public class GivenAParameterTestRunnerNameResolver
+ {
+ private const string SomeTestRunner = "Some test runner";
+
+ [Fact]
+ public void It_returns_the_runner_based_on_the_parameter()
+ {
+ var parameterTestRunnerResolver = new ParameterTestRunnerNameResolver(SomeTestRunner);
+
+ var testRunner = parameterTestRunnerResolver.ResolveTestRunner();
+
+ testRunner.Should().Be($"dotnet-test-{SomeTestRunner}");
+ }
+ }
+}
diff --git a/test/dotnet-test.UnitTests/GivenAProjectJsonTestRunnerNameResolver.cs b/test/dotnet-test.UnitTests/GivenAProjectJsonTestRunnerNameResolver.cs
new file mode 100644
index 000000000..e1dc7f7f7
--- /dev/null
+++ b/test/dotnet-test.UnitTests/GivenAProjectJsonTestRunnerNameResolver.cs
@@ -0,0 +1,43 @@
+// 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.DotNet.ProjectModel;
+using Microsoft.DotNet.Tools.Test;
+using Microsoft.Extensions.Testing.Abstractions;
+using Xunit;
+
+namespace Microsoft.Dotnet.Tools.Test.Tests
+{
+ public class GivenAProjectJsonTestRunnerNameResolver
+ {
+ private const string SomeTestRunner = "runner";
+
+ [Fact]
+ public void It_resolves_the_TestRunner_using_the_testRunner_property_in_the_projectJson()
+ {
+ var project = new Project
+ {
+ TestRunner = SomeTestRunner
+ };
+
+ var projectJsonTestRunnerResolver = new ProjectJsonTestRunnerNameResolver(project);
+
+ var testRunner = projectJsonTestRunnerResolver.ResolveTestRunner();
+
+ testRunner.Should().Be($"dotnet-test-{SomeTestRunner}");
+ }
+
+ [Fact]
+ public void It_returns_null_when_there_is_no_testRunner_set_in_the_projectJson()
+ {
+ var project = new Project();
+
+ var projectJsonTestRunnerResolver = new ProjectJsonTestRunnerNameResolver(project);
+
+ var testRunner = projectJsonTestRunnerResolver.ResolveTestRunner();
+
+ testRunner.Should().BeNull();
+ }
+ }
+}
diff --git a/test/dotnet-test.UnitTests/GivenATestCommand.cs b/test/dotnet-test.UnitTests/GivenATestCommand.cs
index 3a1c7598a..5a0df6743 100644
--- a/test/dotnet-test.UnitTests/GivenATestCommand.cs
+++ b/test/dotnet-test.UnitTests/GivenATestCommand.cs
@@ -21,19 +21,21 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
"NetCoreAppOnlyProject",
"project.json");
- private TestCommand _testCommand;
- private Mock _dotnetTestRunnerFactoryMock;
- private Mock _dotnetTestRunnerMock;
+ private readonly TestCommand _testCommand;
+ private readonly Mock _dotnetTestRunnerFactoryMock;
+ private readonly Mock _dotnetTestRunnerMock;
public GivenATestCommand()
{
_dotnetTestRunnerMock = new Mock();
_dotnetTestRunnerMock
- .Setup(d => d.RunTests(It.IsAny(), It.IsAny(), It.IsAny()))
+ .Setup(d => d.RunTests(It.IsAny()))
.Returns(0);
_dotnetTestRunnerFactoryMock = new Mock();
- _dotnetTestRunnerFactoryMock.Setup(d => d.Create(null)).Returns(_dotnetTestRunnerMock.Object);
+ _dotnetTestRunnerFactoryMock
+ .Setup(d => d.Create(It.IsAny()))
+ .Returns(_dotnetTestRunnerMock.Object);
_testCommand = new TestCommand(_dotnetTestRunnerFactoryMock.Object);
}
@@ -44,7 +46,8 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
var result = _testCommand.DoRun(new[] {"--help"});
result.Should().Be(0);
- _dotnetTestRunnerFactoryMock.Verify(d => d.Create(It.IsAny()), Times.Never);
+ _dotnetTestRunnerFactoryMock
+ .Verify(d => d.Create(It.IsAny()), Times.Never);
}
[Fact]
@@ -53,7 +56,8 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
var result = _testCommand.DoRun(new[] { ProjectJsonPath, "-f", "netcoreapp1.0" });
result.Should().Be(0);
- _dotnetTestRunnerFactoryMock.Verify(d => d.Create(It.IsAny()), Times.Once);
+ _dotnetTestRunnerFactoryMock
+ .Verify(d => d.Create(It.IsAny()), Times.Once);
}
[Fact]
@@ -62,7 +66,7 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
var result = _testCommand.DoRun(new[] { ProjectJsonPath, "-f", "netcoreapp1.0" });
_dotnetTestRunnerMock.Verify(
- d => d.RunTests(It.IsAny(), It.IsAny(), It.IsAny()),
+ d => d.RunTests(It.IsAny()),
Times.Once);
}
}
diff --git a/test/dotnet-test.UnitTests/GivenATestRunner.cs b/test/dotnet-test.UnitTests/GivenATestRunner.cs
index a767f75ce..41238b037 100644
--- a/test/dotnet-test.UnitTests/GivenATestRunner.cs
+++ b/test/dotnet-test.UnitTests/GivenATestRunner.cs
@@ -20,7 +20,7 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
private Mock _commandMock;
private Mock _commandFactoryMock;
private Mock _argumentsBuilderMock;
- private string _runner = "runner";
+ private string _runner = "dotnet-test-runner";
private string[] _testRunnerArguments;
public GivenATestRunner()
@@ -38,7 +38,7 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
_commandFactoryMock = new Mock();
_commandFactoryMock.Setup(c => c.Create(
- $"dotnet-{_runner}",
+ $"{_runner}",
_testRunnerArguments,
null,
null)).Returns(_commandMock.Object).Verifiable();
diff --git a/test/dotnet-test.UnitTests/GivenATestRunnerNameResolverFactoryAndADotnetTestParams.cs b/test/dotnet-test.UnitTests/GivenATestRunnerNameResolverFactoryAndADotnetTestParams.cs
new file mode 100644
index 000000000..109b2addc
--- /dev/null
+++ b/test/dotnet-test.UnitTests/GivenATestRunnerNameResolverFactoryAndADotnetTestParams.cs
@@ -0,0 +1,79 @@
+// 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.IO;
+using FluentAssertions;
+using Microsoft.DotNet.ProjectModel;
+using Microsoft.DotNet.Tools.Test;
+using Moq;
+using Xunit;
+
+namespace Microsoft.Dotnet.Tools.Test.Tests
+{
+ public class GivenATestRunnerNameResolverFactoryAndADotnetTestParams
+ {
+ private const string PathToAFolder = "c:/some/path";
+ private const string PathToAnAssembly = "c:/some/path/to/assembly.dll";
+ private const string SomeTestRunner = "some test runner";
+
+ private readonly string _pathToAProjectJson = Path.Combine(PathToAFolder, "project.json");
+
+ [Fact]
+ public void It_returns_a_ProjectJsonTestRunnerResolver_when_the_path_parameter_points_to_a_project_json()
+ {
+ var dotnetTestParams = new DotnetTestParams
+ {
+ ProjectOrAssemblyPath = _pathToAProjectJson
+ };
+
+ var projectReaderMock = new Mock();
+ projectReaderMock
+ .Setup(p => p.ReadProject(dotnetTestParams.ProjectOrAssemblyPath, null))
+ .Returns(new Project());
+
+ var dotnetTestRunnerResolverFactory = new DotnetTestRunnerResolverFactory(projectReaderMock.Object);
+
+ var testRunnerResolver = dotnetTestRunnerResolverFactory.Create(dotnetTestParams);
+
+ testRunnerResolver.Should().BeOfType();
+ }
+
+ [Fact]
+ public void It_returns_a_ProjectJsonTestRunnerResolver_when_the_path_parameter_points_to_a_folder()
+ {
+ var dotnetTestParams = new DotnetTestParams
+ {
+ ProjectOrAssemblyPath = PathToAFolder
+ };
+
+ var projectReaderMock = new Mock();
+ projectReaderMock
+ .Setup(p => p.ReadProject(dotnetTestParams.ProjectOrAssemblyPath, null))
+ .Returns(new Project());
+
+ var dotnetTestRunnerResolverFactory = new DotnetTestRunnerResolverFactory(projectReaderMock.Object);
+
+ var testRunnerResolver = dotnetTestRunnerResolverFactory.Create(dotnetTestParams);
+
+ testRunnerResolver.Should().BeOfType();
+ }
+
+ [Fact]
+ public void It_returns_a_ParameterTestRunnerResolver_when_an_assembly_and_a_test_runner_are_passed()
+ {
+ var dotnetTestParams = new DotnetTestParams
+ {
+ ProjectOrAssemblyPath = PathToAnAssembly,
+ TestRunner = SomeTestRunner
+ };
+
+ var projectReaderMock = new Mock();
+
+ var dotnetTestRunnerResolverFactory = new DotnetTestRunnerResolverFactory(projectReaderMock.Object);
+
+ var testRunnerResolver = dotnetTestRunnerResolverFactory.Create(dotnetTestParams);
+
+ testRunnerResolver.Should().BeOfType();
+ }
+ }
+}
diff --git a/test/dotnet-test.UnitTests/GivenAnAssemblyTestRunnerNameResolver.cs b/test/dotnet-test.UnitTests/GivenAnAssemblyTestRunnerNameResolver.cs
new file mode 100644
index 000000000..9358efb1e
--- /dev/null
+++ b/test/dotnet-test.UnitTests/GivenAnAssemblyTestRunnerNameResolver.cs
@@ -0,0 +1,100 @@
+// 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.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using FluentAssertions;
+using Microsoft.DotNet.Tools.Test;
+using Microsoft.Extensions.EnvironmentAbstractions;
+using Xunit;
+
+namespace Microsoft.Dotnet.Tools.Test.Tests
+{
+ public class GivenAnAssemblyTestRunnerNameResolver
+ {
+ private readonly string _directoryOfAssemblyUnderTest = Path.Combine("c:", "some", "path");
+
+ private const string TestRunnerName = "dotnet-test-someRunner";
+
+ private static readonly string TestRunnerFileName = $"{TestRunnerName}.dll";
+
+ [Fact]
+ public void It_finds_the_runner_in_the_same_folder_as_the_assembly_when_the_path_passed_is_to_the_assembly()
+ {
+ var directoryMock = new DirectoryMock();
+
+ directoryMock.AddFile(_directoryOfAssemblyUnderTest, TestRunnerFileName);
+
+ var pathToAssemblyUnderTest = Path.Combine(_directoryOfAssemblyUnderTest, TestRunnerFileName);
+ var assemblyTestRunnerResolver =
+ new AssemblyTestRunnerNameResolver(pathToAssemblyUnderTest, directoryMock);
+
+ var testRunner = assemblyTestRunnerResolver.ResolveTestRunner();
+
+ testRunner.Should().Be(TestRunnerName);
+ }
+
+ [Fact]
+ public void It_returns_a_test_runner_even_when_multiple_test_runners_are_present()
+ {
+ var directoryMock = new DirectoryMock();
+
+ directoryMock.AddFile(_directoryOfAssemblyUnderTest, TestRunnerFileName);
+ directoryMock.AddFile(_directoryOfAssemblyUnderTest, "dotnet-test-someOtherTestRunner.dll");
+ directoryMock.AddFile(_directoryOfAssemblyUnderTest, "dotnet-test-AndYetAnotherTestRunner.dll");
+
+ var assemblyTestRunnerResolver =
+ new AssemblyTestRunnerNameResolver(_directoryOfAssemblyUnderTest, directoryMock);
+
+ var bestEffortTestRunner = assemblyTestRunnerResolver.ResolveTestRunner();
+
+ bestEffortTestRunner.Should().NotBeNull();
+ }
+
+ [Fact]
+ public void It_returns_null_when_no_test_runner_is_found()
+ {
+ var directoryMock = new DirectoryMock();
+
+ var assemblyTestRunnerResolver =
+ new AssemblyTestRunnerNameResolver(_directoryOfAssemblyUnderTest, directoryMock);
+
+ var testRunner = assemblyTestRunnerResolver.ResolveTestRunner();
+
+ testRunner.Should().BeNull();
+ }
+
+ private class DirectoryMock : IDirectory
+ {
+ private readonly IList _files = new List();
+
+ public bool Exists(string path)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public ITemporaryDirectory CreateTemporaryDirectory()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public IEnumerable GetFiles(string path, string searchPattern)
+ {
+ var searchPatternRegex = new Regex(searchPattern);
+ return _files.Where(f => f.StartsWith(path) && searchPatternRegex.IsMatch(f));
+ }
+
+ public string GetDirectoryFullName(string path)
+ {
+ return Path.GetDirectoryName(path);
+ }
+
+ public void AddFile(string path, string fileName)
+ {
+ _files.Add(Path.Combine(path, fileName));
+ }
+ }
+ }
+}
diff --git a/test/dotnet-test.UnitTests/GivenThatWeWantToParseArgumentsForDotnetTest.cs b/test/dotnet-test.UnitTests/GivenThatWeWantToParseArgumentsForDotnetTest.cs
index f440b618e..0d9486d32 100644
--- a/test/dotnet-test.UnitTests/GivenThatWeWantToParseArgumentsForDotnetTest.cs
+++ b/test/dotnet-test.UnitTests/GivenThatWeWantToParseArgumentsForDotnetTest.cs
@@ -19,16 +19,20 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
private const string Runtime = "some runtime";
private const int ParentProcessId = 1010;
private const int Port = 2314;
+ private const string TestRunner = "someTestRunner";
+ private const string PathToAssemblyUnderTest = "c:/some/path/assemblyUnderTest.dll";
- private DotnetTestParams _dotnetTestFullParams;
- private DotnetTestParams _emptyDotnetTestParams;
+ private readonly DotnetTestParams _dotnetTestFullParamsWithProjectJson;
+ private readonly DotnetTestParams _emptyDotnetTestParams;
+ private readonly DotnetTestParams _dotnetTestParamsWithAssembly;
public GivenThatWeWantToParseArgumentsForDotnetTest()
{
- _dotnetTestFullParams = new DotnetTestParams();
+ _dotnetTestFullParamsWithProjectJson = new DotnetTestParams();
+ _dotnetTestParamsWithAssembly = new DotnetTestParams();
_emptyDotnetTestParams = new DotnetTestParams();
- _dotnetTestFullParams.Parse(new[]
+ _dotnetTestFullParamsWithProjectJson.Parse(new[]
{
ProjectJson,
"--parentProcessId", ParentProcessId.ToString(),
@@ -42,19 +46,25 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
"--additional-parameters", "additional-parameter-value"
});
+ _dotnetTestParamsWithAssembly.Parse(new[]
+ {
+ PathToAssemblyUnderTest,
+ "--test-runner", TestRunner
+ });
+
_emptyDotnetTestParams.Parse(new string[] { });
}
[Fact]
public void It_sets_the_project_path_current_folder_if_one_is_not_passed_in()
{
- _emptyDotnetTestParams.ProjectPath.Should().Be(Directory.GetCurrentDirectory());
+ _emptyDotnetTestParams.ProjectOrAssemblyPath.Should().Be(Directory.GetCurrentDirectory());
}
[Fact]
public void It_sets_the_project_path_to_the_passed_value()
{
- _dotnetTestFullParams.ProjectPath.Should().Be(ProjectJson);
+ _dotnetTestFullParamsWithProjectJson.ProjectOrAssemblyPath.Should().Be(ProjectJson);
}
[Fact]
@@ -72,7 +82,7 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
[Fact]
public void It_converts_the_parent_process_id_to_int_when_a_valid_one_is_passed()
{
- _dotnetTestFullParams.ParentProcessId.Should().Be(ParentProcessId);
+ _dotnetTestFullParamsWithProjectJson.ParentProcessId.Should().Be(ParentProcessId);
}
[Fact]
@@ -96,7 +106,7 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
[Fact]
public void It_converts_the_port_to_int_when_a_valid_one_is_passed()
{
- _dotnetTestFullParams.Port.Should().Be(Port);
+ _dotnetTestFullParamsWithProjectJson.Port.Should().Be(Port);
}
[Fact]
@@ -108,7 +118,7 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
[Fact]
public void It_converts_the_framework_to_NugetFramework()
{
- _dotnetTestFullParams.Framework.DotNetFrameworkName.Should().Be(".NETCoreApp,Version=v1.0");
+ _dotnetTestFullParamsWithProjectJson.Framework.DotNetFrameworkName.Should().Be(".NETCoreApp,Version=v1.0");
}
[Fact]
@@ -129,7 +139,7 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
[Fact]
public void It_sets_Output_when_one_is_passed_in()
{
- _dotnetTestFullParams.Output.Should().Be(Output);
+ _dotnetTestFullParamsWithProjectJson.Output.Should().Be(Output);
}
[Fact]
@@ -141,7 +151,7 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
[Fact]
public void It_sets_BuildBasePath_when_one_is_passed_in()
{
- _dotnetTestFullParams.BuildBasePath.Should().Be(Path.GetFullPath(BuildBasePath));
+ _dotnetTestFullParamsWithProjectJson.BuildBasePath.Should().Be(Path.GetFullPath(BuildBasePath));
}
[Fact]
@@ -153,7 +163,7 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
[Fact]
public void It_sets_Config_to_passed_in_value()
{
- _dotnetTestFullParams.Config.Should().Be(Config);
+ _dotnetTestFullParamsWithProjectJson.Config.Should().Be(Config);
}
[Fact]
@@ -165,7 +175,7 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
[Fact]
public void It_sets_Runtime_when_one_is_passed_in()
{
- _dotnetTestFullParams.Runtime.Should().Be(Runtime);
+ _dotnetTestFullParamsWithProjectJson.Runtime.Should().Be(Runtime);
}
[Fact]
@@ -177,14 +187,14 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
[Fact]
public void It_sets_any_remaining_params_to_RemainingArguments()
{
- _dotnetTestFullParams.RemainingArguments.ShouldBeEquivalentTo(
+ _dotnetTestFullParamsWithProjectJson.RemainingArguments.ShouldBeEquivalentTo(
new [] { "--additional-parameters", "additional-parameter-value" });
}
[Fact]
public void It_sets_no_build_to_true_when_it_is_passed()
{
- _dotnetTestFullParams.NoBuild.Should().BeTrue();
+ _dotnetTestFullParamsWithProjectJson.NoBuild.Should().BeTrue();
}
[Fact]
@@ -196,7 +206,7 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
[Fact]
public void It_sets_Help_to_false_when_help_is_not_passed_in()
{
- _dotnetTestFullParams.Help.Should().BeFalse();
+ _dotnetTestFullParamsWithProjectJson.Help.Should().BeFalse();
}
[Fact]
@@ -207,5 +217,65 @@ namespace Microsoft.Dotnet.Tools.Test.Tests
dotnetTestParams.Help.Should().BeTrue();
}
+
+ [Fact]
+ public void It_has_the_testRunner_null_by_default()
+ {
+ _emptyDotnetTestParams.TestRunner.Should().BeNull();
+ }
+
+ [Fact]
+ public void It_throws_when_you_specify_a_testRunner_along_with_a_folder()
+ {
+ var dotnetTestParams = new DotnetTestParams();
+ Action action = () => dotnetTestParams.Parse(new[]
+ {
+ "c:/some/path",
+ "--test-runner", "someTestRunner"
+ });
+
+ action
+ .ShouldThrow()
+ .WithMessage("You can only specify a test runner with a dll.");
+ }
+
+ [Fact]
+ public void It_throws_when_you_specify_a_testRunner_along_with_a_project_json()
+ {
+ var dotnetTestParams = new DotnetTestParams();
+ Action action = () => dotnetTestParams.Parse(new[]
+ {
+ ProjectJson,
+ "--test-runner", "someTestRunner"
+ });
+
+ action
+ .ShouldThrow()
+ .WithMessage("You can only specify a test runner with a dll.");
+ }
+
+ [Fact]
+ public void It_succeeds_when_specifying_an_assembly()
+ {
+ _dotnetTestParamsWithAssembly.ProjectOrAssemblyPath.Should().Be(PathToAssemblyUnderTest);
+ }
+
+ [Fact]
+ public void It_succeeds_when_specifying_a_test_runner_along_with_an_assembly()
+ {
+ _dotnetTestParamsWithAssembly.TestRunner.Should().Be(TestRunner);
+ }
+
+ [Fact]
+ public void When_a_testRunner_is_successfully_specified_then_HasTestRunner_returns_true()
+ {
+ _dotnetTestParamsWithAssembly.HasTestRunner.Should().BeTrue();
+ }
+
+ [Fact]
+ public void When_a_testRunner_is_noy_specified_then_HasTestRunner_returns_false()
+ {
+ _dotnetTestFullParamsWithProjectJson.HasTestRunner.Should().BeFalse();
+ }
}
}
diff --git a/test/dotnet-test.UnitTests/project.json b/test/dotnet-test.UnitTests/project.json
index 54f47f175..a34d68a28 100644
--- a/test/dotnet-test.UnitTests/project.json
+++ b/test/dotnet-test.UnitTests/project.json
@@ -6,7 +6,10 @@
"version": "1.0.0"
},
"Newtonsoft.Json": "9.0.1",
- "dotnet": {
+ "Microsoft.DotNet.Tools.Test": {
+ "target": "project"
+ },
+ "Microsoft.DotNet.InternalAbstractions": {
"target": "project"
},
"Microsoft.Win32.Registry": {
@@ -34,6 +37,7 @@
]
},
"buildOptions": {
+ "keyFile": "../../tools/test_key.snk",
"copyToOutput": {
"include": [
"../../TestAssets/TestProjects/ProjectsWithTests/NetCoreAppOnlyProject/project.json"