Initial commit of dotnet-test-xunit prototype

This commit is contained in:
piotrp 2015-12-09 17:48:40 -08:00
Родитель a883041d40
Коммит 379195a82a
40 изменённых файлов: 5925 добавлений и 0 удалений

12
CONTRIBUTING.md Normal file
Просмотреть файл

@ -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?

13
NuGet.Config Normal file
Просмотреть файл

@ -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>

36
README.md Normal file
Просмотреть файл

@ -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).

40
build.ps1 Normal file
Просмотреть файл

@ -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

60
build.sh Normal file
Просмотреть файл

@ -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

90
dnx.xunit.proj Normal file
Просмотреть файл

@ -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="&quot;$(NuGetExePath)&quot; install xunit.buildtasks -Source http://www.myget.org/F/b4ff5f68eccf4f6bbfed74f055f88d8f/ -SolutionDir &quot;$(SolutionDir)&quot; -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>

41
dnx.xunit.sln Normal file
Просмотреть файл

@ -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

Двоичные данные
dnx.xunit.v2.ncrunchsolution Normal file

Двоичный файл не отображается.

4
global.json Normal file
Просмотреть файл

@ -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
}

1911
tools/dnvm.ps1 Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

1054
tools/dnvm.sh Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

24
tools/dnx-build.ps1 Normal file
Просмотреть файл

@ -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

21
tools/dnx-tests.ps1 Normal file
Просмотреть файл

@ -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 }

55
tools/packages.proj Normal file
Просмотреть файл

@ -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>