Initial commit of dotnet-test-xunit prototype
This commit is contained in:
Родитель
a883041d40
Коммит
379195a82a
|
@ -0,0 +1,12 @@
|
|||
# Before you file a bug...
|
||||
|
||||
* Did you [read the documentation](https://xunit.github.io/)?
|
||||
* Did you search the issues list to see if someone already reported it?
|
||||
* Did you create a simple repro for the problem?
|
||||
|
||||
# Before you submit a PR...
|
||||
|
||||
* Did you ensure this is an [accepted up-for-grabs issue](https://github.com/xunit/xunit/issues?q=is%3Aopen+is%3Aissue+label%3A%22%5Bs%5D+Up+For+Grabs%22)? (If not, open one to start the discussion)
|
||||
* Did you read the [project governance](https://xunit.github.io/governance.html)?
|
||||
* Does the code follow existing coding styles? (spaces, comments, no regions, etc.)?
|
||||
* Did you write unit tests?
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<clear/>
|
||||
<add key="CI Builds (aspnetvnext)" value="https://www.myget.org/F/aspnetvnext/" />
|
||||
<add key="CI Builds (dotnet)" value="https://www.myget.org/F/dotnet-cli/" />
|
||||
<add key="CI Builds (xunit)" value="https://www.myget.org/F/xunit/" />
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
||||
</packageSources>
|
||||
<disabledPackageSources>
|
||||
<add key="Microsoft and .NET" value="true" />
|
||||
</disabledPackageSources>
|
||||
</configuration>
|
|
@ -0,0 +1,36 @@
|
|||
## <a href="https://github.com/xunit/xunit"><img src="https://raw.github.com/xunit/media/master/full-logo.png" title="xUnit.net DNX Runner" /></a>
|
||||
|
||||
This runner supports [xUnit.net](https://github.com/xunit/xunit) tests for [DNX 4.5.1+, and DNX Core 5+](https://github.com/aspnet/dnx) (this includes [ASP.NET 5+](https://github.com/aspnet)).
|
||||
|
||||
### Usage
|
||||
|
||||
To install this package, ensure your project.json contains the following lines:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"dependencies": {
|
||||
"xunit": "2.1.0-*",
|
||||
"xunit.runner.dnx": "2.1.0-*"
|
||||
},
|
||||
"commands": {
|
||||
"test": "xunit.runner.dnx"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To run tests from the command line, use the following.
|
||||
|
||||
```Shell
|
||||
# Restore NuGet packages
|
||||
dnu restore
|
||||
|
||||
# Run tests in current directory
|
||||
dnx test
|
||||
|
||||
# Run tests if tests are not in the current directory
|
||||
dnx -p path/to/project test
|
||||
```
|
||||
|
||||
### More Information
|
||||
|
||||
For more complete example usage, please see [Getting Started with xUnit.net and DNX / ASP.NET 5](http://xunit.github.io/docs/getting-started-dnx.html).
|
|
@ -0,0 +1,40 @@
|
|||
param(
|
||||
[string]$target = "Test",
|
||||
[string]$verbosity = "minimal",
|
||||
[int]$maxCpuCount = 0
|
||||
)
|
||||
|
||||
# Kill all MSBUILD.EXE processes because they could very likely have a lock against our
|
||||
# MSBuild runner from when we last ran unit tests.
|
||||
get-process -name "msbuild" -ea SilentlyContinue | %{ stop-process $_.ID -force }
|
||||
|
||||
$msbuilds = @(get-command msbuild -ea SilentlyContinue)
|
||||
if ($msbuilds.Count -gt 0) {
|
||||
$msbuild = $msbuilds[0].Definition
|
||||
}
|
||||
else {
|
||||
if (test-path "env:\ProgramFiles(x86)") {
|
||||
$path = join-path ${env:ProgramFiles(x86)} "MSBuild\14.0\bin\MSBuild.exe"
|
||||
if (test-path $path) {
|
||||
$msbuild = $path
|
||||
}
|
||||
}
|
||||
if ($msbuild -eq $null) {
|
||||
$path = join-path $env:ProgramFiles "MSBuild\14.0\bin\MSBuild.exe"
|
||||
if (test-path $path) {
|
||||
$msbuild = $path
|
||||
}
|
||||
}
|
||||
if ($msbuild -eq $null) {
|
||||
throw "MSBuild could not be found in the path. Please ensure MSBuild v14 (from Visual Studio 2015) is in the path."
|
||||
}
|
||||
}
|
||||
|
||||
if ($maxCpuCount -lt 1) {
|
||||
$maxCpuCountText = $Env:MSBuildProcessorCount
|
||||
} else {
|
||||
$maxCpuCountText = ":$maxCpuCount"
|
||||
}
|
||||
|
||||
$allArgs = @("dnx.xunit.proj", "/m$maxCpuCountText", "/nologo", "/verbosity:$verbosity", "/t:$target", $args)
|
||||
& $msbuild $allArgs
|
|
@ -0,0 +1,60 @@
|
|||
#!/bin/bash
|
||||
|
||||
if ! [ -x "$(command -v mono)" ]; then
|
||||
echo >&2 "Could not find 'mono' on the path."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Installing .NET Execution Environment..."
|
||||
echo ""
|
||||
|
||||
. tools/dnvm.sh
|
||||
dnvm install 1.0.0-rc2-16177 -r coreclr -u
|
||||
if [ $? -ne 0 ]; then
|
||||
echo >&2 ".NET Execution Environment installation has failed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dnvm install 1.0.0-rc2-16177 -u
|
||||
if [ $? -ne 0 ]; then
|
||||
echo >&2 ".NET Execution Environment installation has failed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Restoring packages..."
|
||||
echo ""
|
||||
|
||||
dnvm use 1.0.0-rc2-16177
|
||||
dnu restore
|
||||
if [ $? -ne 0 ]; then
|
||||
echo >&2 "Package restore has failed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Building packages..."
|
||||
echo ""
|
||||
|
||||
dnu pack src/xunit.runner.dnx
|
||||
if [ $? -ne 0 ]; then
|
||||
echo >&2 "Build packages has failed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Running tests..."
|
||||
echo ""
|
||||
dnx -p test/test.xunit.runner.dnx test -parallel none
|
||||
if [ $? -ne 0 ]; then
|
||||
echo >&2 "Running tests on Mono has failed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dnvm use 1.0.0-rc2-16177 -r coreclr
|
||||
dnx -p test/test.xunit.runner.dnx test -parallel none
|
||||
if [ $? -ne 0 ]; then
|
||||
echo >&2 "Running tests on CoreCLR has failed."
|
||||
exit 1
|
||||
fi
|
|
@ -0,0 +1,90 @@
|
|||
<Project DefaultTargets="Test" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||
<UsingTask
|
||||
AssemblyFile="packages\xunit.buildtasks\tools\CodePlex.MSBuildTasks.dll"
|
||||
TaskName="CodePlex.MSBuildTasks.RegexReplace"/>
|
||||
<UsingTask
|
||||
AssemblyFile="packages\xunit.buildtasks\tools\CodePlex.MSBuildTasks.dll"
|
||||
TaskName="CodePlex.MSBuildTasks.Zip"/>
|
||||
|
||||
<!-- Settings -->
|
||||
|
||||
<PropertyGroup>
|
||||
<Configuration Condition="'$(Configuration)' == ''">Release</Configuration>
|
||||
<TrackFileAccess>false</TrackFileAccess>
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildProjectDirectory)</SolutionDir>
|
||||
<NuGetExePath Condition=" '$(NuGetExePath)' == '' ">$(SolutionDir)\.nuget\nuget.exe</NuGetExePath>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectFiles Include="src\**\project.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Build server targets -->
|
||||
|
||||
<Target Name="CI" DependsOnTargets="PackageRestore;SetVersionNumber;Test;ZipArtifacts" />
|
||||
|
||||
<Target Name="PackageRestore" DependsOnTargets="_DownloadNuGet">
|
||||
<Message Text="Restoring NuGet packages..." Importance="High" />
|
||||
<Exec Command=""$(NuGetExePath)" install xunit.buildtasks -Source http://www.myget.org/F/b4ff5f68eccf4f6bbfed74f055f88d8f/ -SolutionDir "$(SolutionDir)" -Verbosity quiet -ExcludeVersion" Condition="!Exists('$(SolutionDir)\packages\xunit.buildtasks\')" />
|
||||
</Target>
|
||||
|
||||
<Target Name="Build" DependsOnTargets="PackageRestore">
|
||||
<Exec Command="powershell -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned tools\dnx-build.ps1" />
|
||||
</Target>
|
||||
|
||||
<Target Name="Test" DependsOnTargets="Build">
|
||||
<Exec Command="powershell -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned tools\dnx-tests.ps1" />
|
||||
</Target>
|
||||
|
||||
<Target Name="SetVersionNumber">
|
||||
<RegexReplace
|
||||
Pattern='99\.99\.99-dev'
|
||||
Replacement='$(BuildSemanticVersion)'
|
||||
Files='@(ProjectFiles)'
|
||||
Condition=" '$(BuildSemanticVersion)' != '' "/>
|
||||
</Target>
|
||||
|
||||
<Target Name='ZipArtifacts'>
|
||||
<ItemGroup>
|
||||
<Binaries Include="src\**\*.nupkg" />
|
||||
</ItemGroup>
|
||||
|
||||
<Delete Files="binaries.zip" />
|
||||
<Zip Files="@(Binaries)" ZipFileName="binaries.zip" StripPath="true" />
|
||||
</Target>
|
||||
|
||||
<Target Name="_DownloadNuGet">
|
||||
<MakeDir Directories="$(SolutionDir)\.nuget" />
|
||||
<DownloadNuGet OutputFilename="$(NuGetExePath)" Condition="!Exists('$(NuGetExePath)')" />
|
||||
</Target>
|
||||
|
||||
<UsingTask TaskName="DownloadNuGet" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
|
||||
<ParameterGroup>
|
||||
<OutputFilename ParameterType="System.String" Required="true" />
|
||||
</ParameterGroup>
|
||||
<Task>
|
||||
<Reference Include="System.Core" />
|
||||
<Using Namespace="System" />
|
||||
<Using Namespace="System.IO" />
|
||||
<Using Namespace="System.Net" />
|
||||
<Using Namespace="Microsoft.Build.Framework" />
|
||||
<Using Namespace="Microsoft.Build.Utilities" />
|
||||
<Code Type="Fragment" Language="cs">
|
||||
<![CDATA[
|
||||
try {
|
||||
OutputFilename = Path.GetFullPath(OutputFilename);
|
||||
|
||||
Log.LogMessage("Downloading latest version of NuGet.exe...");
|
||||
WebClient webClient = new WebClient();
|
||||
webClient.DownloadFile("https://www.nuget.org/nuget.exe", OutputFilename);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.LogErrorFromException(ex);
|
||||
return false;
|
||||
}
|
||||
]]>
|
||||
</Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
</Project>
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.23107.0
|
||||
MinimumVisualStudioVersion = 14.0.22823.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8EE7A674-CE00-403B-BBDE-1C250C7A1F52}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{8B1FE5A0-EA59-456D-B293-82B806DDBEFD}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "xunit.runner.dnx", "src\xunit.runner.dnx\xunit.runner.dnx.xproj", "{002D321E-170E-4E55-BDD1-77C6353A6EB5}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "test.xunit.runner.dnx", "test\test.xunit.runner.dnx\test.xunit.runner.dnx.xproj", "{838070AB-04F2-4A37-9C86-91669E633F70}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{02FA41F5-A5D0-457A-96E7-724756124491}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
global.json = global.json
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{002D321E-170E-4E55-BDD1-77C6353A6EB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{002D321E-170E-4E55-BDD1-77C6353A6EB5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{002D321E-170E-4E55-BDD1-77C6353A6EB5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{002D321E-170E-4E55-BDD1-77C6353A6EB5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{838070AB-04F2-4A37-9C86-91669E633F70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{838070AB-04F2-4A37-9C86-91669E633F70}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{838070AB-04F2-4A37-9C86-91669E633F70}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{838070AB-04F2-4A37-9C86-91669E633F70}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{002D321E-170E-4E55-BDD1-77C6353A6EB5} = {8EE7A674-CE00-403B-BBDE-1C250C7A1F52}
|
||||
{838070AB-04F2-4A37-9C86-91669E633F70} = {8B1FE5A0-EA59-456D-B293-82B806DDBEFD}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
Двоичный файл не отображается.
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"sdk": { "version": "1.0.0-rc2-16177" },
|
||||
"sources": [ "src" ]
|
||||
}
|
|
@ -0,0 +1,299 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Xunit.Runner.DotNet
|
||||
{
|
||||
public class CommandLine
|
||||
{
|
||||
readonly Stack<string> _arguments = new Stack<string>();
|
||||
readonly IReadOnlyList<IRunnerReporter> _reporters;
|
||||
|
||||
protected CommandLine(IReadOnlyList<IRunnerReporter> reporters, string[] args, Predicate<string> fileExists = null)
|
||||
{
|
||||
_reporters = reporters;
|
||||
|
||||
if (fileExists == null)
|
||||
fileExists = fileName => File.Exists(fileName);
|
||||
|
||||
for (var i = args.Length - 1; i >= 0; i--)
|
||||
_arguments.Push(args[i]);
|
||||
|
||||
DesignTimeTestUniqueNames = new List<string>();
|
||||
Project = Parse(fileExists);
|
||||
Reporter = reporters.FirstOrDefault(r => r.IsEnvironmentallyEnabled) ?? Reporter ?? new DefaultRunnerReporter();
|
||||
}
|
||||
|
||||
public bool DiagnosticMessages { get; set; }
|
||||
|
||||
public bool Debug { get; set; }
|
||||
|
||||
public bool DesignTime { get; set; }
|
||||
|
||||
// Used with --designtime - to specify specific tests by uniqueId.
|
||||
public List<string> DesignTimeTestUniqueNames { get; private set; }
|
||||
|
||||
public bool List { get; set; }
|
||||
|
||||
public int? MaxParallelThreads { get; set; }
|
||||
|
||||
public bool NoColor { get; set; }
|
||||
|
||||
public bool NoLogo { get; set; }
|
||||
|
||||
public XunitProject Project { get; protected set; }
|
||||
|
||||
public bool? ParallelizeAssemblies { get; set; }
|
||||
|
||||
public bool? ParallelizeTestCollections { get; set; }
|
||||
|
||||
public IRunnerReporter Reporter { get; protected set; }
|
||||
|
||||
public bool Wait { get; protected set; }
|
||||
|
||||
static XunitProject GetProjectFile(List<Tuple<string, string>> assemblies)
|
||||
{
|
||||
var result = new XunitProject();
|
||||
|
||||
foreach (var assembly in assemblies)
|
||||
result.Add(new XunitProjectAssembly
|
||||
{
|
||||
AssemblyFilename = Path.GetFullPath(assembly.Item1),
|
||||
ConfigFilename = assembly.Item2 != null ? Path.GetFullPath(assembly.Item2) : null,
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void GuardNoOptionValue(KeyValuePair<string, string> option)
|
||||
{
|
||||
if (option.Value != null)
|
||||
throw new ArgumentException(string.Format("error: unknown command line option: {0}", option.Value));
|
||||
}
|
||||
|
||||
public static CommandLine Parse(IReadOnlyList<IRunnerReporter> reporters, params string[] args)
|
||||
{
|
||||
return new CommandLine(reporters, args);
|
||||
}
|
||||
|
||||
protected XunitProject Parse(Predicate<string> fileExists)
|
||||
{
|
||||
if (_arguments.Count == 0)
|
||||
throw new ArgumentException("must specify at least one assembly");
|
||||
|
||||
var assemblyFile = _arguments.Pop();
|
||||
string configFile = null;
|
||||
if (_arguments.Count > 0)
|
||||
{
|
||||
var value = _arguments.Peek();
|
||||
if (!value.StartsWith("-") && value.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
configFile = _arguments.Pop();
|
||||
if (!fileExists(configFile))
|
||||
throw new ArgumentException(string.Format("config file not found: {0}", configFile));
|
||||
}
|
||||
}
|
||||
|
||||
var assemblies = new List<Tuple<string, string>> { Tuple.Create(assemblyFile, configFile) };
|
||||
var project = GetProjectFile(assemblies);
|
||||
|
||||
while (_arguments.Count > 0)
|
||||
{
|
||||
var option = PopOption(_arguments);
|
||||
var optionName = option.Key.ToLowerInvariant();
|
||||
|
||||
if (!optionName.StartsWith("-"))
|
||||
throw new ArgumentException(string.Format("unknown command line option: {0}", option.Key));
|
||||
|
||||
optionName = optionName.Substring(1);
|
||||
|
||||
if (optionName == "nologo")
|
||||
{
|
||||
GuardNoOptionValue(option);
|
||||
NoLogo = true;
|
||||
}
|
||||
else if (optionName == "nocolor")
|
||||
{
|
||||
GuardNoOptionValue(option);
|
||||
NoColor = true;
|
||||
}
|
||||
else if (optionName == "debug")
|
||||
{
|
||||
GuardNoOptionValue(option);
|
||||
Debug = true;
|
||||
}
|
||||
else if (optionName == "wait")
|
||||
{
|
||||
GuardNoOptionValue(option);
|
||||
Wait = true;
|
||||
}
|
||||
else if (optionName == "diagnostics")
|
||||
{
|
||||
GuardNoOptionValue(option);
|
||||
DiagnosticMessages = true;
|
||||
}
|
||||
else if (optionName == "maxthreads")
|
||||
{
|
||||
if (option.Value == null)
|
||||
throw new ArgumentException("missing argument for -maxthreads");
|
||||
|
||||
switch (option.Value)
|
||||
{
|
||||
case "default":
|
||||
MaxParallelThreads = 0;
|
||||
break;
|
||||
|
||||
case "unlimited":
|
||||
MaxParallelThreads = -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
int threadValue;
|
||||
if (!int.TryParse(option.Value, out threadValue) || threadValue < 1)
|
||||
throw new ArgumentException("incorrect argument value for -maxthreads (must be 'default', 'unlimited', or a positive number)");
|
||||
|
||||
MaxParallelThreads = threadValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (optionName == "parallel")
|
||||
{
|
||||
if (option.Value == null)
|
||||
throw new ArgumentException("missing argument for -parallel");
|
||||
|
||||
ParallelismOption parallelismOption;
|
||||
if (!Enum.TryParse<ParallelismOption>(option.Value, out parallelismOption))
|
||||
throw new ArgumentException("incorrect argument value for -parallel");
|
||||
|
||||
switch (parallelismOption)
|
||||
{
|
||||
case ParallelismOption.All:
|
||||
ParallelizeAssemblies = true;
|
||||
ParallelizeTestCollections = true;
|
||||
break;
|
||||
|
||||
case ParallelismOption.Assemblies:
|
||||
ParallelizeAssemblies = true;
|
||||
ParallelizeTestCollections = false;
|
||||
break;
|
||||
|
||||
case ParallelismOption.Collections:
|
||||
ParallelizeAssemblies = false;
|
||||
ParallelizeTestCollections = true;
|
||||
break;
|
||||
|
||||
case ParallelismOption.None:
|
||||
default:
|
||||
ParallelizeAssemblies = false;
|
||||
ParallelizeTestCollections = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (optionName == "trait")
|
||||
{
|
||||
if (option.Value == null)
|
||||
throw new ArgumentException("missing argument for -trait");
|
||||
|
||||
var pieces = option.Value.Split('=');
|
||||
if (pieces.Length != 2 || string.IsNullOrEmpty(pieces[0]) || string.IsNullOrEmpty(pieces[1]))
|
||||
throw new ArgumentException("incorrect argument format for -trait (should be \"name=value\")");
|
||||
|
||||
var name = pieces[0];
|
||||
var value = pieces[1];
|
||||
project.Filters.IncludedTraits.Add(name, value);
|
||||
}
|
||||
else if (optionName == "notrait")
|
||||
{
|
||||
if (option.Value == null)
|
||||
throw new ArgumentException("missing argument for -notrait");
|
||||
|
||||
var pieces = option.Value.Split('=');
|
||||
if (pieces.Length != 2 || string.IsNullOrEmpty(pieces[0]) || string.IsNullOrEmpty(pieces[1]))
|
||||
throw new ArgumentException("incorrect argument format for -notrait (should be \"name=value\")");
|
||||
|
||||
var name = pieces[0];
|
||||
var value = pieces[1];
|
||||
project.Filters.ExcludedTraits.Add(name, value);
|
||||
}
|
||||
else if (optionName == "class")
|
||||
{
|
||||
if (option.Value == null)
|
||||
throw new ArgumentException("missing argument for -class");
|
||||
|
||||
project.Filters.IncludedClasses.Add(option.Value);
|
||||
}
|
||||
else if (optionName == "method")
|
||||
{
|
||||
if (option.Value == null)
|
||||
throw new ArgumentException("missing argument for -method");
|
||||
|
||||
project.Filters.IncludedMethods.Add(option.Value);
|
||||
}
|
||||
else if (optionName == "namespace")
|
||||
{
|
||||
if (option.Value == null)
|
||||
throw new ArgumentException("missing argument for -namespace");
|
||||
|
||||
project.Filters.IncludedNameSpaces.Add(option.Value);
|
||||
}
|
||||
// BEGIN: Special command line switches for DNX <=> Visual Studio integration
|
||||
else if (optionName == "test" || optionName == "-test")
|
||||
{
|
||||
if (option.Value == null)
|
||||
throw new ArgumentException("missing argument for --test");
|
||||
|
||||
DesignTimeTestUniqueNames.Add(option.Value);
|
||||
}
|
||||
else if (optionName == "list" || optionName == "-list")
|
||||
{
|
||||
GuardNoOptionValue(option);
|
||||
List = true;
|
||||
}
|
||||
else if (optionName == "designtime" || optionName == "-designtime")
|
||||
{
|
||||
GuardNoOptionValue(option);
|
||||
DesignTime = true;
|
||||
}
|
||||
// END: Special command line switches for DNX <=> Visual Studio integration
|
||||
else
|
||||
{
|
||||
// Might be a reporter...
|
||||
var reporter = _reporters.FirstOrDefault(r => string.Equals(r.RunnerSwitch, optionName, StringComparison.OrdinalIgnoreCase));
|
||||
if (reporter != null)
|
||||
{
|
||||
GuardNoOptionValue(option);
|
||||
if (Reporter != null)
|
||||
throw new ArgumentException("only one reporter is allowed");
|
||||
|
||||
Reporter = reporter;
|
||||
}
|
||||
// ...or an result output file
|
||||
else
|
||||
{
|
||||
if (!TransformFactory.AvailableTransforms.Any(t => t.CommandLine.Equals(optionName, StringComparison.OrdinalIgnoreCase)))
|
||||
throw new ArgumentException($"unknown option: {option.Key}");
|
||||
|
||||
if (option.Value == null)
|
||||
throw new ArgumentException(string.Format("missing filename for {0}", option.Key));
|
||||
|
||||
project.Output.Add(optionName, option.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return project;
|
||||
}
|
||||
|
||||
static KeyValuePair<string, string> PopOption(Stack<string> arguments)
|
||||
{
|
||||
var option = arguments.Pop();
|
||||
string value = null;
|
||||
|
||||
if (arguments.Count > 0 && !arguments.Peek().StartsWith("-"))
|
||||
value = arguments.Pop();
|
||||
|
||||
return new KeyValuePair<string, string>(option, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#if !DNXCORE50
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
internal static class AssemblyExtensions
|
||||
{
|
||||
public static string GetLocalCodeBase(this Assembly assembly)
|
||||
{
|
||||
string codeBase = assembly.CodeBase;
|
||||
if (codeBase == null)
|
||||
return null;
|
||||
|
||||
if (!codeBase.StartsWith("file:///"))
|
||||
throw new ArgumentException(string.Format("Code base {0} in wrong format; must start with file:///", codeBase), "assembly");
|
||||
|
||||
codeBase = codeBase.Substring(8);
|
||||
if (Path.DirectorySeparatorChar == '/')
|
||||
return "/" + codeBase;
|
||||
|
||||
return codeBase.Replace('/', Path.DirectorySeparatorChar);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
internal static class DictionaryExtensions
|
||||
{
|
||||
public static void Add<TKey, TValue>(this IDictionary<TKey, List<TValue>> dictionary, TKey key, TValue value)
|
||||
{
|
||||
dictionary.GetOrAdd(key).Add(value);
|
||||
}
|
||||
|
||||
public static bool Contains<TKey, TValue>(this IDictionary<TKey, List<TValue>> dictionary, TKey key, TValue value, IEqualityComparer<TValue> valueComparer)
|
||||
{
|
||||
List<TValue> values;
|
||||
|
||||
if (!dictionary.TryGetValue(key, out values))
|
||||
return false;
|
||||
|
||||
return values.Contains(value, valueComparer);
|
||||
}
|
||||
|
||||
public static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
|
||||
where TValue : new()
|
||||
{
|
||||
return dictionary.GetOrAdd<TKey, TValue>(key, () => new TValue());
|
||||
}
|
||||
|
||||
public static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, Func<TValue> newValue)
|
||||
{
|
||||
TValue result;
|
||||
|
||||
if (!dictionary.TryGetValue(key, out result))
|
||||
{
|
||||
result = newValue();
|
||||
dictionary[key] = result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
/// <summary>
|
||||
/// Guard class, used for guard clauses and argument validation
|
||||
/// </summary>
|
||||
internal static class Guard
|
||||
{
|
||||
/// <summary/>
|
||||
public static void ArgumentNotNull(string argName, object argValue)
|
||||
{
|
||||
if (argValue == null)
|
||||
throw new ArgumentNullException(argName);
|
||||
}
|
||||
|
||||
/// <summary/>
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This method may not be called by all users of Guard.")]
|
||||
public static void ArgumentNotNullOrEmpty(string argName, IEnumerable argValue)
|
||||
{
|
||||
ArgumentNotNull(argName, argValue);
|
||||
|
||||
if (!argValue.GetEnumerator().MoveNext())
|
||||
throw new ArgumentException("Argument was empty", argName);
|
||||
}
|
||||
|
||||
/// <summary/>
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This method may not be called by all users of Guard.")]
|
||||
public static void ArgumentValid(string argName, string message, bool test)
|
||||
{
|
||||
if (!test)
|
||||
throw new ArgumentException(message, argName);
|
||||
}
|
||||
|
||||
/// <summary/>
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This method may not be called by all users of Guard.")]
|
||||
public static void FileExists(string argName, string fileName)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System.Collections.Generic;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
#if XUNIT_CORE_DLL
|
||||
namespace Xunit.Sdk
|
||||
#else
|
||||
namespace Xunit
|
||||
#endif
|
||||
{
|
||||
internal class TestDiscoveryVisitor : TestMessageVisitor<IDiscoveryCompleteMessage>
|
||||
{
|
||||
public TestDiscoveryVisitor()
|
||||
{
|
||||
TestCases = new List<ITestCase>();
|
||||
}
|
||||
|
||||
public List<ITestCase> TestCases { get; private set; }
|
||||
|
||||
protected override bool Visit(ITestCaseDiscoveryMessage discovery)
|
||||
{
|
||||
TestCases.Add(discovery.TestCase);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,275 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Globalization;
|
||||
using System.Xml.Linq;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Xunit
|
||||
{
|
||||
public class XmlTestExecutionVisitor : TestMessageVisitor<ITestAssemblyFinished>
|
||||
{
|
||||
readonly XElement _assemblyElement;
|
||||
readonly XElement _errorsElement;
|
||||
readonly ConcurrentDictionary<ITestCollection, XElement> _testCollectionElements = new ConcurrentDictionary<ITestCollection, XElement>();
|
||||
|
||||
public XmlTestExecutionVisitor(XElement assemblyElement, Func<bool> cancelThunk)
|
||||
{
|
||||
CancelThunk = cancelThunk ?? (() => false);
|
||||
|
||||
_assemblyElement = assemblyElement;
|
||||
|
||||
if (_assemblyElement != null)
|
||||
{
|
||||
_errorsElement = new XElement("errors");
|
||||
_assemblyElement.Add(_errorsElement);
|
||||
}
|
||||
}
|
||||
|
||||
public readonly Func<bool> CancelThunk;
|
||||
public int Errors;
|
||||
public int Failed;
|
||||
public int Skipped;
|
||||
public decimal Time;
|
||||
public int Total;
|
||||
|
||||
XElement CreateTestResultElement(ITestResultMessage testResult, string resultText)
|
||||
{
|
||||
var collectionElement = GetTestCollectionElement(testResult.TestCase.TestMethod.TestClass.TestCollection);
|
||||
var testResultElement =
|
||||
new XElement("test",
|
||||
new XAttribute("name", XmlEscape(testResult.Test.DisplayName)),
|
||||
new XAttribute("type", testResult.TestCase.TestMethod.TestClass.Class.Name),
|
||||
new XAttribute("method", testResult.TestCase.TestMethod.Method.Name),
|
||||
new XAttribute("time", testResult.ExecutionTime.ToString(CultureInfo.InvariantCulture)),
|
||||
new XAttribute("result", resultText)
|
||||
);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(testResult.Output))
|
||||
{
|
||||
testResultElement.Add(new XElement("output", new XCData(testResult.Output)));
|
||||
}
|
||||
|
||||
if (testResult.TestCase.SourceInformation != null)
|
||||
{
|
||||
if (testResult.TestCase.SourceInformation.FileName != null)
|
||||
testResultElement.Add(new XAttribute("source-file", testResult.TestCase.SourceInformation.FileName));
|
||||
if (testResult.TestCase.SourceInformation.LineNumber != null)
|
||||
testResultElement.Add(new XAttribute("source-line", testResult.TestCase.SourceInformation.LineNumber.GetValueOrDefault()));
|
||||
}
|
||||
|
||||
if (testResult.TestCase.Traits != null && testResult.TestCase.Traits.Count > 0)
|
||||
{
|
||||
var traitsElement = new XElement("traits");
|
||||
|
||||
foreach (var key in testResult.TestCase.Traits.Keys)
|
||||
foreach (var value in testResult.TestCase.Traits[key])
|
||||
traitsElement.Add(
|
||||
new XElement("trait",
|
||||
new XAttribute("name", XmlEscape(key)),
|
||||
new XAttribute("value", XmlEscape(value))
|
||||
)
|
||||
);
|
||||
|
||||
testResultElement.Add(traitsElement);
|
||||
}
|
||||
|
||||
collectionElement.Add(testResultElement);
|
||||
|
||||
return testResultElement;
|
||||
}
|
||||
|
||||
XElement GetTestCollectionElement(ITestCollection testCollection)
|
||||
{
|
||||
return _testCollectionElements.GetOrAdd(testCollection, tc => new XElement("collection"));
|
||||
}
|
||||
|
||||
public override bool OnMessage(IMessageSinkMessage message)
|
||||
{
|
||||
var result = base.OnMessage(message);
|
||||
if (result)
|
||||
result = !CancelThunk();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected override bool Visit(ITestAssemblyFinished assemblyFinished)
|
||||
{
|
||||
Total += assemblyFinished.TestsRun;
|
||||
Failed += assemblyFinished.TestsFailed;
|
||||
Skipped += assemblyFinished.TestsSkipped;
|
||||
Time += assemblyFinished.ExecutionTime;
|
||||
|
||||
if (_assemblyElement != null)
|
||||
{
|
||||
_assemblyElement.Add(
|
||||
new XAttribute("total", Total),
|
||||
new XAttribute("passed", Total - Failed - Skipped),
|
||||
new XAttribute("failed", Failed),
|
||||
new XAttribute("skipped", Skipped),
|
||||
new XAttribute("time", Time.ToString("0.000", CultureInfo.InvariantCulture)),
|
||||
new XAttribute("errors", Errors)
|
||||
);
|
||||
|
||||
foreach (var element in _testCollectionElements.Values)
|
||||
_assemblyElement.Add(element);
|
||||
}
|
||||
|
||||
return base.Visit(assemblyFinished);
|
||||
}
|
||||
|
||||
protected override bool Visit(ITestAssemblyStarting assemblyStarting)
|
||||
{
|
||||
if (_assemblyElement != null)
|
||||
{
|
||||
_assemblyElement.Add(
|
||||
new XAttribute("name", assemblyStarting.TestAssembly.Assembly.AssemblyPath),
|
||||
new XAttribute("environment", assemblyStarting.TestEnvironment),
|
||||
new XAttribute("test-framework", assemblyStarting.TestFrameworkDisplayName),
|
||||
new XAttribute("run-date", assemblyStarting.StartTime.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture)),
|
||||
new XAttribute("run-time", assemblyStarting.StartTime.ToString("HH:mm:ss", CultureInfo.InvariantCulture))
|
||||
);
|
||||
|
||||
if (assemblyStarting.TestAssembly.ConfigFileName != null)
|
||||
_assemblyElement.Add(new XAttribute("config-file", assemblyStarting.TestAssembly.ConfigFileName));
|
||||
}
|
||||
|
||||
return base.Visit(assemblyStarting);
|
||||
}
|
||||
|
||||
protected override bool Visit(ITestCollectionFinished testCollectionFinished)
|
||||
{
|
||||
if (_assemblyElement != null)
|
||||
{
|
||||
var collectionElement = GetTestCollectionElement(testCollectionFinished.TestCollection);
|
||||
collectionElement.Add(
|
||||
new XAttribute("total", testCollectionFinished.TestsRun),
|
||||
new XAttribute("passed", testCollectionFinished.TestsRun - testCollectionFinished.TestsFailed - testCollectionFinished.TestsSkipped),
|
||||
new XAttribute("failed", testCollectionFinished.TestsFailed),
|
||||
new XAttribute("skipped", testCollectionFinished.TestsSkipped),
|
||||
new XAttribute("name", XmlEscape(testCollectionFinished.TestCollection.DisplayName)),
|
||||
new XAttribute("time", testCollectionFinished.ExecutionTime.ToString("0.000", CultureInfo.InvariantCulture))
|
||||
);
|
||||
}
|
||||
|
||||
return base.Visit(testCollectionFinished);
|
||||
}
|
||||
|
||||
protected override bool Visit(ITestFailed testFailed)
|
||||
{
|
||||
if (_assemblyElement != null)
|
||||
{
|
||||
var testElement = CreateTestResultElement(testFailed, "Fail");
|
||||
testElement.Add(CreateFailureElement(testFailed));
|
||||
}
|
||||
|
||||
return base.Visit(testFailed);
|
||||
}
|
||||
|
||||
protected override bool Visit(ITestPassed testPassed)
|
||||
{
|
||||
if (_assemblyElement != null)
|
||||
CreateTestResultElement(testPassed, "Pass");
|
||||
|
||||
return base.Visit(testPassed);
|
||||
}
|
||||
|
||||
protected override bool Visit(ITestSkipped testSkipped)
|
||||
{
|
||||
if (_assemblyElement != null)
|
||||
{
|
||||
var testElement = CreateTestResultElement(testSkipped, "Skip");
|
||||
testElement.Add(new XElement("reason", new XCData(XmlEscape(testSkipped.Reason))));
|
||||
}
|
||||
|
||||
return base.Visit(testSkipped);
|
||||
}
|
||||
|
||||
protected override bool Visit(IErrorMessage error)
|
||||
{
|
||||
AddError("fatal", null, error);
|
||||
|
||||
return base.Visit(error);
|
||||
}
|
||||
|
||||
protected override bool Visit(ITestAssemblyCleanupFailure cleanupFailure)
|
||||
{
|
||||
AddError("assembly-cleanup", cleanupFailure.TestAssembly.Assembly.AssemblyPath, cleanupFailure);
|
||||
|
||||
return base.Visit(cleanupFailure);
|
||||
}
|
||||
|
||||
protected override bool Visit(ITestCaseCleanupFailure cleanupFailure)
|
||||
{
|
||||
AddError("test-case-cleanup", cleanupFailure.TestCase.DisplayName, cleanupFailure);
|
||||
|
||||
return base.Visit(cleanupFailure);
|
||||
}
|
||||
|
||||
protected override bool Visit(ITestClassCleanupFailure cleanupFailure)
|
||||
{
|
||||
AddError("test-class-cleanup", cleanupFailure.TestClass.Class.Name, cleanupFailure);
|
||||
|
||||
return base.Visit(cleanupFailure);
|
||||
}
|
||||
|
||||
protected override bool Visit(ITestCollectionCleanupFailure cleanupFailure)
|
||||
{
|
||||
AddError("test-collection-cleanup", cleanupFailure.TestCollection.DisplayName, cleanupFailure);
|
||||
|
||||
return base.Visit(cleanupFailure);
|
||||
}
|
||||
|
||||
protected override bool Visit(ITestCleanupFailure cleanupFailure)
|
||||
{
|
||||
AddError("test-cleanup", cleanupFailure.Test.DisplayName, cleanupFailure);
|
||||
|
||||
return base.Visit(cleanupFailure);
|
||||
}
|
||||
|
||||
protected override bool Visit(ITestMethodCleanupFailure cleanupFailure)
|
||||
{
|
||||
AddError("test-method-cleanup", cleanupFailure.TestMethod.Method.Name, cleanupFailure);
|
||||
|
||||
return base.Visit(cleanupFailure);
|
||||
}
|
||||
|
||||
void AddError(string type, string name, IFailureInformation failureInfo)
|
||||
{
|
||||
Errors++;
|
||||
|
||||
if (_errorsElement == null)
|
||||
return;
|
||||
|
||||
var errorElement = new XElement("error", new XAttribute("type", type), CreateFailureElement(failureInfo));
|
||||
if (name != null)
|
||||
errorElement.Add(new XAttribute("name", name));
|
||||
|
||||
_errorsElement.Add(errorElement);
|
||||
}
|
||||
|
||||
static XElement CreateFailureElement(IFailureInformation failureInfo)
|
||||
{
|
||||
return new XElement("failure",
|
||||
new XAttribute("exception-type", failureInfo.ExceptionTypes[0]),
|
||||
new XElement("message", new XCData(XmlEscape(ExceptionUtility.CombineMessages(failureInfo)))),
|
||||
new XElement("stack-trace", new XCData(ExceptionUtility.CombineStackTraces(failureInfo) ?? string.Empty))
|
||||
);
|
||||
}
|
||||
|
||||
protected static string Escape(string value)
|
||||
{
|
||||
if (value == null)
|
||||
return string.Empty;
|
||||
|
||||
return value.Replace("\r", "\\r").Replace("\n", "\\n").Replace("\t", "\\t").Replace("\0", "\\0");
|
||||
}
|
||||
|
||||
protected static string XmlEscape(string value)
|
||||
{
|
||||
if (value == null)
|
||||
return string.Empty;
|
||||
|
||||
return value.Replace("\0", "\\0");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
using System;
|
||||
|
||||
namespace Xunit
|
||||
{
|
||||
/// <summary>
|
||||
/// An implementation of <see cref="IRunnerLogger"/> which logs messages
|
||||
/// to <see cref="Console"/> and <see cref="Console.Error"/>.
|
||||
/// </summary>
|
||||
public class ConsoleRunnerLogger : IRunnerLogger
|
||||
{
|
||||
readonly object _lockObject = new object();
|
||||
readonly bool _useColors;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConsoleRunnerLogger"/> class.
|
||||
/// </summary>
|
||||
/// <param name="useColors">A flag to indicate whether colors should be used when
|
||||
/// logging messages.</param>
|
||||
public ConsoleRunnerLogger(bool useColors)
|
||||
{
|
||||
_useColors = useColors;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object LockObject
|
||||
{
|
||||
get { return _lockObject; }
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void LogError(StackFrameInfo stackFrame, string message)
|
||||
{
|
||||
using (SetColor(ConsoleColor.Red))
|
||||
lock (LockObject)
|
||||
Console.Error.WriteLine(message);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void LogImportantMessage(StackFrameInfo stackFrame, string message)
|
||||
{
|
||||
using (SetColor(ConsoleColor.Gray))
|
||||
lock (LockObject)
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void LogMessage(StackFrameInfo stackFrame, string message)
|
||||
{
|
||||
using (SetColor(ConsoleColor.DarkGray))
|
||||
lock (LockObject)
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void LogWarning(StackFrameInfo stackFrame, string message)
|
||||
{
|
||||
using (SetColor(ConsoleColor.Yellow))
|
||||
lock (LockObject)
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
|
||||
IDisposable SetColor(ConsoleColor color)
|
||||
{
|
||||
return _useColors ? new ColorRestorer(color) : null;
|
||||
}
|
||||
|
||||
class ColorRestorer : IDisposable
|
||||
{
|
||||
public ColorRestorer(ConsoleColor color)
|
||||
{
|
||||
Console.ForegroundColor = color;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Console.ResetColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Testing.Abstractions;
|
||||
using Xunit.Abstractions;
|
||||
using VsTestCase = Microsoft.Extensions.Testing.Abstractions.Test;
|
||||
|
||||
namespace Xunit.Runner.DotNet
|
||||
{
|
||||
public class DesignTimeExecutionVisitor : TestMessageVisitor<ITestAssemblyFinished>, IExecutionVisitor
|
||||
{
|
||||
private readonly ITestExecutionSink _sink;
|
||||
private readonly IDictionary<ITestCase, VsTestCase> _conversions;
|
||||
private readonly IMessageSink _next;
|
||||
|
||||
public DesignTimeExecutionVisitor(ITestExecutionSink sink, IDictionary<ITestCase, VsTestCase> conversions, IMessageSink next)
|
||||
{
|
||||
_sink = sink;
|
||||
_conversions = conversions;
|
||||
_next = next;
|
||||
|
||||
ExecutionSummary = new ExecutionSummary();
|
||||
}
|
||||
|
||||
public ExecutionSummary ExecutionSummary { get; private set; }
|
||||
|
||||
protected override bool Visit(ITestStarting testStarting)
|
||||
{
|
||||
var test = _conversions[testStarting.TestCase];
|
||||
|
||||
if (_sink != null)
|
||||
_sink.RecordStart(test);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool Visit(ITestSkipped testSkipped)
|
||||
{
|
||||
var test = _conversions[testSkipped.TestCase];
|
||||
|
||||
if (_sink != null)
|
||||
_sink.RecordResult(new TestResult(test) { Outcome = TestOutcome.Skipped });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool Visit(ITestFailed testFailed)
|
||||
{
|
||||
var test = _conversions[testFailed.TestCase];
|
||||
var result = new TestResult(test)
|
||||
{
|
||||
Outcome = TestOutcome.Failed,
|
||||
Duration = TimeSpan.FromSeconds((double)testFailed.ExecutionTime),
|
||||
ErrorMessage = string.Join(Environment.NewLine, testFailed.Messages),
|
||||
ErrorStackTrace = string.Join(Environment.NewLine, testFailed.StackTraces),
|
||||
};
|
||||
|
||||
result.Messages.Add(testFailed.Output);
|
||||
|
||||
if (_sink != null)
|
||||
_sink.RecordResult(result);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool Visit(ITestPassed testPassed)
|
||||
{
|
||||
var test = _conversions[testPassed.TestCase];
|
||||
|
||||
if (_sink != null)
|
||||
{
|
||||
_sink.RecordResult(new TestResult(test)
|
||||
{
|
||||
Outcome = TestOutcome.Passed,
|
||||
Duration = TimeSpan.FromSeconds((double)testPassed.ExecutionTime),
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool Visit(ITestAssemblyFinished assemblyFinished)
|
||||
{
|
||||
var result = base.Visit(assemblyFinished);
|
||||
|
||||
ExecutionSummary = new ExecutionSummary
|
||||
{
|
||||
Failed = assemblyFinished.TestsFailed,
|
||||
Skipped = assemblyFinished.TestsSkipped,
|
||||
Time = assemblyFinished.ExecutionTime,
|
||||
Total = assemblyFinished.TestsRun
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override bool OnMessage(IMessageSinkMessage message)
|
||||
{
|
||||
return
|
||||
base.OnMessage(message) &&
|
||||
_next.OnMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Xunit.Abstractions;
|
||||
using VsTestCase = Microsoft.Extensions.Testing.Abstractions.Test;
|
||||
|
||||
namespace Xunit.Runner.DotNet
|
||||
{
|
||||
public static class DesignTimeTestConverter
|
||||
{
|
||||
#if DNXCORE50
|
||||
private readonly static HashAlgorithm Hash = SHA1.Create();
|
||||
#else
|
||||
private readonly static HashAlgorithm _hash = new SHA1Managed();
|
||||
#endif
|
||||
public static IDictionary<ITestCase, VsTestCase> Convert(IEnumerable<ITestCase> testcases)
|
||||
{
|
||||
// When tests have the same class name and method name, generate unique names for display
|
||||
var groups = testcases
|
||||
.Select(tc => new
|
||||
{
|
||||
testcase = tc,
|
||||
shortName = GetShortName(tc),
|
||||
fullyQualifiedName = string.Format("{0}.{1}", tc.TestMethod.TestClass.Class.Name, tc.TestMethod.Method.Name)
|
||||
})
|
||||
.GroupBy(tc => tc.fullyQualifiedName);
|
||||
|
||||
var results = new Dictionary<ITestCase, VsTestCase>();
|
||||
foreach (var group in groups)
|
||||
{
|
||||
var uniquifyNames = group.Count() > 1;
|
||||
foreach (var testcase in group)
|
||||
{
|
||||
results.Add(
|
||||
testcase.testcase,
|
||||
Convert(
|
||||
testcase.testcase,
|
||||
testcase.shortName,
|
||||
testcase.fullyQualifiedName,
|
||||
uniquifyNames));
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private static string GetShortName(ITestCase tc)
|
||||
{
|
||||
var shortName = new StringBuilder();
|
||||
|
||||
var classFullName = tc.TestMethod.TestClass.Class.Name;
|
||||
var dotIndex = classFullName.LastIndexOf('.');
|
||||
if (dotIndex >= 0)
|
||||
shortName.Append(classFullName.Substring(dotIndex + 1));
|
||||
else
|
||||
shortName.Append(classFullName);
|
||||
|
||||
shortName.Append(".");
|
||||
shortName.Append(tc.TestMethod.Method.Name);
|
||||
|
||||
// We need to shorten the arguments list if it's long. Let's arbitrarily pick 50 characters.
|
||||
var argumentsIndex = tc.DisplayName.IndexOf('(');
|
||||
if (argumentsIndex >= 0 && tc.DisplayName.Length - argumentsIndex > 50)
|
||||
{
|
||||
shortName.Append(tc.DisplayName.Substring(argumentsIndex, 46));
|
||||
shortName.Append("...");
|
||||
shortName.Append(")");
|
||||
}
|
||||
else if (argumentsIndex >= 0)
|
||||
shortName.Append(tc.DisplayName.Substring(argumentsIndex));
|
||||
|
||||
return shortName.ToString();
|
||||
}
|
||||
|
||||
private static VsTestCase Convert(
|
||||
ITestCase testcase,
|
||||
string shortName,
|
||||
string fullyQualifiedName,
|
||||
bool uniquifyNames)
|
||||
{
|
||||
string uniqueName;
|
||||
if (uniquifyNames)
|
||||
uniqueName = string.Format("{0}({1})", fullyQualifiedName, testcase.UniqueID);
|
||||
else
|
||||
uniqueName = fullyQualifiedName;
|
||||
|
||||
var result = new VsTestCase();
|
||||
result.DisplayName = shortName;
|
||||
result.FullyQualifiedName = uniqueName;
|
||||
|
||||
result.Id = GuidFromString(testcase.UniqueID);
|
||||
|
||||
if (testcase.SourceInformation != null)
|
||||
{
|
||||
result.CodeFilePath = testcase.SourceInformation.FileName;
|
||||
result.LineNumber = testcase.SourceInformation.LineNumber;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Guid GuidFromString(string data)
|
||||
{
|
||||
var hash = Hash.ComputeHash(Encoding.Unicode.GetBytes(data));
|
||||
var b = new byte[16];
|
||||
Array.Copy((Array)hash, (Array)b, 16);
|
||||
return new Guid(b);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
using Xunit.Abstractions;
|
||||
using TestHostSourceInformationProvider = Microsoft.Extensions.Testing.Abstractions.ISourceInformationProvider;
|
||||
|
||||
namespace Xunit.Runner.DotNet
|
||||
{
|
||||
public class SourceInformationProviderAdapater : ISourceInformationProvider
|
||||
{
|
||||
private readonly TestHostSourceInformationProvider _provider;
|
||||
|
||||
public SourceInformationProviderAdapater(TestHostSourceInformationProvider provider)
|
||||
{
|
||||
_provider = provider;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
public ISourceInformation GetSourceInformation(ITestCase testCase)
|
||||
{
|
||||
if (_provider == null)
|
||||
return null;
|
||||
|
||||
var reflectionMethodInfo = testCase.TestMethod.Method as IReflectionMethodInfo;
|
||||
if (reflectionMethodInfo == null)
|
||||
return null;
|
||||
|
||||
var innerInformation = _provider.GetSourceInformation(reflectionMethodInfo.MethodInfo);
|
||||
if (innerInformation == null)
|
||||
return null;
|
||||
|
||||
return new SourceInformation
|
||||
{
|
||||
FileName = innerInformation.Filename,
|
||||
LineNumber = innerInformation.LineNumber,
|
||||
};
|
||||
}
|
||||
|
||||
private class SourceInformation : ISourceInformation
|
||||
{
|
||||
public string FileName { get; set; }
|
||||
|
||||
public int? LineNumber { get; set; }
|
||||
|
||||
public void Deserialize(IXunitSerializationInfo info)
|
||||
{
|
||||
FileName = info.GetValue<string>("FileName");
|
||||
LineNumber = info.GetValue<int?>("LineNumber");
|
||||
}
|
||||
|
||||
public void Serialize(IXunitSerializationInfo info)
|
||||
{
|
||||
info.AddValue("FileName", FileName, typeof(string));
|
||||
info.AddValue("LineNumber", LineNumber, typeof(int?));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace Xunit.Runner.DotNet
|
||||
{
|
||||
public enum ParallelismOption
|
||||
{
|
||||
None,
|
||||
Collections,
|
||||
Assemblies,
|
||||
All
|
||||
}
|
||||
}
|
|
@ -0,0 +1,464 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.Extensions.Testing.Abstractions;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.ProjectModel.Loader;
|
||||
using NuGet.Frameworks;
|
||||
using Xunit.Abstractions;
|
||||
using ISourceInformationProvider = Xunit.Abstractions.ISourceInformationProvider;
|
||||
using VsTestCase = Microsoft.Extensions.Testing.Abstractions.Test;
|
||||
|
||||
namespace Xunit.Runner.DotNet
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
#pragma warning disable 0649
|
||||
volatile bool _cancel;
|
||||
#pragma warning restore 0649
|
||||
readonly ConcurrentDictionary<string, ExecutionSummary> _completionMessages = new ConcurrentDictionary<string, ExecutionSummary>();
|
||||
bool _failed;
|
||||
IRunnerLogger _logger;
|
||||
IMessageSink _reporterMessageHandler;
|
||||
readonly ITestDiscoverySink _testDiscoverySink;
|
||||
readonly ITestExecutionSink _testExecutionSink;
|
||||
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
DebugHelper.HandleDebugSwitch(ref args);
|
||||
|
||||
var dllPath = args[0];
|
||||
var projectPath = GetProjectPathFromDllPath(dllPath);
|
||||
AssemblyLoadContext.InitializeDefaultContext(ProjectContext.Create(projectPath, FrameworkConstants.CommonFrameworks.DnxCore50, new[] { RuntimeIdentifier.Current }).CreateLoadContext());
|
||||
|
||||
return new Program().Run(args);
|
||||
}
|
||||
|
||||
// This is a temporary workaround.
|
||||
private static string GetProjectPathFromDllPath(string dllPath)
|
||||
{
|
||||
var directory = new DirectoryInfo(Path.GetDirectoryName(dllPath));
|
||||
while (directory != directory.Root && directory.EnumerateFiles().All(f => f.Name != "project.json"))
|
||||
{
|
||||
directory = directory.Parent;
|
||||
}
|
||||
|
||||
var projectFile = directory.EnumerateFiles().FirstOrDefault(f => f.Name == "project.json");
|
||||
|
||||
return projectFile?.FullName;
|
||||
}
|
||||
|
||||
public Program()
|
||||
{
|
||||
_testDiscoverySink = new StreamingTestDiscoverySink(Console.OpenStandardOutput());
|
||||
|
||||
_testExecutionSink = new StreamingTestExecutionSink(Console.OpenStandardOutput());
|
||||
}
|
||||
|
||||
public int Run(string[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
var reporters = GetAvailableRunnerReporters();
|
||||
|
||||
if (args.Length == 0 || args.Any(arg => arg == "-?"))
|
||||
{
|
||||
PrintHeader();
|
||||
PrintUsage(reporters);
|
||||
return 2;
|
||||
}
|
||||
|
||||
#if !DNXCORE50
|
||||
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
|
||||
#endif
|
||||
|
||||
var commandLine = CommandLine.Parse(reporters, args);
|
||||
|
||||
#if !DNXCORE50
|
||||
if (commandLine.Debug)
|
||||
Debugger.Launch();
|
||||
#else
|
||||
if (commandLine.Debug)
|
||||
{
|
||||
Console.WriteLine("Debug support is not available in DNX Core.");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
_logger = new ConsoleRunnerLogger(!commandLine.NoColor);
|
||||
_reporterMessageHandler = commandLine.Reporter.CreateMessageHandler(_logger);
|
||||
|
||||
if (!commandLine.NoLogo)
|
||||
PrintHeader();
|
||||
|
||||
var failCount = RunProject(commandLine.Project, commandLine.ParallelizeAssemblies, commandLine.ParallelizeTestCollections,
|
||||
commandLine.MaxParallelThreads, commandLine.DiagnosticMessages, commandLine.NoColor,
|
||||
commandLine.DesignTime, commandLine.List, commandLine.DesignTimeTestUniqueNames);
|
||||
|
||||
if (commandLine.Wait)
|
||||
{
|
||||
Console.WriteLine();
|
||||
|
||||
Console.Write("Press ENTER to continue...");
|
||||
Console.ReadLine();
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
return failCount > 0 ? 1 : 0;
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
Console.WriteLine("error: {0}", ex.Message);
|
||||
return 3;
|
||||
}
|
||||
catch (BadImageFormatException ex)
|
||||
{
|
||||
Console.WriteLine("{0}", ex.Message);
|
||||
return 4;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.ResetColor();
|
||||
}
|
||||
}
|
||||
|
||||
#if !DNXCORE50
|
||||
static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
var ex = e.ExceptionObject as Exception;
|
||||
|
||||
if (ex != null)
|
||||
Console.WriteLine(ex.ToString());
|
||||
else
|
||||
Console.WriteLine("Error of unknown type thrown in application domain");
|
||||
|
||||
Environment.Exit(1);
|
||||
}
|
||||
#endif
|
||||
static List<IRunnerReporter> GetAvailableRunnerReporters()
|
||||
{
|
||||
var result = new List<IRunnerReporter>();
|
||||
var runnerPath = Path.GetDirectoryName(AppContext.BaseDirectory);
|
||||
|
||||
foreach (var dllFile in Directory.GetFiles(runnerPath, "*.dll").Select(f => Path.Combine(runnerPath, f)))
|
||||
{
|
||||
TypeInfo[] types;
|
||||
|
||||
var dllName = Path.GetFileNameWithoutExtension(dllFile);
|
||||
|
||||
try
|
||||
{
|
||||
var assembly = Assembly.Load(new AssemblyName(dllName));
|
||||
types = assembly.DefinedTypes.ToArray();
|
||||
}
|
||||
catch
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
if (type == null || type.IsAbstract || type == typeof(DefaultRunnerReporter).GetTypeInfo() || type.ImplementedInterfaces.All(i => i != typeof (IRunnerReporter)))
|
||||
continue;
|
||||
|
||||
var ctor = type.DeclaredConstructors.FirstOrDefault(c => c.GetParameters().Length == 0);
|
||||
if (ctor == null)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.WriteLine($"Type {type.FullName} in assembly {dllFile} appears to be a runner reporter, but does not have an empty constructor.");
|
||||
Console.ResetColor();
|
||||
continue;
|
||||
}
|
||||
|
||||
result.Add((IRunnerReporter)ctor.Invoke(new object[0]));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PrintHeader()
|
||||
{
|
||||
Console.WriteLine("xUnit.net DNX Runner ({0}-bit {1})", IntPtr.Size * 8, RuntimeIdentifier.Current);
|
||||
}
|
||||
|
||||
static void PrintUsage(IReadOnlyList<IRunnerReporter> reporters)
|
||||
{
|
||||
Console.WriteLine("Copyright (C) 2015 Outercurve Foundation.");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("usage: xunit.runner.dnx [configFile.json] [options] [reporter] [resultFormat filename [...]]");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Valid options:");
|
||||
Console.WriteLine(" -nologo : do not show the copyright message");
|
||||
Console.WriteLine(" -nocolor : do not output results with colors");
|
||||
Console.WriteLine(" -parallel option : set parallelization based on option");
|
||||
Console.WriteLine(" : none - turn off all parallelization");
|
||||
Console.WriteLine(" : collections - only parallelize collections");
|
||||
Console.WriteLine(" : assemblies - only parallelize assemblies");
|
||||
Console.WriteLine(" : all - parallelize collections and assemblies");
|
||||
Console.WriteLine(" -maxthreads count : maximum thread count for collection parallelization");
|
||||
Console.WriteLine(" : default - run with default (1 thread per CPU thread)");
|
||||
Console.WriteLine(" : unlimited - run with unbounded thread count");
|
||||
Console.WriteLine(" : (number) - limit task thread pool size to 'count'");
|
||||
Console.WriteLine(" -wait : wait for input after completion");
|
||||
Console.WriteLine(" -diagnostics : enable diagnostics messages for all test assemblies");
|
||||
#if !DNXCORE50
|
||||
Console.WriteLine(" -debug : launch the debugger to debug the tests");
|
||||
#endif
|
||||
Console.WriteLine(" -trait \"name=value\" : only run tests with matching name/value traits");
|
||||
Console.WriteLine(" : if specified more than once, acts as an OR operation");
|
||||
Console.WriteLine(" -notrait \"name=value\" : do not run tests with matching name/value traits");
|
||||
Console.WriteLine(" : if specified more than once, acts as an AND operation");
|
||||
Console.WriteLine(" -method \"name\" : run a given test method (should be fully specified;");
|
||||
Console.WriteLine(" : i.e., 'MyNamespace.MyClass.MyTestMethod')");
|
||||
Console.WriteLine(" : if specified more than once, acts as an OR operation");
|
||||
Console.WriteLine(" -class \"name\" : run all methods in a given test class (should be fully");
|
||||
Console.WriteLine(" : specified; i.e., 'MyNamespace.MyClass')");
|
||||
Console.WriteLine(" : if specified more than once, acts as an OR operation");
|
||||
Console.WriteLine(" -namespace \"name\" : run all methods in a given namespace (i.e.,");
|
||||
Console.WriteLine(" : 'MyNamespace.MySubNamespace')");
|
||||
Console.WriteLine(" : if specified more than once, acts as an OR operation");
|
||||
Console.WriteLine();
|
||||
|
||||
var switchableReporters = reporters.Where(r => !string.IsNullOrWhiteSpace(r.RunnerSwitch)).ToList();
|
||||
if (switchableReporters.Count > 0)
|
||||
{
|
||||
Console.WriteLine("Reporters: (optional, choose only one)");
|
||||
|
||||
foreach (var reporter in switchableReporters.OrderBy(r => r.RunnerSwitch))
|
||||
Console.WriteLine(" -{0} : {1}", reporter.RunnerSwitch.ToLowerInvariant().PadRight(21), reporter.Description);
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
Console.WriteLine("Result formats: (optional, choose one or more)");
|
||||
|
||||
foreach (var transform in TransformFactory.AvailableTransforms)
|
||||
Console.WriteLine(" {0} : {1}",
|
||||
string.Format("-{0} <filename>", transform.CommandLine).PadRight(22).Substring(0, 22),
|
||||
transform.Description);
|
||||
}
|
||||
|
||||
int RunProject(XunitProject project,
|
||||
bool? parallelizeAssemblies,
|
||||
bool? parallelizeTestCollections,
|
||||
int? maxThreadCount,
|
||||
bool diagnosticMessages,
|
||||
bool noColor,
|
||||
bool designTime,
|
||||
bool list,
|
||||
IReadOnlyList<string> designTimeFullyQualifiedNames)
|
||||
{
|
||||
XElement assembliesElement = null;
|
||||
var xmlTransformers = TransformFactory.GetXmlTransformers(project);
|
||||
var needsXml = xmlTransformers.Count > 0;
|
||||
var consoleLock = new object();
|
||||
|
||||
if (!parallelizeAssemblies.HasValue)
|
||||
parallelizeAssemblies = project.All(assembly => assembly.Configuration.ParallelizeAssemblyOrDefault);
|
||||
|
||||
if (needsXml)
|
||||
assembliesElement = new XElement("assemblies");
|
||||
|
||||
var originalWorkingFolder = Directory.GetCurrentDirectory();
|
||||
|
||||
using (AssemblyHelper.SubscribeResolve())
|
||||
{
|
||||
var clockTime = Stopwatch.StartNew();
|
||||
|
||||
if (parallelizeAssemblies.GetValueOrDefault())
|
||||
{
|
||||
var tasks = project.Assemblies.Select(assembly => TaskRun(() => ExecuteAssembly(consoleLock, assembly, needsXml, parallelizeTestCollections, maxThreadCount, diagnosticMessages, noColor, project.Filters, designTime, list, designTimeFullyQualifiedNames)));
|
||||
var results = Task.WhenAll(tasks).GetAwaiter().GetResult();
|
||||
foreach (var assemblyElement in results.Where(result => result != null))
|
||||
assembliesElement.Add(assemblyElement);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var assembly in project.Assemblies)
|
||||
{
|
||||
var assemblyElement = ExecuteAssembly(consoleLock, assembly, needsXml, parallelizeTestCollections, maxThreadCount, diagnosticMessages, noColor, project.Filters, designTime, list, designTimeFullyQualifiedNames);
|
||||
if (assemblyElement != null)
|
||||
assembliesElement.Add(assemblyElement);
|
||||
}
|
||||
}
|
||||
|
||||
clockTime.Stop();
|
||||
|
||||
if (_completionMessages.Count > 0)
|
||||
_reporterMessageHandler.OnMessage(new TestExecutionSummary(clockTime.Elapsed, _completionMessages.OrderBy(kvp => kvp.Key).ToList()));
|
||||
}
|
||||
|
||||
Directory.SetCurrentDirectory(originalWorkingFolder);
|
||||
|
||||
foreach (var transformer in xmlTransformers)
|
||||
transformer(assembliesElement);
|
||||
|
||||
return _failed ? 1 : _completionMessages.Values.Sum(summary => summary.Failed);
|
||||
}
|
||||
|
||||
XElement ExecuteAssembly(object consoleLock,
|
||||
XunitProjectAssembly assembly,
|
||||
bool needsXml,
|
||||
bool? parallelizeTestCollections,
|
||||
int? maxThreadCount,
|
||||
bool diagnosticMessages,
|
||||
bool noColor,
|
||||
XunitFilters filters,
|
||||
bool designTime,
|
||||
bool listTestCases,
|
||||
IReadOnlyList<string> designTimeFullyQualifiedNames)
|
||||
{
|
||||
if (_cancel)
|
||||
return null;
|
||||
|
||||
var assemblyElement = needsXml ? new XElement("assembly") : null;
|
||||
|
||||
try
|
||||
{
|
||||
// Turn off pre-enumeration of theories when we're not running in Visual Studio
|
||||
if (!designTime)
|
||||
assembly.Configuration.PreEnumerateTheories = false;
|
||||
|
||||
if (diagnosticMessages)
|
||||
assembly.Configuration.DiagnosticMessages = true;
|
||||
|
||||
var discoveryOptions = TestFrameworkOptions.ForDiscovery(assembly.Configuration);
|
||||
var executionOptions = TestFrameworkOptions.ForExecution(assembly.Configuration);
|
||||
if (maxThreadCount.HasValue)
|
||||
executionOptions.SetMaxParallelThreads(maxThreadCount);
|
||||
if (parallelizeTestCollections.HasValue)
|
||||
executionOptions.SetDisableParallelization(!parallelizeTestCollections.GetValueOrDefault());
|
||||
|
||||
var assemblyDisplayName = Path.GetFileNameWithoutExtension(assembly.AssemblyFilename);
|
||||
var diagnosticMessageVisitor = new DiagnosticMessageVisitor(consoleLock, assemblyDisplayName, assembly.Configuration.DiagnosticMessagesOrDefault, noColor);
|
||||
|
||||
var sourceInformationProvider = GetSourceInformationProviderAdapater(assembly);
|
||||
|
||||
|
||||
using (var controller = new XunitFrontController(AppDomainSupport.Denied, assembly.AssemblyFilename, assembly.ConfigFilename, false, diagnosticMessageSink: diagnosticMessageVisitor, sourceInformationProvider: sourceInformationProvider))
|
||||
using (var discoveryVisitor = new TestDiscoveryVisitor())
|
||||
{
|
||||
var includeSourceInformation = designTime && listTestCases;
|
||||
|
||||
// Discover & filter the tests
|
||||
_reporterMessageHandler.OnMessage(new TestAssemblyDiscoveryStarting(assembly, false, false, discoveryOptions));
|
||||
|
||||
controller.Find(includeSourceInformation: includeSourceInformation, messageSink: discoveryVisitor, discoveryOptions: discoveryOptions);
|
||||
discoveryVisitor.Finished.WaitOne();
|
||||
|
||||
IDictionary<ITestCase, VsTestCase> vsTestCases = null;
|
||||
if (designTime)
|
||||
vsTestCases = DesignTimeTestConverter.Convert(discoveryVisitor.TestCases);
|
||||
|
||||
if (listTestCases)
|
||||
{
|
||||
lock (consoleLock)
|
||||
{
|
||||
if (designTime)
|
||||
{
|
||||
foreach (var testcase in vsTestCases.Values)
|
||||
{
|
||||
_testDiscoverySink?.SendTest(testcase);
|
||||
|
||||
Console.WriteLine(testcase.FullyQualifiedName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var testcase in discoveryVisitor.TestCases)
|
||||
Console.WriteLine(testcase.DisplayName);
|
||||
}
|
||||
}
|
||||
|
||||
return assemblyElement;
|
||||
}
|
||||
|
||||
IExecutionVisitor resultsVisitor;
|
||||
|
||||
if (designTime)
|
||||
{
|
||||
resultsVisitor = new DesignTimeExecutionVisitor(_testExecutionSink, vsTestCases, _reporterMessageHandler);
|
||||
}
|
||||
else
|
||||
resultsVisitor = new XmlAggregateVisitor(_reporterMessageHandler, _completionMessages, assemblyElement, () => _cancel);
|
||||
|
||||
IList<ITestCase> filteredTestCases;
|
||||
var testCasesDiscovered = discoveryVisitor.TestCases.Count;
|
||||
if (!designTime || designTimeFullyQualifiedNames.Count == 0)
|
||||
filteredTestCases = discoveryVisitor.TestCases.Where(filters.Filter).ToList();
|
||||
else
|
||||
filteredTestCases = vsTestCases.Where(t => designTimeFullyQualifiedNames.Contains(t.Value.FullyQualifiedName)).Select(t => t.Key).ToList();
|
||||
var testCasesToRun = filteredTestCases.Count;
|
||||
|
||||
_reporterMessageHandler.OnMessage(new TestAssemblyDiscoveryFinished(assembly, discoveryOptions, testCasesDiscovered, testCasesToRun));
|
||||
|
||||
if (filteredTestCases.Count == 0)
|
||||
_completionMessages.TryAdd(Path.GetFileName(assembly.AssemblyFilename), new ExecutionSummary());
|
||||
else
|
||||
{
|
||||
_reporterMessageHandler.OnMessage(new TestAssemblyExecutionStarting(assembly, executionOptions));
|
||||
|
||||
controller.RunTests(filteredTestCases, resultsVisitor, executionOptions);
|
||||
resultsVisitor.Finished.WaitOne();
|
||||
|
||||
_reporterMessageHandler.OnMessage(new TestAssemblyExecutionFinished(assembly, executionOptions, resultsVisitor.ExecutionSummary));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_failed = true;
|
||||
|
||||
var e = ex;
|
||||
while (e != null)
|
||||
{
|
||||
Console.WriteLine("{0}: {1}", e.GetType().FullName, e.Message);
|
||||
e = e.InnerException;
|
||||
}
|
||||
}
|
||||
|
||||
return assemblyElement;
|
||||
}
|
||||
|
||||
private static ISourceInformationProvider GetSourceInformationProviderAdapater(XunitProjectAssembly assembly)
|
||||
{
|
||||
var directoryPath = Path.GetDirectoryName(assembly.AssemblyFilename);
|
||||
var assemblyName = Path.GetFileNameWithoutExtension(assembly.AssemblyFilename);
|
||||
var pdbPath = Path.Combine(directoryPath, assemblyName + FileNameSuffixes.DotNet.ProgramDatabase);
|
||||
|
||||
return File.Exists(pdbPath)
|
||||
? new SourceInformationProviderAdapater(new SourceInformationProvider(pdbPath, null))
|
||||
: null;
|
||||
}
|
||||
|
||||
static Task<T> TaskRun<T>(Func<T> function)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<T>();
|
||||
|
||||
ThreadPool.QueueUserWorkItem(_ =>
|
||||
{
|
||||
try
|
||||
{
|
||||
tcs.SetResult(function());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
tcs.SetException(ex);
|
||||
}
|
||||
});
|
||||
|
||||
return tcs.Task;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
using System.Reflection;
|
||||
|
||||
[assembly : AssemblyTitle("xUnit.net Test Runner (DNX / DNX Core)")]
|
|
@ -0,0 +1,13 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyCompany("Outercurve Foundation")]
|
||||
[assembly: AssemblyProduct("xUnit.net Testing Framework")]
|
||||
[assembly: AssemblyCopyright("Copyright (C) Outercurve Foundation")]
|
||||
[assembly: AssemblyVersion("99.99.99.0")]
|
||||
|
||||
[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "Xunit.Sdk")]
|
||||
[assembly: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "xunit")]
|
||||
[assembly: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "extensions")]
|
||||
[assembly: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "utility")]
|
||||
[assembly: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "runner")]
|
|
@ -0,0 +1,11 @@
|
|||
using System.Threading;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Xunit
|
||||
{
|
||||
public interface IExecutionVisitor : IMessageSink
|
||||
{
|
||||
ExecutionSummary ExecutionSummary { get; }
|
||||
ManualResetEvent Finished { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Xunit.Runner.DotNet
|
||||
{
|
||||
/// <summary>
|
||||
/// Transforms stack frames and stack traces into compiler-like output
|
||||
/// so they can be double-clicked in Visual Studio.
|
||||
/// </summary>
|
||||
public static class StackFrameTransformer
|
||||
{
|
||||
static Regex _regex;
|
||||
|
||||
static StackFrameTransformer()
|
||||
{
|
||||
_regex = new Regex(@"^\s*at (?<method>.*) in (?<file>.*):(line )?(?<line>\d+)$");
|
||||
}
|
||||
|
||||
/// <summary/>
|
||||
public static string TransformFrame(string stackFrame, string defaultDirectory)
|
||||
{
|
||||
if (stackFrame == null)
|
||||
return null;
|
||||
|
||||
var match = _regex.Match(stackFrame);
|
||||
if (match == Match.Empty)
|
||||
return stackFrame;
|
||||
|
||||
var file = match.Groups["file"].Value;
|
||||
if (file.StartsWith(defaultDirectory, StringComparison.OrdinalIgnoreCase))
|
||||
file = file.Substring(defaultDirectory.Length);
|
||||
|
||||
return string.Format("{0}({1},0): at {2}",
|
||||
file,
|
||||
match.Groups["line"].Value,
|
||||
match.Groups["method"].Value);
|
||||
}
|
||||
|
||||
/// <summary/>
|
||||
public static string TransformStack(string stack, string defaultDirectory)
|
||||
{
|
||||
if (stack == null)
|
||||
return null;
|
||||
|
||||
List<string> results = new List<string>();
|
||||
|
||||
foreach (string frame in stack.Split(new[] { Environment.NewLine }, StringSplitOptions.None))
|
||||
results.Add(TransformFrame(frame, defaultDirectory));
|
||||
|
||||
return string.Join(Environment.NewLine, results.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Xunit.Runner.DotNet
|
||||
{
|
||||
public class Transform
|
||||
{
|
||||
public string CommandLine;
|
||||
public string Description;
|
||||
public Action<XElement, string> OutputHandler;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Xunit.Runner.DotNet
|
||||
{
|
||||
public class TransformFactory
|
||||
{
|
||||
static readonly TransformFactory Instance = new TransformFactory();
|
||||
|
||||
readonly Dictionary<string, Transform> _availableTransforms = new Dictionary<string, Transform>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
protected TransformFactory()
|
||||
{
|
||||
_availableTransforms.Add("xml", new Transform { CommandLine = "xml", Description = "output results to xUnit.net v2 style XML file", OutputHandler = Handler_DirectWrite });
|
||||
}
|
||||
|
||||
public static List<Transform> AvailableTransforms
|
||||
{
|
||||
get { return Instance._availableTransforms.Values.ToList(); }
|
||||
}
|
||||
|
||||
public static List<Action<XElement>> GetXmlTransformers(XunitProject project)
|
||||
{
|
||||
return project.Output.Select(output => new Action<XElement>(xml => Instance._availableTransforms[output.Key].OutputHandler(xml, output.Value))).ToList();
|
||||
}
|
||||
|
||||
static void Handler_DirectWrite(XElement xml, string outputFileName)
|
||||
{
|
||||
// Create the output parent directories if they don't exist.
|
||||
int lastSlashIdx = outputFileName.LastIndexOf('/');
|
||||
if (lastSlashIdx != -1)
|
||||
Directory.CreateDirectory(outputFileName.Substring(0, lastSlashIdx));
|
||||
|
||||
using (var stream = File.Open(outputFileName, FileMode.Create))
|
||||
xml.Save(stream);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Xml.Linq;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Xunit
|
||||
{
|
||||
public class XmlAggregateVisitor : XmlTestExecutionVisitor, IExecutionVisitor
|
||||
{
|
||||
readonly ConcurrentDictionary<string, ExecutionSummary> _completionMessages;
|
||||
readonly IMessageSink _innerMessageSink;
|
||||
|
||||
public XmlAggregateVisitor(IMessageSink innerMessageSink,
|
||||
ConcurrentDictionary<string, ExecutionSummary> completionMessages,
|
||||
XElement assemblyElement,
|
||||
Func<bool> cancelThunk)
|
||||
: base(assemblyElement, cancelThunk)
|
||||
{
|
||||
_innerMessageSink = innerMessageSink;
|
||||
_completionMessages = completionMessages;
|
||||
|
||||
ExecutionSummary = new ExecutionSummary();
|
||||
}
|
||||
|
||||
public ExecutionSummary ExecutionSummary { get; private set; }
|
||||
|
||||
protected override bool Visit(ITestAssemblyFinished assemblyFinished)
|
||||
{
|
||||
var result = base.Visit(assemblyFinished);
|
||||
|
||||
ExecutionSummary = new ExecutionSummary
|
||||
{
|
||||
Total = assemblyFinished.TestsRun,
|
||||
Failed = assemblyFinished.TestsFailed,
|
||||
Skipped = assemblyFinished.TestsSkipped,
|
||||
Time = assemblyFinished.ExecutionTime,
|
||||
Errors = Errors
|
||||
};
|
||||
|
||||
if (_completionMessages != null)
|
||||
_completionMessages.TryAdd(Path.GetFileNameWithoutExtension(assemblyFinished.TestAssembly.Assembly.AssemblyPath), ExecutionSummary);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override bool OnMessage(IMessageSinkMessage message)
|
||||
{
|
||||
var result = base.OnMessage(message);
|
||||
result = _innerMessageSink.OnMessage(message) || result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Xunit.Runner.DotNet
|
||||
{
|
||||
public class DiagnosticMessageVisitor : TestMessageVisitor
|
||||
{
|
||||
readonly string _assemblyDisplayName;
|
||||
readonly object _consoleLock;
|
||||
readonly bool _noColor;
|
||||
readonly bool _showDiagnostics;
|
||||
|
||||
public DiagnosticMessageVisitor(object consoleLock, string assemblyDisplayName, bool showDiagnostics, bool noColor)
|
||||
{
|
||||
_noColor = noColor;
|
||||
_consoleLock = consoleLock;
|
||||
_assemblyDisplayName = assemblyDisplayName;
|
||||
_showDiagnostics = showDiagnostics;
|
||||
}
|
||||
|
||||
protected override bool Visit(IDiagnosticMessage diagnosticMessage)
|
||||
{
|
||||
if (_showDiagnostics)
|
||||
lock (_consoleLock)
|
||||
{
|
||||
if (!_noColor)
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
|
||||
Console.WriteLine(" {0}: {1}", _assemblyDisplayName, diagnosticMessage.Message);
|
||||
|
||||
if (!_noColor)
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
}
|
||||
|
||||
return base.Visit(diagnosticMessage);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>002d321e-170e-4e55-bdd1-77c6353a6eb5</ProjectGuid>
|
||||
<RootNamespace>Xunit.Runner.Dnx</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"authors": [ "James Newkirk", "Brad Wilson" ],
|
||||
"title": "xUnit.net [Runner: dotnet]",
|
||||
"description": "Console and Visual Studio runner for xUnit.net.\r\n\r\nSupported platforms:\r\n- dotnet 5.4+",
|
||||
"name": "dotnet-test-xunit",
|
||||
"projectUrl": "https://github.com/xunit/dnx.xunit",
|
||||
"iconUrl": "https://raw.githubusercontent.com/xunit/media/master/logo-512-transparent.png",
|
||||
"licenseUrl": "https://raw.githubusercontent.com/xunit/xunit/master/license.txt",
|
||||
"requireLicenseAcceptance": false,
|
||||
"developmentDependency": true,
|
||||
"version": "99.99.99-dev",
|
||||
"compilationOptions": {
|
||||
"warningsAsErrors": true,
|
||||
"emitEntryPoint": true
|
||||
},
|
||||
"frameworks": {
|
||||
"dnxcore50": {
|
||||
"dependencies": {
|
||||
"System.Linq.Expressions": "4.0.11-rc2-*",
|
||||
"System.Security.Cryptography.Algorithms": "4.0.0-beta-*",
|
||||
"System.Threading.ThreadPool": "4.0.10-beta-*",
|
||||
"System.Xml.XDocument": "4.0.11-beta-*"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Runtime": "1.0.1-beta-*",
|
||||
"Microsoft.Extensions.Testing.Abstractions": "1.0.0-*",
|
||||
"Microsoft.DotNet.ProjectModel": "1.0.0-*",
|
||||
"Microsoft.DotNet.ProjectModel.Loader": "1.0.0-*",
|
||||
"Microsoft.DotNet.Cli.Utils": "1.0.0-*",
|
||||
"Microsoft.Extensions.CommandLineUtils.Sources": "1.0.0-*",
|
||||
"NuGet.Packaging.Core": "3.3.0-rtm-*",
|
||||
"xunit.runner.reporters": "2.1.0-rc1-*"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/xunit/dnx.xunit"
|
||||
},
|
||||
"packInclude": {
|
||||
"lib/dnxcore50/": [ "bin/Debug/dnxcore50/dotnet-test-xunit.deps", "bin/Debug/dnxcore50/dotnet-test-xunit.exe" ]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,716 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using Xunit.Runner.DotNet;
|
||||
|
||||
public class CommandLineTests
|
||||
{
|
||||
public class UnknownSwitch
|
||||
{
|
||||
[Fact]
|
||||
public static void UnknownSwitchThrows()
|
||||
{
|
||||
var exception = Record.Exception(() => TestableCommandLine.Parse(new[] { "assemblyName.dll", "-unknown" }));
|
||||
|
||||
Assert.IsType<ArgumentException>(exception);
|
||||
Assert.Equal("unknown option: -unknown", exception.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public class Filename
|
||||
{
|
||||
[Fact]
|
||||
public static void MissingAssemblyFileNameThrows()
|
||||
{
|
||||
var exception = Record.Exception(() => TestableCommandLine.Parse());
|
||||
|
||||
Assert.IsType<ArgumentException>(exception);
|
||||
Assert.Equal("must specify at least one assembly", exception.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void ConfigFileDoesNotExist_Throws()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "badConfig.json" };
|
||||
|
||||
var exception = Record.Exception(() => TestableCommandLine.Parse(arguments));
|
||||
|
||||
Assert.IsType<ArgumentException>(exception);
|
||||
Assert.Equal("config file not found: badConfig.json", exception.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public class DiagnosticsOption
|
||||
{
|
||||
[Fact]
|
||||
public static void DiagnosticsNotSetDebugIsFalse()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.False(commandLine.DiagnosticMessages);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void DiagnosticsSetDebugIsTrue()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-diagnostics" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.True(commandLine.DiagnosticMessages);
|
||||
}
|
||||
}
|
||||
|
||||
public class DebugOption
|
||||
{
|
||||
[Fact]
|
||||
public static void DebugNotSetDebugIsFalse()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.False(commandLine.Debug);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void DebugSetDebugIsTrue()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-debug" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.True(commandLine.Debug);
|
||||
}
|
||||
}
|
||||
|
||||
public class MaxThreadsOption
|
||||
{
|
||||
[Fact]
|
||||
public static void DefaultValueIsNull()
|
||||
{
|
||||
var commandLine = TestableCommandLine.Parse("assemblyName.dll");
|
||||
|
||||
Assert.Null(commandLine.MaxParallelThreads);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void MissingValue()
|
||||
{
|
||||
var ex = Assert.Throws<ArgumentException>(() => TestableCommandLine.Parse("assemblyName.dll", "-maxthreads"));
|
||||
|
||||
Assert.Equal("missing argument for -maxthreads", ex.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("0")]
|
||||
[InlineData("abc")]
|
||||
public static void InvalidValues(string value)
|
||||
{
|
||||
var ex = Assert.Throws<ArgumentException>(() => TestableCommandLine.Parse("assemblyName.dll", "-maxthreads", value));
|
||||
|
||||
Assert.Equal("incorrect argument value for -maxthreads (must be 'default', 'unlimited', or a positive number)", ex.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("default", 0)]
|
||||
[InlineData("unlimited", -1)]
|
||||
[InlineData("16", 16)]
|
||||
public static void ValidValues(string value, int expected)
|
||||
{
|
||||
var commandLine = TestableCommandLine.Parse("assemblyName.dll", "-maxthreads", value);
|
||||
|
||||
Assert.Equal(expected, commandLine.MaxParallelThreads);
|
||||
}
|
||||
}
|
||||
|
||||
public class NoLogoOption
|
||||
{
|
||||
[Fact]
|
||||
public static void NoLogoNotSetNoLogoIsFalse()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.False(commandLine.NoLogo);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void NoLogoSetNoLogoIsTrue()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-nologo" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.True(commandLine.NoLogo);
|
||||
}
|
||||
}
|
||||
|
||||
public class WaitOption
|
||||
{
|
||||
[Fact]
|
||||
public static void WaitOptionNotPassedWaitFalse()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.False(commandLine.Wait);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void WaitOptionWaitIsTrue()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-wait" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.True(commandLine.Wait);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void WaitOptionIgnoreCaseWaitIsTrue()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-wAiT" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.True(commandLine.Wait);
|
||||
}
|
||||
}
|
||||
|
||||
public class TraitArgument
|
||||
{
|
||||
[Fact]
|
||||
public static void TraitArgumentNotPassed()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.Equal(0, commandLine.Project.Filters.IncludedTraits.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void SingleValidTraitArgument()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-trait", "foo=bar" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.Equal(1, commandLine.Project.Filters.IncludedTraits.Count);
|
||||
Assert.Equal(1, commandLine.Project.Filters.IncludedTraits["foo"].Count());
|
||||
Assert.Contains("bar", commandLine.Project.Filters.IncludedTraits["foo"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void MultipleValidTraitArguments_SameName()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-trait", "foo=bar", "-trait", "foo=baz" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.Equal(1, commandLine.Project.Filters.IncludedTraits.Count);
|
||||
Assert.Equal(2, commandLine.Project.Filters.IncludedTraits["foo"].Count());
|
||||
Assert.Contains("bar", commandLine.Project.Filters.IncludedTraits["foo"]);
|
||||
Assert.Contains("baz", commandLine.Project.Filters.IncludedTraits["foo"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void MultipleValidTraitArguments_DifferentName()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-trait", "foo=bar", "-trait", "baz=biff" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.Equal(2, commandLine.Project.Filters.IncludedTraits.Count);
|
||||
Assert.Equal(1, commandLine.Project.Filters.IncludedTraits["foo"].Count());
|
||||
Assert.Contains("bar", commandLine.Project.Filters.IncludedTraits["foo"]);
|
||||
Assert.Equal(1, commandLine.Project.Filters.IncludedTraits["baz"].Count());
|
||||
Assert.Contains("biff", commandLine.Project.Filters.IncludedTraits["baz"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void MissingOptionValue()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-trait" };
|
||||
|
||||
var ex = Record.Exception(() => TestableCommandLine.Parse(arguments));
|
||||
|
||||
Assert.IsType<ArgumentException>(ex);
|
||||
Assert.Equal("missing argument for -trait", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void OptionValueMissingEquals()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-trait", "foobar" };
|
||||
|
||||
var ex = Record.Exception(() => TestableCommandLine.Parse(arguments));
|
||||
|
||||
Assert.IsType<ArgumentException>(ex);
|
||||
Assert.Equal("incorrect argument format for -trait (should be \"name=value\")", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void OptionValueMissingName()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-trait", "=bar" };
|
||||
|
||||
var ex = Record.Exception(() => TestableCommandLine.Parse(arguments));
|
||||
|
||||
Assert.IsType<ArgumentException>(ex);
|
||||
Assert.Equal("incorrect argument format for -trait (should be \"name=value\")", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void OptionNameMissingValue()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-trait", "foo=" };
|
||||
|
||||
var ex = Record.Exception(() => TestableCommandLine.Parse(arguments));
|
||||
|
||||
Assert.IsType<ArgumentException>(ex);
|
||||
Assert.Equal("incorrect argument format for -trait (should be \"name=value\")", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void TooManyEqualsSigns()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-trait", "foo=bar=baz" };
|
||||
|
||||
var ex = Record.Exception(() => TestableCommandLine.Parse(arguments));
|
||||
|
||||
Assert.IsType<ArgumentException>(ex);
|
||||
Assert.Equal("incorrect argument format for -trait (should be \"name=value\")", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public class MinusTraitArgument
|
||||
{
|
||||
[Fact]
|
||||
public static void TraitArgumentNotPassed()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.Equal(0, commandLine.Project.Filters.ExcludedTraits.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void SingleValidTraitArgument()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-notrait", "foo=bar" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.Equal(1, commandLine.Project.Filters.ExcludedTraits.Count);
|
||||
Assert.Equal(1, commandLine.Project.Filters.ExcludedTraits["foo"].Count());
|
||||
Assert.Contains("bar", commandLine.Project.Filters.ExcludedTraits["foo"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void MultipleValidTraitArguments_SameName()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-notrait", "foo=bar", "-notrait", "foo=baz" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.Equal(1, commandLine.Project.Filters.ExcludedTraits.Count);
|
||||
Assert.Equal(2, commandLine.Project.Filters.ExcludedTraits["foo"].Count());
|
||||
Assert.Contains("bar", commandLine.Project.Filters.ExcludedTraits["foo"]);
|
||||
Assert.Contains("baz", commandLine.Project.Filters.ExcludedTraits["foo"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void MultipleValidTraitArguments_DifferentName()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-notrait", "foo=bar", "-notrait", "baz=biff" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.Equal(2, commandLine.Project.Filters.ExcludedTraits.Count);
|
||||
Assert.Equal(1, commandLine.Project.Filters.ExcludedTraits["foo"].Count());
|
||||
Assert.Contains("bar", commandLine.Project.Filters.ExcludedTraits["foo"]);
|
||||
Assert.Equal(1, commandLine.Project.Filters.ExcludedTraits["baz"].Count());
|
||||
Assert.Contains("biff", commandLine.Project.Filters.ExcludedTraits["baz"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void MissingOptionValue()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-notrait" };
|
||||
|
||||
var ex = Record.Exception(() => TestableCommandLine.Parse(arguments));
|
||||
|
||||
Assert.IsType<ArgumentException>(ex);
|
||||
Assert.Equal("missing argument for -notrait", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void OptionValueMissingEquals()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-notrait", "foobar" };
|
||||
|
||||
var ex = Record.Exception(() => TestableCommandLine.Parse(arguments));
|
||||
|
||||
Assert.IsType<ArgumentException>(ex);
|
||||
Assert.Equal("incorrect argument format for -notrait (should be \"name=value\")", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void OptionValueMissingName()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-notrait", "=bar" };
|
||||
|
||||
var ex = Record.Exception(() => TestableCommandLine.Parse(arguments));
|
||||
|
||||
Assert.IsType<ArgumentException>(ex);
|
||||
Assert.Equal("incorrect argument format for -notrait (should be \"name=value\")", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void OptionNameMissingValue()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-notrait", "foo=" };
|
||||
|
||||
var ex = Record.Exception(() => TestableCommandLine.Parse(arguments));
|
||||
|
||||
Assert.IsType<ArgumentException>(ex);
|
||||
Assert.Equal("incorrect argument format for -notrait (should be \"name=value\")", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void TooManyEqualsSigns()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-notrait", "foo=bar=baz" };
|
||||
|
||||
var ex = Record.Exception(() => TestableCommandLine.Parse(arguments));
|
||||
|
||||
Assert.IsType<ArgumentException>(ex);
|
||||
Assert.Equal("incorrect argument format for -notrait (should be \"name=value\")", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public class MethodArgument
|
||||
{
|
||||
[Fact]
|
||||
public static void MethodArgumentNotPassed()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.Equal(0, commandLine.Project.Filters.IncludedMethods.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void SingleValidMethodArgument()
|
||||
{
|
||||
const string name = "Namespace.Class.Method1";
|
||||
|
||||
var arguments = new[] { "assemblyName.dll", "-method", name };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.Equal(1, commandLine.Project.Filters.IncludedMethods.Count);
|
||||
Assert.True(commandLine.Project.Filters.IncludedMethods.Contains(name));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void MultipleValidMethodArguments()
|
||||
{
|
||||
const string name1 = "Namespace.Class.Method1";
|
||||
const string name2 = "Namespace.Class.Method2";
|
||||
|
||||
var arguments = new[] { "assemblyName.dll", "-method", name1, "-method", name2 };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.Equal(2, commandLine.Project.Filters.IncludedMethods.Count);
|
||||
Assert.True(commandLine.Project.Filters.IncludedMethods.Contains(name1));
|
||||
Assert.True(commandLine.Project.Filters.IncludedMethods.Contains(name2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void MissingOptionValue()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-method" };
|
||||
|
||||
var ex = Record.Exception(() => TestableCommandLine.Parse(arguments));
|
||||
|
||||
Assert.IsType<ArgumentException>(ex);
|
||||
Assert.Equal("missing argument for -method", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public class ClassArgument
|
||||
{
|
||||
[Fact]
|
||||
public static void ClassArgumentNotPassed()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.Equal(0, commandLine.Project.Filters.IncludedMethods.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void SingleValidClassArgument()
|
||||
{
|
||||
const string name = "Namespace.Class";
|
||||
|
||||
var arguments = new[] { "assemblyName.dll", "-class", name };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.Equal(1, commandLine.Project.Filters.IncludedClasses.Count);
|
||||
Assert.True(commandLine.Project.Filters.IncludedClasses.Contains(name));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void MultipleValidClassArguments()
|
||||
{
|
||||
const string name1 = "Namespace.Class1";
|
||||
const string name2 = "Namespace.Class2";
|
||||
|
||||
var arguments = new[] { "assemblyName.dll", "-class", name1, "-class", name2 };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.Equal(2, commandLine.Project.Filters.IncludedClasses.Count);
|
||||
Assert.True(commandLine.Project.Filters.IncludedClasses.Contains(name1));
|
||||
Assert.True(commandLine.Project.Filters.IncludedClasses.Contains(name2));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void MissingOptionValue()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-class" };
|
||||
|
||||
var ex = Record.Exception(() => TestableCommandLine.Parse(arguments));
|
||||
|
||||
Assert.IsType<ArgumentException>(ex);
|
||||
Assert.Equal("missing argument for -class", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public class ParallelizationOptions
|
||||
{
|
||||
[Fact]
|
||||
public static void ParallelizationOptionsAreNullByDefault()
|
||||
{
|
||||
var project = TestableCommandLine.Parse("assemblyName.dll");
|
||||
|
||||
Assert.Null(project.ParallelizeAssemblies);
|
||||
Assert.Null(project.ParallelizeTestCollections);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void FailsWithoutOptionOrWithIncorrectOptions()
|
||||
{
|
||||
var aex1 = Assert.Throws<ArgumentException>(() => TestableCommandLine.Parse("assemblyName.dll", "-parallel"));
|
||||
Assert.Equal("missing argument for -parallel", aex1.Message);
|
||||
|
||||
var aex2 = Assert.Throws<ArgumentException>(() => TestableCommandLine.Parse("assemblyName.dll", "-parallel", "nonsense"));
|
||||
Assert.Equal("incorrect argument value for -parallel", aex2.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("None", false, false)]
|
||||
[InlineData("Assemblies", true, false)]
|
||||
[InlineData("Collections", false, true)]
|
||||
[InlineData("All", true, true)]
|
||||
public static void ParallelCanBeTurnedOn(string parallelOption, bool expectedAssemblyParallelization, bool expectedCollectionsParallelization)
|
||||
{
|
||||
|
||||
var project = TestableCommandLine.Parse("assemblyName.dll", "-parallel", parallelOption);
|
||||
|
||||
Assert.Equal(expectedAssemblyParallelization, project.ParallelizeAssemblies);
|
||||
Assert.Equal(expectedCollectionsParallelization, project.ParallelizeTestCollections);
|
||||
}
|
||||
}
|
||||
|
||||
public class Reporters
|
||||
{
|
||||
[Fact]
|
||||
public void NoReporters_UsesDefaultReporter()
|
||||
{
|
||||
var commandLine = TestableCommandLine.Parse("assemblyName.dll");
|
||||
|
||||
Assert.IsType<DefaultRunnerReporter>(commandLine.Reporter);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NoExplicitReporter_NoEnvironmentallyEnabledReporters_UsesDefaultReporter()
|
||||
{
|
||||
var implicitReporter = new MockRunnerReporter(isEnvironmentallyEnabled: false);
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(new[] { implicitReporter }, "assemblyName.dll");
|
||||
|
||||
Assert.IsType<DefaultRunnerReporter>(commandLine.Reporter);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExplicitReporter_NoEnvironmentalOverride_UsesExplicitReporter()
|
||||
{
|
||||
var explicitReporter = new MockRunnerReporter("switch");
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(new[] { explicitReporter }, "assemblyName.dll", "-switch");
|
||||
|
||||
Assert.Same(explicitReporter, commandLine.Reporter);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExplicitReporter_WithEnvironmentalOverride_UsesEnvironmentalOverride()
|
||||
{
|
||||
var explicitReporter = new MockRunnerReporter("switch");
|
||||
var implicitReporter = new MockRunnerReporter(isEnvironmentallyEnabled: true);
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(new[] { explicitReporter, implicitReporter }, "assemblyName.dll", "-switch");
|
||||
|
||||
Assert.Same(implicitReporter, commandLine.Reporter);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NoExplicitReporter_SelectsFirstEnvironmentallyEnabledReporter()
|
||||
{
|
||||
var explicitReporter = new MockRunnerReporter("switch");
|
||||
var implicitReporter1 = new MockRunnerReporter(isEnvironmentallyEnabled: true);
|
||||
var implicitReporter2 = new MockRunnerReporter(isEnvironmentallyEnabled: true);
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(new[] { explicitReporter, implicitReporter1, implicitReporter2 }, "assemblyName.dll");
|
||||
|
||||
Assert.Same(implicitReporter1, commandLine.Reporter);
|
||||
}
|
||||
}
|
||||
|
||||
public class Transform
|
||||
{
|
||||
[Fact]
|
||||
public static void OutputMissingFilename()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-xml" };
|
||||
|
||||
var ex = Record.Exception(() => TestableCommandLine.Parse(arguments));
|
||||
|
||||
Assert.IsType<ArgumentException>(ex);
|
||||
Assert.Equal("missing filename for -xml", ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void Output()
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", "-xml", "foo.xml" };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
var output = Assert.Single(commandLine.Project.Output);
|
||||
Assert.Equal("xml", output.Key);
|
||||
Assert.Equal("foo.xml", output.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public class DesignTimeSwitch
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("-designtime")]
|
||||
[InlineData("--designtime")]
|
||||
public static void DesignTime(string arg)
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", arg };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.True(commandLine.DesignTime);
|
||||
}
|
||||
}
|
||||
|
||||
public class ListSwitch
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("-list")]
|
||||
[InlineData("--list")]
|
||||
public static void List(string arg)
|
||||
{
|
||||
var arguments = new[] { "assemblyName.dll", arg };
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.True(commandLine.List);
|
||||
}
|
||||
}
|
||||
|
||||
public class TestArgument
|
||||
{
|
||||
[Fact]
|
||||
public static void TestUniqueNames()
|
||||
{
|
||||
var arguments = new[]
|
||||
{
|
||||
"assemblyName.dll",
|
||||
"-test",
|
||||
"foo",
|
||||
"--test",
|
||||
"bar",
|
||||
"--test",
|
||||
"baz",
|
||||
};
|
||||
|
||||
var commandLine = TestableCommandLine.Parse(arguments);
|
||||
|
||||
Assert.Equal(3, commandLine.DesignTimeTestUniqueNames.Count);
|
||||
Assert.Contains("foo", commandLine.DesignTimeTestUniqueNames);
|
||||
Assert.Contains("bar", commandLine.DesignTimeTestUniqueNames);
|
||||
Assert.Contains("baz", commandLine.DesignTimeTestUniqueNames);
|
||||
}
|
||||
}
|
||||
|
||||
class MockRunnerReporter : IRunnerReporter
|
||||
{
|
||||
// Need this here so the runner doesn't complain that this isn't a legal runner reporter. :-p
|
||||
public MockRunnerReporter() { }
|
||||
|
||||
public MockRunnerReporter(string runnerSwitch = null, bool isEnvironmentallyEnabled = false)
|
||||
{
|
||||
RunnerSwitch = runnerSwitch;
|
||||
IsEnvironmentallyEnabled = isEnvironmentallyEnabled;
|
||||
}
|
||||
|
||||
public string Description { get { return "The description"; } }
|
||||
|
||||
public bool IsEnvironmentallyEnabled { get; private set; }
|
||||
|
||||
public string RunnerSwitch { get; private set; }
|
||||
|
||||
public IMessageSink CreateMessageHandler(IRunnerLogger logger)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
class TestableCommandLine : CommandLine
|
||||
{
|
||||
private TestableCommandLine(IReadOnlyList<IRunnerReporter> reporters, params string[] arguments)
|
||||
: base(reporters, arguments, filename => filename != "badConfig.json")
|
||||
{
|
||||
}
|
||||
|
||||
public static TestableCommandLine Parse(params string[] arguments)
|
||||
{
|
||||
return new TestableCommandLine(new IRunnerReporter[0], arguments);
|
||||
}
|
||||
|
||||
public new static TestableCommandLine Parse(IReadOnlyList<IRunnerReporter> reporters, params string[] arguments)
|
||||
{
|
||||
return new TestableCommandLine(reporters, arguments);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"frameworks": {
|
||||
"dnxcore50": { }
|
||||
},
|
||||
"testRunner":"xunit",
|
||||
"dependencies": {
|
||||
"xunit": "2.1.0",
|
||||
"dotnet-test-xunit": "99.99.99-dev"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>838070ab-04f2-4a37-9c86-91669e633f70</ProjectGuid>
|
||||
<RootNamespace>Xunit.Runner.Dnx</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"diagnosticMessages": true
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,24 @@
|
|||
$toolsPath = split-path $MyInvocation.MyCommand.Definition
|
||||
$dnvm = join-path $toolsPath "dnvm.ps1"
|
||||
$solutionPath = [System.IO.Path]::GetFullPath($(join-path $toolsPath ".."))
|
||||
$globalJson = join-path $solutionPath "global.json"
|
||||
$dnxVersion = (ConvertFrom-JSON ([System.IO.File]::ReadAllText($globalJson))).sdk.version
|
||||
|
||||
& $dnvm install $dnxVersion -runtime CoreCLR -arch x86 -u
|
||||
& $dnvm install $dnxVersion -runtime CLR -arch x86 -u
|
||||
& $dnvm install $dnxVersion -runtime CoreCLR -arch x64 -u
|
||||
& $dnvm install $dnxVersion -runtime CLR -arch x64 -u
|
||||
|
||||
& $dnvm use $dnxVersion -runtime CLR -arch x86
|
||||
|
||||
# Update build number during CI
|
||||
if ($env:BuildSemanticVersion -ne $null) {
|
||||
$projectJson = join-path $solutionPath "src\xunit.runner.dnx\project.json"
|
||||
$content = get-content $projectJson
|
||||
$content = $content.Replace("99.99.99-dev", $env:BuildSemanticVersion)
|
||||
set-content $projectJson $content -encoding UTF8
|
||||
}
|
||||
|
||||
# Restore packages and build
|
||||
& dnu restore $solutionPath
|
||||
& dnu pack $(join-path $solutionPath "src\xunit.runner.dnx") --configuration Release
|
|
@ -0,0 +1,21 @@
|
|||
$toolsPath = split-path $MyInvocation.MyCommand.Definition
|
||||
$dnvm = join-path $toolsPath "dnvm.ps1"
|
||||
$solutionPath = [System.IO.Path]::GetFullPath($(join-path $toolsPath ".."))
|
||||
$globalJson = join-path $solutionPath "global.json"
|
||||
$dnxVersion = (ConvertFrom-JSON ([System.IO.File]::ReadAllText($globalJson))).sdk.version
|
||||
|
||||
& $dnvm use $dnxVersion -runtime CLR -arch x86
|
||||
& dnx -p $(join-path $solutionPath "test\test.xunit.runner.dnx") test
|
||||
if ($LastExitCode -ne 0) { exit 1 }
|
||||
|
||||
& $dnvm use $dnxVersion -runtime CoreCLR -arch x86
|
||||
& dnx -p $(join-path $solutionPath "test\test.xunit.runner.dnx") test
|
||||
if ($LastExitCode -ne 0) { exit 1 }
|
||||
|
||||
& $dnvm use $dnxVersion -runtime CLR -arch x64
|
||||
& dnx -p $(join-path $solutionPath "test\test.xunit.runner.dnx") test
|
||||
if ($LastExitCode -ne 0) { exit 1 }
|
||||
|
||||
& $dnvm use $dnxVersion -runtime CoreCLR -arch x64
|
||||
& dnx -p $(join-path $solutionPath "test\test.xunit.runner.dnx") test
|
||||
if ($LastExitCode -ne 0) { exit 1 }
|
|
@ -0,0 +1,55 @@
|
|||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
|
||||
<PropertyGroup>
|
||||
<SolutionDir>$(MSBuildProjectDirectory)\..\</SolutionDir>
|
||||
<NuGetExePath Condition="'$(NuGetExePath)' == ''">$(SolutionDir).nuget\nuget.exe</NuGetExePath>
|
||||
<MyGetUrl Condition="'$(MyGetUrl)' == ''">https://www.myget.org/F/xunit/api/v2/package</MyGetUrl>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<NupkgFiles Include="$(SolutionDir)src\xunit.runner.dnx\bin\Release\*.nupkg" Exclude="$(SolutionDir)src\xunit.runner.dnx\bin\Release\*.symbols*.nupkg" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PushMyGet" DependsOnTargets="_DownloadNuGet" Condition="'$(ForcePushMyGet)' == 'true' Or '$(GitBranch)' == 'master' Or '$(GitBranch)' == 'refs/heads/master'">
|
||||
<Exec Command='"$(NuGetExePath)" push %(NupkgFiles.Identity) -NonInteractive -Source $(MyGetUrl)' />
|
||||
</Target>
|
||||
|
||||
<Target Name="PushNuGet" DependsOnTargets="_DownloadNuGet">
|
||||
<Exec Command='"$(NuGetExePath)" push %(NupkgFiles.Identity) -NonInteractive' />
|
||||
</Target>
|
||||
|
||||
<Target Name="_DownloadNuGet">
|
||||
<MakeDir Directories="$(SolutionDir)\.nuget" />
|
||||
<DownloadNuGet OutputFilename="$(NuGetExePath)" Condition="!Exists('$(NuGetExePath)')" />
|
||||
</Target>
|
||||
|
||||
<UsingTask TaskName="DownloadNuGet" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
|
||||
<ParameterGroup>
|
||||
<OutputFilename ParameterType="System.String" Required="true" />
|
||||
</ParameterGroup>
|
||||
<Task>
|
||||
<Reference Include="System.Core" />
|
||||
<Using Namespace="System" />
|
||||
<Using Namespace="System.IO" />
|
||||
<Using Namespace="System.Net" />
|
||||
<Using Namespace="Microsoft.Build.Framework" />
|
||||
<Using Namespace="Microsoft.Build.Utilities" />
|
||||
<Code Type="Fragment" Language="cs">
|
||||
<![CDATA[
|
||||
try {
|
||||
OutputFilename = Path.GetFullPath(OutputFilename);
|
||||
|
||||
Log.LogMessage("Downloading latest version of NuGet.exe...");
|
||||
WebClient webClient = new WebClient();
|
||||
webClient.DownloadFile("https://www.nuget.org/nuget.exe", OutputFilename);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.LogErrorFromException(ex);
|
||||
return false;
|
||||
}
|
||||
]]>
|
||||
</Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
</Project>
|
Загрузка…
Ссылка в новой задаче