2016-10-04 15:37:36 +05:30
// Copyright(c) .NET Foundation and contributors.All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System ;
using System.Collections.Generic ;
using Microsoft.DotNet.Cli.CommandLine ;
using Microsoft.DotNet.Cli.Utils ;
using Microsoft.DotNet.Tools.MSBuild ;
using System.IO ;
using System.Text.RegularExpressions ;
2016-10-27 18:46:43 -07:00
namespace Microsoft.DotNet.Tools.Test
2016-10-04 15:37:36 +05:30
{
2016-10-27 18:46:43 -07:00
public class TestCommand
2016-10-04 15:37:36 +05:30
{
public static int Run ( string [ ] args )
{
DebugHelper . HandleDebugSwitch ( ref args ) ;
var cmd = new CommandLineApplication ( throwOnUnexpectedArg : false )
{
2016-10-27 18:46:43 -07:00
Name = "dotnet test" ,
2016-12-01 17:15:25 -08:00
FullName = LocalizableStrings . AppFullName ,
Description = LocalizableStrings . AppDescription
2016-10-04 15:37:36 +05:30
} ;
2016-11-24 14:18:54 +05:30
cmd . AllowArgumentSeparator = true ;
cmd . ArgumentSeparatorHelpText = HelpMessageStrings . MSBuildAdditionalArgsHelpText ;
2016-10-04 15:37:36 +05:30
cmd . HelpOption ( "-h|--help" ) ;
var argRoot = cmd . Argument (
2016-12-01 17:15:25 -08:00
$"<{LocalizableStrings.CmdArgProject}>" ,
LocalizableStrings . CmdArgDescription ,
2016-10-04 15:37:36 +05:30
multipleValues : false ) ;
var settingOption = cmd . Option (
2016-12-01 17:15:25 -08:00
$"-s|--settings <{LocalizableStrings.CmdSettingsFile}>" ,
LocalizableStrings . CmdSettingsDescription ,
2016-10-04 15:37:36 +05:30
CommandOptionType . SingleValue ) ;
2016-10-06 04:33:54 +05:30
var listTestsOption = cmd . Option (
"-lt|--listTests" ,
2016-12-01 17:15:25 -08:00
LocalizableStrings . CmdListTestsDescription ,
2016-10-06 04:33:54 +05:30
CommandOptionType . NoValue ) ;
var testCaseFilterOption = cmd . Option (
2016-12-01 17:15:25 -08:00
$"-tcf|--testCaseFilter <{LocalizableStrings.CmdTestCaseFilterExpression}>" ,
LocalizableStrings . CmdTestCaseFilterDescription ,
2016-10-04 15:37:36 +05:30
CommandOptionType . SingleValue ) ;
var testAdapterPathOption = cmd . Option (
2016-10-12 15:20:07 +05:30
"-tap|--testAdapterPath" ,
2016-12-01 17:15:25 -08:00
LocalizableStrings . CmdTestAdapterPathDescription ,
2016-10-04 15:37:36 +05:30
CommandOptionType . SingleValue ) ;
var loggerOption = cmd . Option (
2016-12-01 17:15:25 -08:00
$"-l|--logger <{LocalizableStrings.CmdLoggerOption}>" ,
LocalizableStrings . CmdLoggerDescription ,
2016-10-06 04:33:54 +05:30
CommandOptionType . SingleValue ) ;
2016-10-04 15:37:36 +05:30
2016-10-06 04:33:54 +05:30
var configurationOption = cmd . Option (
2016-12-01 17:15:25 -08:00
$"-c|--configuration <{LocalizableStrings.CmdConfiguration}>" ,
LocalizableStrings . CmdConfigDescription ,
2016-10-06 04:33:54 +05:30
CommandOptionType . SingleValue ) ;
2016-10-04 15:37:36 +05:30
2016-10-06 04:33:54 +05:30
var frameworkOption = cmd . Option (
2016-12-01 17:15:25 -08:00
$"-f|--framework <{LocalizableStrings.CmdFramework}>" ,
LocalizableStrings . CmdFrameworkDescription ,
2016-10-04 15:37:36 +05:30
CommandOptionType . SingleValue ) ;
2016-10-06 04:33:54 +05:30
var outputOption = cmd . Option (
2016-12-01 17:15:25 -08:00
$"-o|--output <{LocalizableStrings.CmdOutputDir}>" ,
LocalizableStrings . CmdOutputDescription ,
2016-10-04 15:37:36 +05:30
CommandOptionType . SingleValue ) ;
2016-10-28 20:15:38 +05:30
var diagOption = cmd . Option (
2016-12-01 17:15:25 -08:00
$"-d|--diag <{LocalizableStrings.CmdPathToLogFile}>" ,
LocalizableStrings . CmdPathTologFileDescription ,
2016-10-28 20:15:38 +05:30
CommandOptionType . SingleValue ) ;
2016-10-06 04:33:54 +05:30
var noBuildtOption = cmd . Option (
"--noBuild" ,
2016-12-01 17:15:25 -08:00
LocalizableStrings . CmdNoBuildDescription ,
2016-10-06 04:33:54 +05:30
CommandOptionType . NoValue ) ;
2016-11-15 11:56:39 -08:00
CommandOption verbosityOption = MSBuildForwardingApp . AddVerbosityOption ( cmd ) ;
2016-10-04 15:37:36 +05:30
cmd . OnExecute ( ( ) = >
{
var msbuildArgs = new List < string > ( )
{
"/t:VSTest"
} ;
msbuildArgs . Add ( "/nologo" ) ;
if ( settingOption . HasValue ( ) )
{
msbuildArgs . Add ( $"/p:VSTestSetting={settingOption.Value()}" ) ;
}
2016-10-06 04:33:54 +05:30
if ( listTestsOption . HasValue ( ) )
2016-10-04 15:37:36 +05:30
{
2016-10-06 04:33:54 +05:30
msbuildArgs . Add ( $"/p:VSTestListTests=true" ) ;
2016-10-04 15:37:36 +05:30
}
2016-10-06 04:33:54 +05:30
if ( testCaseFilterOption . HasValue ( ) )
2016-10-04 15:37:36 +05:30
{
2016-10-06 04:33:54 +05:30
msbuildArgs . Add ( $"/p:VSTestTestCaseFilter={testCaseFilterOption.Value()}" ) ;
2016-10-04 15:37:36 +05:30
}
2016-10-06 04:33:54 +05:30
if ( testAdapterPathOption . HasValue ( ) )
2016-10-04 15:37:36 +05:30
{
2016-10-06 04:33:54 +05:30
msbuildArgs . Add ( $"/p:VSTestTestAdapterPath={testAdapterPathOption.Value()}" ) ;
2016-10-04 15:37:36 +05:30
}
2016-10-06 04:33:54 +05:30
if ( loggerOption . HasValue ( ) )
2016-10-04 15:37:36 +05:30
{
2016-10-06 04:33:54 +05:30
msbuildArgs . Add ( $"/p:VSTestLogger={string.Join(" ; ", loggerOption.Values)}" ) ;
2016-10-04 15:37:36 +05:30
}
2016-10-06 04:33:54 +05:30
if ( configurationOption . HasValue ( ) )
2016-10-04 15:37:36 +05:30
{
2016-10-06 04:33:54 +05:30
msbuildArgs . Add ( $"/p:Configuration={configurationOption.Value()}" ) ;
2016-10-04 15:37:36 +05:30
}
2016-10-06 04:33:54 +05:30
if ( frameworkOption . HasValue ( ) )
2016-10-04 15:37:36 +05:30
{
2016-10-06 04:33:54 +05:30
msbuildArgs . Add ( $"/p:TargetFramework={frameworkOption.Value()}" ) ;
2016-10-04 15:37:36 +05:30
}
2016-10-06 04:33:54 +05:30
if ( outputOption . HasValue ( ) )
2016-10-04 15:37:36 +05:30
{
2016-10-06 04:33:54 +05:30
msbuildArgs . Add ( $"/p:OutputPath={outputOption.Value()}" ) ;
2016-10-04 15:37:36 +05:30
}
2016-10-28 20:15:38 +05:30
if ( diagOption . HasValue ( ) )
{
msbuildArgs . Add ( $"/p:VSTestDiag={diagOption.Value()}" ) ;
}
2016-10-06 04:33:54 +05:30
if ( noBuildtOption . HasValue ( ) )
2016-10-04 15:37:36 +05:30
{
2016-10-06 04:33:54 +05:30
msbuildArgs . Add ( $"/p:VSTestNoBuild=true" ) ;
2016-10-04 15:37:36 +05:30
}
2016-11-15 11:56:39 -08:00
if ( verbosityOption . HasValue ( ) )
{
msbuildArgs . Add ( $"/verbosity:{verbosityOption.Value()}" ) ;
}
else
{
msbuildArgs . Add ( "/verbosity:quiet" ) ;
}
2016-10-04 15:37:36 +05:30
string defaultproject = GetSingleTestProjectToRunTestIfNotProvided ( argRoot . Value , cmd . RemainingArguments ) ;
if ( ! string . IsNullOrEmpty ( defaultproject ) )
{
msbuildArgs . Add ( defaultproject ) ;
}
2016-10-06 04:33:54 +05:30
if ( ! string . IsNullOrEmpty ( argRoot . Value ) )
{
msbuildArgs . Add ( argRoot . Value ) ;
}
2016-10-04 15:37:36 +05:30
// Add remaining arguments that the parser did not understand,
msbuildArgs . AddRange ( cmd . RemainingArguments ) ;
return new MSBuildForwardingApp ( msbuildArgs ) . Execute ( ) ;
} ) ;
return cmd . Execute ( args ) ;
}
private static string GetSingleTestProjectToRunTestIfNotProvided ( string args , List < string > remainingArguments )
{
string result = string . Empty ;
2016-10-06 04:33:54 +05:30
int projectFound = NumberOfTestProjectInRemainingArgs ( remainingArguments ) + NumberOfTestProjectInArgsRoot ( args ) ;
2016-10-04 15:37:36 +05:30
if ( projectFound > 1 )
{
throw new GracefulException (
$"Specify a single project file to run tests from." ) ;
}
else if ( projectFound = = 0 )
{
result = GetDefaultTestProject ( ) ;
}
return result ;
}
2016-10-06 04:33:54 +05:30
private static int NumberOfTestProjectInArgsRoot ( string args )
2016-10-04 15:37:36 +05:30
{
Regex pattern = new Regex ( @"^.*\..*proj$" ) ;
if ( ! string . IsNullOrEmpty ( args ) )
{
return pattern . IsMatch ( args ) ? 1 : 0 ;
}
return 0 ;
}
private static int NumberOfTestProjectInRemainingArgs ( List < string > remainingArguments )
{
int count = 0 ;
if ( remainingArguments . Count ! = 0 )
{
Regex pattern = new Regex ( @"^.*\..*proj$" ) ;
foreach ( var x in remainingArguments )
{
if ( pattern . IsMatch ( x ) )
{
count + + ;
}
}
}
return count ;
}
private static string GetDefaultTestProject ( )
{
string directory = Directory . GetCurrentDirectory ( ) ;
string [ ] projectFiles = Directory . GetFiles ( directory , "*.*proj" ) ;
if ( projectFiles . Length = = 0 )
{
throw new GracefulException (
$"Couldn't find a project to run test from. Ensure a project exists in {directory}." + Environment . NewLine +
"Or pass the path to the project" ) ;
}
else if ( projectFiles . Length > 1 )
{
throw new GracefulException (
$"Specify which project file to use because this '{directory}' contains more than one project file." ) ;
}
return projectFiles [ 0 ] ;
}
}
}