diff --git a/src/Microsoft.DotNet.Cli.Utils/Command.cs b/src/Microsoft.DotNet.Cli.Utils/Command.cs index ad099563b..3779deeb0 100644 --- a/src/Microsoft.DotNet.Cli.Utils/Command.cs +++ b/src/Microsoft.DotNet.Cli.Utils/Command.cs @@ -67,12 +67,14 @@ namespace Microsoft.DotNet.Cli.Utils string commandName, IEnumerable args, NuGetFramework framework = null, - string configuration = Constants.DefaultConfiguration) + string configuration = Constants.DefaultConfiguration, + string outputPath = null) { var commandSpec = CommandResolver.TryResolveCommandSpec(commandName, args, framework, - configuration: configuration); + configuration: configuration, + outputPath: outputPath); if (commandSpec == null) { diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandResolver.cs b/src/Microsoft.DotNet.Cli.Utils/CommandResolver.cs index 413235884..791848b03 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandResolver.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandResolver.cs @@ -13,10 +13,15 @@ namespace Microsoft.DotNet.Cli.Utils { internal static class CommandResolver { - public static CommandSpec TryResolveCommandSpec(string commandName, IEnumerable args, NuGetFramework framework = null, string configuration=Constants.DefaultConfiguration) + public static CommandSpec TryResolveCommandSpec( + string commandName, + IEnumerable args, + NuGetFramework framework = null, + string configuration = Constants.DefaultConfiguration, + string outputPath = null) { return ResolveFromRootedCommand(commandName, args) ?? - ResolveFromProjectDependencies(commandName, args, framework, configuration) ?? + ResolveFromProjectDependencies(commandName, args, framework, configuration, outputPath) ?? ResolveFromProjectTools(commandName, args) ?? ResolveFromAppBase(commandName, args) ?? ResolveFromPath(commandName, args); @@ -67,10 +72,11 @@ namespace Microsoft.DotNet.Cli.Utils } public static CommandSpec ResolveFromProjectDependencies( - string commandName, - IEnumerable args, - NuGetFramework framework, - string configuration) + string commandName, + IEnumerable args, + NuGetFramework framework, + string configuration, + string outputPath) { if (framework == null) return null; @@ -82,7 +88,7 @@ namespace Microsoft.DotNet.Cli.Utils if (commandPackage == null) return null; - var depsPath = projectContext.GetOutputPaths(configuration).RuntimeFiles.Deps; + var depsPath = projectContext.GetOutputPaths(configuration, outputPath: outputPath).RuntimeFiles.Deps; return ConfigureCommandFromPackage(commandName, args, commandPackage, projectContext, depsPath); } diff --git a/src/Microsoft.DotNet.Cli.Utils/FixedPathCommandFactory.cs b/src/Microsoft.DotNet.Cli.Utils/FixedPathCommandFactory.cs new file mode 100644 index 000000000..40837a7f3 --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/FixedPathCommandFactory.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.Collections.Generic; +using NuGet.Frameworks; + +namespace Microsoft.DotNet.Cli.Utils +{ + public class FixedPathCommandFactory : ICommandFactory + { + private readonly string _configuration; + private readonly string _outputPath; + + public FixedPathCommandFactory(string configuration, string outputPath) + { + _configuration = configuration; + _outputPath = outputPath; + } + + public ICommand Create( + string commandName, + IEnumerable args, + NuGetFramework framework = null, + string configuration = Constants.DefaultConfiguration) + { + if (string.IsNullOrEmpty(configuration)) + { + configuration = _configuration; + } + + return Command.Create(commandName, args, framework, configuration, _outputPath); + } + } +} diff --git a/src/dotnet/commands/dotnet-test/Program.cs b/src/dotnet/commands/dotnet-test/Program.cs index 51ad4ae35..e5b884a4b 100644 --- a/src/dotnet/commands/dotnet-test/Program.cs +++ b/src/dotnet/commands/dotnet-test/Program.cs @@ -30,6 +30,7 @@ namespace Microsoft.DotNet.Tools.Test var parentProcessIdOption = app.Option("--parentProcessId", "Used by IDEs to specify their process ID. Test will exit if the parent process does.", CommandOptionType.SingleValue); var portOption = app.Option("--port", "Used by IDEs to specify a port number to listen for a connection.", CommandOptionType.SingleValue); var configurationOption = app.Option("-c|--configuration ", "Configuration under which to build", CommandOptionType.SingleValue); + var output = app.Option("-o|--output ", "Directory in which to find the binaries to be run", CommandOptionType.SingleValue); var projectPath = app.Argument("", "The project to test, defaults to the current directory. Can be a path to a project.json or a project directory."); app.OnExecute(() => @@ -57,6 +58,8 @@ namespace Microsoft.DotNet.Tools.Test var configuration = configurationOption.Value() ?? Constants.DefaultConfiguration; + var outputPath = output.Value(); + if (portOption.HasValue()) { int port; @@ -66,11 +69,11 @@ namespace Microsoft.DotNet.Tools.Test throw new InvalidOperationException($"{portOption.Value()} is not a valid port number."); } - return RunDesignTime(port, projectContext, testRunner, configuration); + return RunDesignTime(port, projectContext, testRunner, configuration, outputPath); } else { - return RunConsole(projectContext, app, testRunner, configuration); + return RunConsole(projectContext, app, testRunner, configuration, outputPath); } } catch (InvalidOperationException ex) @@ -89,28 +92,53 @@ namespace Microsoft.DotNet.Tools.Test return app.Execute(args); } - private static int RunConsole(ProjectContext projectContext, CommandLineApplication app, string testRunner, string configuration) + private static int RunConsole( + ProjectContext projectContext, + CommandLineApplication app, + string testRunner, + string configuration, + string outputPath) { - var commandArgs = new List { projectContext.GetOutputPaths(configuration).CompilationFiles.Assembly }; + var commandArgs = new List { GetAssemblyUnderTest(projectContext, configuration, outputPath) }; commandArgs.AddRange(app.RemainingArguments); - return Command.Create($"dotnet-{GetCommandName(testRunner)}", commandArgs, projectContext.TargetFramework, configuration: configuration) + return Command.Create( + $"dotnet-{GetCommandName(testRunner)}", + commandArgs, + projectContext.TargetFramework, + configuration: configuration, + outputPath: outputPath) .ForwardStdErr() .ForwardStdOut() .Execute() .ExitCode; } + private static string GetAssemblyUnderTest(ProjectContext projectContext, string configuration, string outputPath) + { + var assemblyUnderTest = + projectContext.GetOutputPaths(configuration, outputPath: outputPath).CompilationFiles.Assembly; + + if (!string.IsNullOrEmpty(outputPath)) + { + assemblyUnderTest = + projectContext.GetOutputPaths(configuration, outputPath: outputPath).RuntimeFiles.Assembly; + } + + return assemblyUnderTest; + } + private static int RunDesignTime( int port, ProjectContext projectContext, string testRunner, - string configuration) + string configuration, + string outputPath) { Console.WriteLine("Listening on port {0}", port); - HandleDesignTimeMessages(projectContext, testRunner, port, configuration); + HandleDesignTimeMessages(projectContext, testRunner, port, configuration, outputPath); return 0; } @@ -119,18 +147,19 @@ namespace Microsoft.DotNet.Tools.Test ProjectContext projectContext, string testRunner, int port, - string configuration) + string configuration, + string outputPath) { var reportingChannelFactory = new ReportingChannelFactory(); var adapterChannel = reportingChannelFactory.CreateChannelWithPort(port); try { - var assemblyUnderTest = projectContext.GetOutputPaths(configuration).CompilationFiles.Assembly; + var assemblyUnderTest = GetAssemblyUnderTest(projectContext, configuration, outputPath); var messages = new TestMessagesCollection(); using (var dotnetTest = new DotnetTest(messages, assemblyUnderTest)) { - var commandFactory = new CommandFactory(); + var commandFactory = new FixedPathCommandFactory(configuration, outputPath); var testRunnerFactory = new TestRunnerFactory(GetCommandName(testRunner), commandFactory); dotnetTest diff --git a/src/dotnet/commands/dotnet-test/TestRunners/TestRunner.cs b/src/dotnet/commands/dotnet-test/TestRunners/TestRunner.cs index b66d39f12..58f7f4950 100644 --- a/src/dotnet/commands/dotnet-test/TestRunners/TestRunner.cs +++ b/src/dotnet/commands/dotnet-test/TestRunners/TestRunner.cs @@ -54,7 +54,7 @@ namespace Microsoft.DotNet.Tools.Test $"dotnet-{_testRunner}", commandArgs, new NuGetFramework("DNXCore", Version.Parse("5.0")), - Constants.DefaultConfiguration); + null); } } } diff --git a/test/dotnet-test.UnitTests/GivenATestRunner.cs b/test/dotnet-test.UnitTests/GivenATestRunner.cs index fd8496f27..7257ee6f8 100644 --- a/test/dotnet-test.UnitTests/GivenATestRunner.cs +++ b/test/dotnet-test.UnitTests/GivenATestRunner.cs @@ -41,7 +41,7 @@ namespace Microsoft.Dotnet.Tools.Test.Tests $"dotnet-{_runner}", _testRunnerArguments, new NuGetFramework("DNXCore", Version.Parse("5.0")), - Constants.DefaultConfiguration)).Returns(_commandMock.Object).Verifiable(); + null)).Returns(_commandMock.Object).Verifiable(); } [Fact]