updated to use AssemblyRunner from xunit.v3.runner.utility

This commit is contained in:
Matteo Cominetti
2020-06-27 15:45:54 +01:00
parent e9bf973bba
commit 70620b8e7d
60 changed files with 2346 additions and 3216 deletions
+2 -2
View File
@@ -21,8 +21,8 @@ namespace SampleTestAssembly
//[Trait("TraitName1", "TraitValue2")]
public void Fail()
{
Thread.Sleep(TimeSpan.FromSeconds(1));
Assert.True(false);
Thread.Sleep(TimeSpan.FromSeconds(2));
Assert.True(true);
}
[Fact(Skip = "Testing")]
+19 -11
View File
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\xunit.core.2.4.1\build\xunit.core.props" Condition="Exists('..\packages\xunit.core.2.4.1\build\xunit.core.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -41,20 +42,16 @@
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll</HintPath>
<Private>True</Private>
<HintPath>..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll</HintPath>
</Reference>
<Reference Include="xunit.assert, Version=2.1.0.3179, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll</HintPath>
<Private>True</Private>
<Reference Include="xunit.assert, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\packages\xunit.assert.2.4.1\lib\netstandard1.1\xunit.assert.dll</HintPath>
</Reference>
<Reference Include="xunit.core, Version=2.1.0.3179, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll</HintPath>
<Private>True</Private>
<Reference Include="xunit.core, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\packages\xunit.extensibility.core.2.4.1\lib\net452\xunit.core.dll</HintPath>
</Reference>
<Reference Include="xunit.execution.desktop, Version=2.1.0.3179, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll</HintPath>
<Private>True</Private>
<Reference Include="xunit.execution.desktop, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\packages\xunit.extensibility.execution.2.4.1\lib\net452\xunit.execution.desktop.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
@@ -64,7 +61,18 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Analyzer Include="..\packages\xunit.analyzers.0.10.0\analyzers\dotnet\cs\xunit.analyzers.dll" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\xunit.core.2.4.1\build\xunit.core.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.4.1\build\xunit.core.props'))" />
<Error Condition="!Exists('..\packages\xunit.core.2.4.1\build\xunit.core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.4.1\build\xunit.core.targets'))" />
</Target>
<Import Project="..\packages\xunit.core.2.4.1\build\xunit.core.targets" Condition="Exists('..\packages\xunit.core.2.4.1\build\xunit.core.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
+7 -6
View File
@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="xunit" version="2.1.0" targetFramework="net452" />
<package id="xunit.abstractions" version="2.0.0" targetFramework="net452" />
<package id="xunit.assert" version="2.1.0" targetFramework="net452" />
<package id="xunit.core" version="2.1.0" targetFramework="net452" />
<package id="xunit.extensibility.core" version="2.1.0" targetFramework="net452" />
<package id="xunit.extensibility.execution" version="2.1.0" targetFramework="net452" />
<package id="xunit" version="2.4.1" targetFramework="net452" />
<package id="xunit.abstractions" version="2.0.3" targetFramework="net452" />
<package id="xunit.analyzers" version="0.10.0" targetFramework="net452" />
<package id="xunit.assert" version="2.4.1" targetFramework="net452" />
<package id="xunit.core" version="2.4.1" targetFramework="net452" />
<package id="xunit.extensibility.core" version="2.4.1" targetFramework="net452" />
<package id="xunit.extensibility.execution" version="2.4.1" targetFramework="net452" />
</packages>
-13
View File
@@ -1,13 +0,0 @@
Steps to make a new release
===========================
1. Make sure no one else is planning on doing anything that would trigger a build
2. Check the "next build number" on [AppVeyor](https://ci.appveyor.com/project/Pilchie/xunit-runner-wpf/settings)
3. Click on [releases](https://github.com/Pilchie/xunit.runner.wpf/releases) -> `Draft a new release`
4. Set the version to `v1.0.nextbuildnumber` from 2
5. Set the title to `v1.0.nextbuildnumber - Some reason for the release to exist`
6. Click `Publish`
7. This will create the release, and start a new build on AppVeyor
8. Download the .nupkg from the AppVeyor artifacts page for that new build - (e.g. https://ci.appveyor.com/project/Pilchie/xunit-runner-wpf/build/1.0.15/artifacts)
9. Go back to the release you created in 6, and add the nupkg, and write a changelog
10. Tell [@Pilchie](https://github.com/Pilchie) to upload the nupkg to NuGet.org
Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

-86
View File
@@ -1,86 +0,0 @@
using System;
using System.IO;
namespace Xunit.Runner.Data
{
public sealed class ClientReader : IDisposable
{
private readonly BinaryReader _reader;
private bool _closed;
private Exception _exception;
public bool IsConnected => !_closed;
public ClientReader(Stream stream)
{
_reader = new BinaryReader(stream, Constants.Encoding, leaveOpen: true);
}
public void Close()
{
if (_closed)
{
return;
}
_closed = true;
_reader.Dispose();
}
public TestDataKind ReadKind()
{
return (TestDataKind)ReadCore(() => _reader.ReadInt32());
}
public TestCaseData ReadTestCaseData()
{
return ReadCore(() => TestCaseData.ReadFrom(_reader));
}
public TestResultData ReadTestResultData()
{
return ReadCore(() => TestResultData.ReadFrom(_reader));
}
public string ReadString()
{
return ReadCore(() => _reader.ReadString());
}
private T ReadCore<T>(Func<T> func)
{
if (_closed)
{
if (_exception == null)
{
throw new Exception("Connection is closed");
}
throw new Exception("Connection is closed", _exception);
}
try
{
return func();
}
catch (Exception ex)
{
// Happens during rude shut down of the client. Log to the screen and close
// the connection.
Console.WriteLine(ex.Message);
_exception = ex;
Close();
throw;
}
}
#region IDisposable
void IDisposable.Dispose()
{
Close();
}
#endregion
}
}
-78
View File
@@ -1,78 +0,0 @@
using System;
using System.IO;
namespace Xunit.Runner.Data
{
public sealed class ClientWriter : IDisposable
{
private readonly BinaryWriter _writer;
private bool _closed;
public bool IsConnected => !_closed;
public ClientWriter(Stream stream)
{
_writer = new BinaryWriter(stream, Constants.Encoding, leaveOpen: true);
}
public void Close()
{
if (_closed)
{
return;
}
_closed = true;
_writer.Dispose();
}
public void Write(TestDataKind kind)
{
WriteCore(() => _writer.Write((int)kind));
}
public void Write(TestCaseData testCaseData)
{
WriteCore(() => testCaseData.WriteTo(_writer));
}
public void Write(TestResultData testCaseResultData)
{
WriteCore(() => testCaseResultData.WriteTo(_writer));
}
public void Write(string str)
{
WriteCore(() => _writer.Write(str));
}
private void WriteCore(Action action)
{
if (_closed)
{
return;
}
try
{
action();
}
catch (Exception ex)
{
// Happens during rude shut down of the client. Log to the screen and close
// the connection.
Console.WriteLine(ex.Message);
Close();
}
}
#region IDisposable
void IDisposable.Dispose()
{
Close();
}
#endregion
}
}
-12
View File
@@ -1,12 +0,0 @@
using System.Text;
namespace Xunit.Runner.Data
{
public static class Constants
{
public const string ActionDiscover = "discover";
public const string ActionRunAll = "runall";
public const string ActionRunSpecific = "runspecific";
public static readonly Encoding Encoding = Encoding.UTF8;
}
}
@@ -1,35 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("xunit.runner.data")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("xunit.runner.data")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a1f579f4-443e-4f64-bc55-998ab86ff293")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
-69
View File
@@ -1,69 +0,0 @@
using System.Collections.Generic;
using System.IO;
namespace Xunit.Runner.Data
{
public sealed class TestCaseData
{
public string DisplayName { get; set; }
public string UniqueID { get; set; }
public string SkipReason { get; set; }
public string AssemblyPath { get; set; }
public Dictionary<string, List<string>> TraitMap { get; set; }
public TestCaseData(string displayName, string uniqueID, string skipReason, string assemblyPath, Dictionary<string, List<string>> traitMap)
{
DisplayName = displayName;
UniqueID = uniqueID;
SkipReason = skipReason;
AssemblyPath = assemblyPath;
TraitMap = traitMap;
}
public static TestCaseData ReadFrom(BinaryReader reader)
{
var displayName = reader.ReadString();
var uniqueID = reader.ReadString();
var skipReason = reader.ReadString();
var assemblyPath = reader.ReadString();
var count = reader.ReadInt32();
var traitMap = new Dictionary<string, List<string>>(count);
for (int i = 0; i < count; i++)
{
var key = reader.ReadString();
var valueCount = reader.ReadInt32();
var values = new List<string>(valueCount);
for (int j = 0; j < valueCount; j++)
{
values.Add(reader.ReadString());
}
traitMap.Add(key, values);
}
return new TestCaseData(displayName, uniqueID, skipReason, assemblyPath, traitMap);
}
public void WriteTo(BinaryWriter writer)
{
writer.Write(DisplayName);
writer.Write(UniqueID);
writer.Write(SkipReason ?? string.Empty);
writer.Write(AssemblyPath);
writer.Write(TraitMap.Count);
foreach (var pair in TraitMap)
{
writer.Write(pair.Key);
writer.Write(pair.Value.Count);
foreach (var value in pair.Value)
{
writer.Write(value);
}
}
}
}
}
-8
View File
@@ -1,8 +0,0 @@
namespace Xunit.Runner.Data
{
public enum TestDataKind
{
Value = 1,
EndOfData = 2
}
}
-51
View File
@@ -1,51 +0,0 @@
using System.IO;
namespace Xunit.Runner.Data
{
/// <summary>
/// Note: More severe states are higher numbers.
/// <see cref="MainViewModel.TestRunVisitor_TestFinished(object, TestStateEventArgs)"/>
/// </summary>
public enum TestState
{
All = 0,
NotRun,
Running,
Passed,
Skipped,
Failed,
}
public sealed class TestResultData
{
public string TestCaseDisplayName { get; set; }
public string TestCaseUniqueID { get; set; }
public TestState TestState { get; set; }
public string Output { get; set; }
public TestResultData(string displayName, string uniqueID, TestState state, string output = "")
{
TestCaseDisplayName = displayName;
TestCaseUniqueID = uniqueID;
TestState = state;
Output = output;
}
public static TestResultData ReadFrom(BinaryReader reader)
{
var displayName = reader.ReadString();
var uniqueID = reader.ReadString();
var state = (TestState)reader.ReadInt32();
var output = reader.ReadString();
return new TestResultData(displayName, uniqueID, state, output);
}
public void WriteTo(BinaryWriter writer)
{
writer.Write(TestCaseDisplayName);
writer.Write(TestCaseUniqueID);
writer.Write((int)TestState);
writer.Write(Output);
}
}
}
@@ -1,59 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A1F579F4-443E-4F64-BC55-998AB86FF293}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Xunit.Runner.Data</RootNamespace>
<AssemblyName>xunit.runner.data</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ClientReader.cs" />
<Compile Include="ClientWriter.cs" />
<Compile Include="Constants.cs" />
<Compile Include="TestCaseData.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TestDataKind.cs" />
<Compile Include="TestResultData.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/>
</startup>
</configuration>
-93
View File
@@ -1,93 +0,0 @@
using System;
using System.IO;
using System.IO.Pipes;
namespace Xunit.Runner.Worker
{
internal abstract class Connection : IDisposable
{
private bool _closed;
internal abstract Stream Stream { get; }
internal abstract void WaitForClientConnect();
internal abstract void WaitForClientDone();
protected virtual void DisposeCore()
{
}
internal void Dispose()
{
if (_closed)
{
return;
}
_closed = true;
DisposeCore();
}
#region IDisposable
void IDisposable.Dispose()
{
Dispose();
}
#endregion
}
internal sealed class NamedPipeConnection : Connection
{
private readonly NamedPipeServerStream _stream;
internal override Stream Stream => _stream;
internal NamedPipeConnection(string pipeName)
{
_stream = new NamedPipeServerStream(pipeName, PipeDirection.InOut);
}
protected override void DisposeCore()
{
_stream.Dispose();
}
internal override void WaitForClientConnect()
{
_stream.WaitForConnection();
}
internal override void WaitForClientDone()
{
try
{
_stream.ReadByte();
}
catch (Exception ex)
{
// If there is an error reading from the client then clearly they are done
Console.WriteLine($"Error reading client done byte {ex.Message}");
}
}
}
internal sealed class TestConnection : Connection
{
private readonly MemoryStream _stream = new MemoryStream();
internal override Stream Stream => _stream;
internal override void WaitForClientConnect()
{
}
internal override void WaitForClientDone()
{
}
}
}
-53
View File
@@ -1,53 +0,0 @@
using System.IO;
using Xunit.Abstractions;
using Xunit.Runner.Data;
using Xunit.Runner.Worker.MessageSinks;
namespace Xunit.Runner.Worker
{
internal sealed class DiscoverUtil : XunitUtil
{
private sealed class TestDiscoverySink : BaseTestDiscoverySink
{
private readonly ClientWriter _writer;
internal TestDiscoverySink(ClientWriter writer)
{
_writer = writer;
}
protected override bool ShouldContinue => _writer.IsConnected;
protected override void OnTestDiscovered(ITestCaseDiscoveryMessage testCaseDiscovered)
{
var testCase = testCaseDiscovered.TestCase;
var testCaseData = new TestCaseData(
testCase.DisplayName,
testCase.UniqueID,
testCase.SkipReason,
testCaseDiscovered.TestAssembly.Assembly.AssemblyPath,
testCase.Traits);
_writer.Write(TestDataKind.Value);
_writer.Write(testCaseData);
}
}
internal static void Go(string assemblyFileName, Stream stream)
{
Go(assemblyFileName, stream, AppDomainSupport.IfAvailable,
(xunit, configuration, writer) =>
{
using (var sink = new TestDiscoverySink(writer))
{
xunit.Find(includeSourceInformation: false, messageSink: sink,
discoveryOptions: TestFrameworkOptions.ForDiscovery(configuration));
sink.Finished.WaitOne();
writer.Write(TestDataKind.EndOfData);
}
});
}
}
}
-117
View File
@@ -1,117 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Threading.Tasks;
using Xunit.Runner.Data;
namespace Xunit.Runner.Worker
{
internal sealed class Listener
{
private readonly string _pipeName;
private readonly List<Task> _taskList = new List<Task>();
internal Listener(string pipeName)
{
_pipeName = pipeName;
}
internal void Go()
{
bool success;
do
{
_taskList.RemoveAll(x => x.IsCompleted);
success = GoOne();
}
while (success);
// Wait for the existing tasks to complete before stopping the listener
Task.WaitAll(_taskList.ToArray());
}
private bool GoOne()
{
try
{
var namedPipe = new NamedPipeServerStream(_pipeName, PipeDirection.InOut, maxNumberOfServerInstances: -1);
namedPipe.WaitForConnection();
_taskList.Add(Task.Run(() => ProcessConnection(namedPipe)));
return true;
}
catch (Exception ex)
{
Console.WriteLine($"Error creating named pipe {ex.Message}");
return false;
}
}
private static void ProcessConnection(NamedPipeServerStream stream)
{
Console.WriteLine("Connection established processing");
ProcessConnectionCore(stream);
Console.WriteLine("Connection completed");
}
private static void ProcessConnectionCore(NamedPipeServerStream stream)
{
Debug.Assert(stream.IsConnected);
try
{
var reader = new ClientReader(stream);
var action = reader.ReadString();
var assemblyFileName = reader.ReadString();
switch (action)
{
case Constants.ActionDiscover:
Discover(stream, assemblyFileName);
break;
case Constants.ActionRunAll:
RunAll(stream, assemblyFileName);
break;
case Constants.ActionRunSpecific:
RunSpecific(stream, assemblyFileName);
break;
default:
Debug.Fail($"Invalid action {action}");
break;
}
}
catch (Exception ex)
{
// Happens during a rude disconnect by the client
Console.WriteLine(ex.Message);
}
finally
{
stream.Dispose();
}
}
private static void Discover(Stream stream, string assemblyFileName)
{
Console.WriteLine($"discover started: {assemblyFileName}");
DiscoverUtil.Go(assemblyFileName, stream);
Console.WriteLine("discover ended");
}
private static void RunAll(Stream stream, string assemblyFileName)
{
Console.WriteLine($"run all started: {assemblyFileName}");
RunUtil.RunAll(assemblyFileName, stream);
Console.WriteLine("run all ended");
}
private static void RunSpecific(Stream stream, string assemblyFileName)
{
Console.WriteLine($"run specific started: {assemblyFileName}");
RunUtil.RunSpecific(assemblyFileName, stream);
Console.WriteLine("run specific ended");
}
}
}
@@ -1,52 +0,0 @@
using System;
using Xunit.Abstractions;
namespace Xunit.Runner.Worker.MessageSinks
{
/// <summary>
/// An Xunit <see cref="IMessageSink"/> implementation without the dispatch overhead of <see cref="TestMessageVisitor"/>
/// and <see cref="TestMessageVisitor{TCompleteMessage}"/>.
/// </summary>
internal abstract class BaseMessageSink : LongLivedMarshalByRefObject, IMessageSink, IDisposable
{
private bool _disposed;
protected BaseMessageSink()
{
}
~BaseMessageSink()
{
Dispose(false);
}
protected virtual void DisposeCore(bool disposing)
{
}
private void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
DisposeCore(disposing);
_disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(true);
}
protected abstract bool OnMessage(IMessageSinkMessage message);
bool IMessageSink.OnMessage(IMessageSinkMessage message)
{
return OnMessage(message);
}
}
}
@@ -1,40 +0,0 @@
using System.Threading;
using Xunit.Abstractions;
namespace Xunit.Runner.Worker.MessageSinks
{
internal abstract class BaseTestDiscoverySink : BaseMessageSink
{
public ManualResetEvent Finished { get; }
protected BaseTestDiscoverySink()
{
Finished = new ManualResetEvent(false);
}
protected override void DisposeCore(bool disposing)
{
Finished.Dispose();
}
protected override bool OnMessage(IMessageSinkMessage message)
{
var discoveryMessage = message as ITestCaseDiscoveryMessage;
if (discoveryMessage != null)
{
OnTestDiscovered(discoveryMessage);
}
if (message is IDiscoveryCompleteMessage)
{
Finished.Set();
}
return ShouldContinue;
}
protected virtual bool ShouldContinue => true;
protected abstract void OnTestDiscovered(ITestCaseDiscoveryMessage testCaseDiscovered);
}
}
@@ -1,61 +0,0 @@
using System.Threading;
using Xunit.Abstractions;
namespace Xunit.Runner.Worker.MessageSinks
{
internal abstract class BaseTestRunSink : BaseMessageSink
{
public ManualResetEvent Finished { get; }
protected BaseTestRunSink()
{
Finished = new ManualResetEvent(false);
}
protected override void DisposeCore(bool disposing)
{
Finished.Dispose();
}
protected override bool OnMessage(IMessageSinkMessage message)
{
var testStarted = message as ITestStarting;
if (testStarted != null)
{
OnTestStarted(testStarted);
}
var testFailed = message as ITestFailed;
if (testFailed != null)
{
OnTestFailed(testFailed);
}
var testPassed = message as ITestPassed;
if (testPassed != null)
{
OnTestPassed(testPassed);
}
var testSkipped = message as ITestSkipped;
if (testSkipped != null)
{
OnTestSkipped(testSkipped);
}
if (message is ITestAssemblyFinished)
{
Finished.Set();
}
return ShouldContinue;
}
protected virtual bool ShouldContinue => true;
protected abstract void OnTestStarted(ITestStarting testStarted);
protected abstract void OnTestFailed(ITestFailed testFailed);
protected abstract void OnTestPassed(ITestPassed testPassed);
protected abstract void OnTestSkipped(ITestSkipped testSkipped);
}
}
@@ -1,12 +0,0 @@
using Xunit.Abstractions;
namespace Xunit.Runner.Worker.MessageSinks
{
internal class DiagnosticSink : BaseMessageSink
{
protected override bool OnMessage(IMessageSinkMessage message)
{
return true;
}
}
}
-44
View File
@@ -1,44 +0,0 @@
using System;
using System.Diagnostics;
using System.Threading.Tasks;
namespace Xunit.Runner.Worker
{
public static class Program
{
private const int ExitSuccess = 0;
private const int ExitError = 1;
public static int Main(string[] args)
{
if (args.Length < 2)
{
Usage();
return ExitError;
}
var pipeName = args[0];
var parentPid = Int32.Parse(args[1]);
var process = Process.GetProcessById(parentPid);
if (process == null)
{
Console.WriteLine($"Invalid parent pid {parentPid}");
return ExitError;
}
Task.WaitAny(
Task.Run(() => process.WaitForExit()),
Task.Run(() => new Listener(pipeName).Go()));
return ExitSuccess;
}
private static void Usage()
{
Console.WriteLine("xunit.runner.worker [pipe name] [action] [assembly path]");
Console.WriteLine("\tpipe name: Name of the pipe this worker should communicate on");
Console.WriteLine("\taction: Action performed by the worker (run or discover tests)");
Console.WriteLine("\tassembly path: Path of assembly to perform the action against");
}
}
}
@@ -1,35 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("xunit.runner.worker")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("xunit.runner.worker")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("9df97a2b-0eb5-4b12-9f81-69dfac979814")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
-160
View File
@@ -1,160 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Xunit.Runner.Data;
using Xunit.Abstractions;
using Xunit.Runner.Worker.MessageSinks;
namespace Xunit.Runner.Worker
{
internal sealed class RunUtil : XunitUtil
{
private sealed class TestRunSink : BaseTestRunSink
{
private readonly ClientWriter _writer;
public TestRunSink(ClientWriter writer)
{
_writer = writer;
}
protected override bool ShouldContinue => _writer.IsConnected;
private void Process(string displayName, string uniqueID, TestState state, string output = "")
{
System.Diagnostics.Trace.WriteLine($"{state} - {displayName}");
var result = new TestResultData(displayName, uniqueID, state, output);
_writer.Write(TestDataKind.Value);
_writer.Write(result);
}
protected override void OnTestStarted(ITestStarting testStarted)
{
Process(testStarted.TestCase.DisplayName, testStarted.TestCase.UniqueID, TestState.Running);
}
protected override void OnTestFailed(ITestFailed testFailed)
{
var displayName = testFailed.TestCase.DisplayName;
var builder = new StringBuilder();
builder.AppendLine($"{displayName} FAILED:");
for (int i = 0; i < testFailed.ExceptionTypes.Length; i++)
{
builder.AppendLine($"\tException type: '{testFailed.ExceptionTypes[i]}', number: '{i}', parent: '{testFailed.ExceptionParentIndices[i]}'");
builder.AppendLine($"\tException message:");
builder.AppendLine(testFailed.Messages[i]);
builder.AppendLine($"\tException stacktrace");
builder.AppendLine(testFailed.StackTraces[i]);
}
builder.AppendLine();
Process(testFailed.TestCase.DisplayName, testFailed.TestCase.UniqueID, TestState.Failed, builder.ToString());
}
protected override void OnTestPassed(ITestPassed testPassed)
{
Process(testPassed.TestCase.DisplayName, testPassed.TestCase.UniqueID, TestState.Passed);
}
protected override void OnTestSkipped(ITestSkipped testSkipped)
{
Process(testSkipped.TestCase.DisplayName, testSkipped.TestCase.UniqueID, TestState.Skipped);
}
}
private sealed class TestDiscoverySink : BaseTestDiscoverySink
{
private readonly HashSet<string> _testCaseUniqueIDSet;
private readonly List<ITestCase> _testCaseList;
internal TestDiscoverySink(HashSet<string> testCaseUniqueIDSet, List<ITestCase> testCaseList)
{
_testCaseUniqueIDSet = testCaseUniqueIDSet;
_testCaseList = testCaseList;
}
protected override void OnTestDiscovered(ITestCaseDiscoveryMessage testCaseDiscovered)
{
var testCase = testCaseDiscovered.TestCase;
if (_testCaseUniqueIDSet.Contains(testCase.UniqueID))
{
_testCaseList.Add(testCaseDiscovered.TestCase);
}
}
}
/// <summary>
/// Read out the set of test case unique IDs to run.
/// </summary>
private static List<string> ReadTestCaseUniqueIDs(Stream stream)
{
using (var reader = new ClientReader(stream))
{
var list = new List<string>();
while (reader.ReadKind() == TestDataKind.Value)
{
list.Add(reader.ReadString());
}
return list;
}
}
private static List<ITestCase> GetTestCaseList(XunitFrontController xunit, TestAssemblyConfiguration configuration, HashSet<string> testCaseNameSet)
{
var testCaseList = new List<ITestCase>();
using (var sink = new TestDiscoverySink(testCaseNameSet, testCaseList))
{
xunit.Find(includeSourceInformation: false, messageSink: sink,
discoveryOptions: TestFrameworkOptions.ForDiscovery(configuration));
sink.Finished.WaitOne();
}
return testCaseList;
}
internal static void RunAll(string assemblyFileName, Stream stream)
{
Go(assemblyFileName, stream, AppDomainSupport.IfAvailable,
(xunit, configuration, writer) =>
{
using (var sink = new TestRunSink(writer))
{
xunit.RunAll(sink,
discoveryOptions: TestFrameworkOptions.ForDiscovery(configuration),
executionOptions: TestFrameworkOptions.ForExecution(configuration));
sink.Finished.WaitOne();
writer.Write(TestDataKind.EndOfData);
}
});
}
internal static void RunSpecific(string assemblyFileName, Stream stream)
{
var testCaseUniqueIDSet = new HashSet<string>(ReadTestCaseUniqueIDs(stream), StringComparer.Ordinal);
Go(assemblyFileName, stream, AppDomainSupport.IfAvailable,
(xunit, configuration, writer) =>
{
using (var sink = new TestRunSink(writer))
{
var testCaseList = GetTestCaseList(xunit, configuration, testCaseUniqueIDSet);
xunit.RunTests(testCaseList, sink,
executionOptions: TestFrameworkOptions.ForExecution(configuration));
sink.Finished.WaitOne();
writer.Write(TestDataKind.EndOfData);
}
});
}
}
}
-21
View File
@@ -1,21 +0,0 @@
using System;
using System.IO;
using Xunit.Runner.Data;
namespace Xunit.Runner.Worker
{
internal abstract class XunitUtil
{
protected static void Go(string assemblyFileName, Stream stream, AppDomainSupport appDomainSupport,
Action<XunitFrontController, TestAssemblyConfiguration, ClientWriter> action)
{
using (AssemblyHelper.SubscribeResolve())
using (var xunit = new XunitFrontController(appDomainSupport, assemblyFileName, shadowCopy: false))
using (var writer = new ClientWriter(stream))
{
var configuration = ConfigReader.Load(assemblyFileName);
action(xunit, configuration, writer);
}
}
}
}
-5
View File
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="xunit.abstractions" version="2.0.0" targetFramework="net452" />
<package id="xunit.runner.utility" version="2.1.0" targetFramework="net46" />
</packages>
@@ -1,86 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{9DF97A2B-0EB5-4B12-9F81-69DFAC979814}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Xunit.Runner.Worker</RootNamespace>
<AssemblyName>xunit.runner.worker</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="xunit.abstractions">
<HintPath>..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll</HintPath>
</Reference>
<Reference Include="xunit.runner.utility.desktop, Version=2.1.0.3179, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\packages\xunit.runner.utility.2.1.0\lib\net35\xunit.runner.utility.desktop.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Connection.cs" />
<Compile Include="DiscoverUtil.cs" />
<Compile Include="Listener.cs" />
<Compile Include="MessageSinks\BaseMessageSink.cs" />
<Compile Include="MessageSinks\BaseTestRunSink.cs" />
<Compile Include="MessageSinks\DiagnosticSink.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RunUtil.cs" />
<Compile Include="MessageSinks\BaseTestDiscoverySink.cs" />
<Compile Include="XunitUtil.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\xunit.runner.data\xunit.runner.data.csproj">
<Project>{a1f579f4-443e-4f64-bc55-998ab86ff293}</Project>
<Name>xunit.runner.data</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
+10 -19
View File
@@ -1,40 +1,31 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.4
# Visual Studio Version 16
VisualStudioVersion = 16.0.30011.22
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "xunit.runner.wpf", "xunit.runner.wpf\xunit.runner.wpf.csproj", "{34FB519C-FB49-4B31-ACA2-7F7879311BCF}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "xunit.runner.wpf", "xunit.runner.wpf\xunit.runner.wpf.csproj", "{4120F4AC-1B24-4B7C-86A9-0A3C75E526CD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleTestAssembly", "SampleTestAssembly\SampleTestAssembly.csproj", "{BDAFB5DD-FFB3-4A94-A312-DFB080010846}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "xunit.runner.worker", "xunit.runner.worker\xunit.runner.worker.csproj", "{9DF97A2B-0EB5-4B12-9F81-69DFAC979814}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "xunit.runner.data", "xunit.runner.data\xunit.runner.data.csproj", "{A1F579F4-443E-4F64-BC55-998AB86FF293}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{34FB519C-FB49-4B31-ACA2-7F7879311BCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{34FB519C-FB49-4B31-ACA2-7F7879311BCF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{34FB519C-FB49-4B31-ACA2-7F7879311BCF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{34FB519C-FB49-4B31-ACA2-7F7879311BCF}.Release|Any CPU.Build.0 = Release|Any CPU
{4120F4AC-1B24-4B7C-86A9-0A3C75E526CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4120F4AC-1B24-4B7C-86A9-0A3C75E526CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4120F4AC-1B24-4B7C-86A9-0A3C75E526CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4120F4AC-1B24-4B7C-86A9-0A3C75E526CD}.Release|Any CPU.Build.0 = Release|Any CPU
{BDAFB5DD-FFB3-4A94-A312-DFB080010846}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BDAFB5DD-FFB3-4A94-A312-DFB080010846}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BDAFB5DD-FFB3-4A94-A312-DFB080010846}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BDAFB5DD-FFB3-4A94-A312-DFB080010846}.Release|Any CPU.Build.0 = Release|Any CPU
{9DF97A2B-0EB5-4B12-9F81-69DFAC979814}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9DF97A2B-0EB5-4B12-9F81-69DFAC979814}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9DF97A2B-0EB5-4B12-9F81-69DFAC979814}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9DF97A2B-0EB5-4B12-9F81-69DFAC979814}.Release|Any CPU.Build.0 = Release|Any CPU
{A1F579F4-443E-4F64-BC55-998AB86FF293}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A1F579F4-443E-4F64-BC55-998AB86FF293}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A1F579F4-443E-4F64-BC55-998AB86FF293}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A1F579F4-443E-4F64-BC55-998AB86FF293}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F8EBD009-FF10-49B8-91DB-F90A51C529BA}
EndGlobalSection
EndGlobal
+3 -3
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
</configuration>
</configuration>
+6 -13
View File
@@ -1,14 +1,7 @@
<Application x:Class="Xunit.Runner.Wpf.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Xunit.Runner.Wpf"
StartupUri="MainWindow.xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
d1p1:Ignorable="d"
xmlns:d1p1="http://schemas.openxmlformats.org/markup-compatibility/2006">
<Application.Resources>
<vm:ViewModelLocator x:Key="Locator"
d:IsDataSource="True"
xmlns:vm="clr-namespace:Xunit.Runner.Wpf.ViewModel" />
</Application.Resources>
<Application x:Class="Xunit.Runner.Wpf.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Xunit.Runner.Wpf" StartupUri="MainWindow.xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" d1p1:Ignorable="d" xmlns:d1p1="http://schemas.openxmlformats.org/markup-compatibility/2006">
<Application.Resources>
<ResourceDictionary>
<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" xmlns:vm="clr-namespace:Xunit.Runner.Wpf.ViewModel" />
</ResourceDictionary>
</Application.Resources>
</Application>
+13 -4
View File
@@ -1,8 +1,17 @@
using System.Windows;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace Xunit.Runner.Wpf
{
public partial class App : Application
{
}
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}
+384
View File
@@ -0,0 +1,384 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Xunit.Abstractions;
using Xunit.Runner.Wpf;
using Xunit.Sdk;
namespace Xunit.Runners
{
/// <summary>
/// A class which makes it simpler for casual runner authors to find and run tests and get results.
/// Adapted from: https://github.com/xunit/xunit/blob/main/src/xunit.v3.runner.utility/Runners/AssemblyRunner.cs
/// </summary>
public class AssemblyRunner2 : LongLivedMarshalByRefObject, IDisposable, IMessageSinkWithTypes
{
static readonly Dictionary<Type, string> MessageTypeNames;
private TaskCompletionSource<string> tcs { get; set; }
private CancellationToken cancellationToken { get; set; }
volatile bool cancelled;
bool disposed;
readonly TestAssemblyConfiguration configuration;
readonly IFrontController controller;
string assemblyFileName { get; set; }
int testCasesDiscovered;
readonly List<ITestCase> testCasesToRun = new List<ITestCase>();
static AssemblyRunner2()
{
MessageTypeNames = new Dictionary<Type, string>();
AddMessageTypeName<IDiagnosticMessage>();
AddMessageTypeName<IDiscoveryCompleteMessage>();
AddMessageTypeName<IErrorMessage>();
AddMessageTypeName<ITestAssemblyCleanupFailure>();
AddMessageTypeName<ITestAssemblyFinished>();
AddMessageTypeName<ITestCaseCleanupFailure>();
AddMessageTypeName<ITestCaseDiscoveryMessage>();
AddMessageTypeName<ITestClassCleanupFailure>();
AddMessageTypeName<ITestCleanupFailure>();
AddMessageTypeName<ITestCollectionCleanupFailure>();
AddMessageTypeName<ITestFailed>();
AddMessageTypeName<ITestFinished>();
AddMessageTypeName<ITestMethodCleanupFailure>();
AddMessageTypeName<ITestOutput>();
AddMessageTypeName<ITestPassed>();
AddMessageTypeName<ITestSkipped>();
AddMessageTypeName<ITestStarting>();
}
AssemblyRunner2(AppDomainSupport appDomainSupport,
string assemblyFileName,
TaskCompletionSource<string> tcs,
CancellationToken cancellationToken,
string configFileName = null,
bool shadowCopy = true,
string shadowCopyFolder = null)
{
this.tcs = tcs;
this.cancellationToken = cancellationToken;
this.assemblyFileName = assemblyFileName;
controller = new XunitFrontController(appDomainSupport, assemblyFileName, configFileName, shadowCopy, shadowCopyFolder, diagnosticMessageSink: MessageSinkAdapter.Wrap(this));
configuration = ConfigReader.Load(assemblyFileName, configFileName);
}
/// <summary>
/// Set to get notification of diagnostic messages.
/// </summary>
public Action<DiagnosticMessageInfo> OnDiagnosticMessage { get; set; }
/// <summary>
/// Set to get notification of when test discovery is complete.
/// </summary>
public Action<TestDiscoveryInfo> OnDiscoveryComplete { get; set; }
/// <summary>
/// Set to get notification of error messages (unhandled exceptions outside of tests).
/// </summary>
public Action<ErrorMessageInfo> OnErrorMessage { get; set; }
/// <summary>
/// Set to get notification of when test execution is complete.
/// </summary>
public Action<ExecutionCompleteInfo> OnExecutionComplete { get; set; }
/// <summary>
/// Set to get notification of failed tests.
/// </summary>
public Action<TestFailedInfo> OnTestFailed { get; set; }
/// <summary>
/// Set to get notification of finished tests (regardless of outcome).
/// </summary>
public Action<TestFinishedInfo> OnTestFinished { get; set; }
/// <summary>
/// Set to get real-time notification of test output (for xUnit.net v2 tests only).
/// Note that output is captured and reported back to all the test completion Info>s
/// in addition to being sent to this Info>.
/// </summary>
public Action<TestOutputInfo> OnTestOutput { get; set; }
/// <summary>
/// Set to get notification of passing tests.
/// </summary>
public Action<TestPassedInfo> OnTestPassed { get; set; }
/// <summary>
/// Set to get notification of skipped tests.
/// </summary>
public Action<TestSkippedInfo> OnTestSkipped { get; set; }
/// <summary>
/// Set to get notification of when tests start running.
/// </summary>
public Action<TestStartingInfo> OnTestStarting { get; set; }
/// <summary>
/// Set to be able to filter the test cases to decide which ones to run. If this is not set,
/// then all test cases will be run.
/// </summary>
public Func<ITestCase, bool> TestCaseFilter { get; set; }
static void AddMessageTypeName<T>() => MessageTypeNames.Add(typeof(T), typeof(T).FullName);
/// <summary>
/// Call to request that the current run be cancelled. Note that cancellation may not be
/// instantaneous, and even after cancellation has been acknowledged, you can expect to
/// receive all the cleanup-related messages.
/// </summary>
public void Cancel()
{
cancelled = true;
}
/// <inheritdoc/>
public void Dispose()
{
if (disposed)
return;
disposed = true;
controller?.Dispose();
}
ITestFrameworkDiscoveryOptions GetDiscoveryOptions(bool? diagnosticMessages, TestMethodDisplay? methodDisplay, TestMethodDisplayOptions? methodDisplayOptions, bool? preEnumerateTheories, bool? internalDiagnosticMessages)
{
var discoveryOptions = TestFrameworkOptions.ForDiscovery(configuration);
discoveryOptions.SetSynchronousMessageReporting(true);
if (diagnosticMessages.HasValue)
discoveryOptions.SetDiagnosticMessages(diagnosticMessages);
if (internalDiagnosticMessages.HasValue)
discoveryOptions.SetDiagnosticMessages(internalDiagnosticMessages);
if (methodDisplay.HasValue)
discoveryOptions.SetMethodDisplay(methodDisplay);
if (methodDisplayOptions.HasValue)
discoveryOptions.SetMethodDisplayOptions(methodDisplayOptions);
if (preEnumerateTheories.HasValue)
discoveryOptions.SetPreEnumerateTheories(preEnumerateTheories);
return discoveryOptions;
}
ITestFrameworkExecutionOptions GetExecutionOptions(bool? diagnosticMessages, bool? parallel, int? maxParallelThreads, bool? internalDiagnosticMessages)
{
var executionOptions = TestFrameworkOptions.ForExecution(configuration);
executionOptions.SetSynchronousMessageReporting(true);
if (diagnosticMessages.HasValue)
executionOptions.SetDiagnosticMessages(diagnosticMessages);
if (internalDiagnosticMessages.HasValue)
executionOptions.SetDiagnosticMessages(internalDiagnosticMessages);
if (parallel.HasValue)
executionOptions.SetDisableParallelization(!parallel.GetValueOrDefault());
if (maxParallelThreads.HasValue)
executionOptions.SetMaxParallelThreads(maxParallelThreads);
return executionOptions;
}
/// <summary>
/// Starts running tests from a single type (if provided) or the whole assembly (if not). This call returns
/// immediately, and status results are dispatched to the Info>s on this class. Callers can check <see cref="Status"/>
/// to find out the current status.
/// </summary>
/// <param name="typeName">The (optional) type name of the single test class to run</param>
/// <param name="diagnosticMessages">Set to <c>true</c> to enable diagnostic messages; set to <c>false</c> to disable them.
/// By default, uses the value from the assembly configuration file.</param>
/// <param name="methodDisplay">Set to choose the default display name style for test methods.
/// By default, uses the value from the assembly configuration file. (This parameter is ignored for xUnit.net v1 tests.)</param>
/// <param name="methodDisplayOptions">Set to choose the default display name style options for test methods.
/// By default, uses the value from the assembly configuration file. (This parameter is ignored for xUnit.net v1 tests.)</param>
/// <param name="preEnumerateTheories">Set to <c>true</c> to pre-enumerate individual theory tests; set to <c>false</c> to use
/// a single test case for the theory. By default, uses the value from the assembly configuration file. (This parameter is ignored
/// for xUnit.net v1 tests.)</param>
/// <param name="parallel">Set to <c>true</c> to run test collections in parallel; set to <c>false</c> to run them sequentially.
/// By default, uses the value from the assembly configuration file. (This parameter is ignored for xUnit.net v1 tests.)</param>
/// <param name="maxParallelThreads">Set to 0 to use unlimited threads; set to any other positive integer to limit to an exact number
/// of threads. By default, uses the value from the assembly configuration file. (This parameter is ignored for xUnit.net v1 tests.)</param>
/// <param name="internalDiagnosticMessages">Set to <c>true</c> to enable internal diagnostic messages; set to <c>false</c> to disable them.
/// By default, uses the value from the assembly configuration file.</param>
public void Discover(
string typeName = null,
bool? diagnosticMessages = null,
TestMethodDisplay? methodDisplay = null,
TestMethodDisplayOptions? methodDisplayOptions = null,
bool? preEnumerateTheories = null,
bool? internalDiagnosticMessages = null)
{
cancelled = false;
testCasesDiscovered = 0;
testCasesToRun.Clear();
XunitWorkerThread.QueueUserWorkItem(() =>
{
var discoveryOptions = GetDiscoveryOptions(diagnosticMessages, methodDisplay, methodDisplayOptions, preEnumerateTheories, internalDiagnosticMessages);
if (typeName != null)
controller.Find(typeName, false, this, discoveryOptions);
else
controller.Find(false, this, discoveryOptions);
if (cancelled)
{
// Synthesize the execution complete message, since we're not going to run at all
if (OnExecutionComplete != null)
OnExecutionComplete(ExecutionCompleteInfo.Empty);
return;
}
});
}
public void Run(List<ITestCase> cases,
bool? diagnosticMessages = null,
bool? parallel = null,
int? maxParallelThreads = null,
bool? internalDiagnosticMessages = null)
{
cancelled = false;
testCasesDiscovered = cases.Count();
testCasesToRun.Clear();
testCasesToRun.AddRange(cases);
XunitWorkerThread.QueueUserWorkItem(() =>
{
if (cancelled)
{
// Synthesize the execution complete message, since we're not going to run at all
if (OnExecutionComplete != null)
OnExecutionComplete(ExecutionCompleteInfo.Empty);
return;
}
var executionOptions = GetExecutionOptions(diagnosticMessages, parallel, maxParallelThreads, internalDiagnosticMessages);
controller.RunTests(testCasesToRun, this, executionOptions);
});
}
/// <summary>
/// Creates an assembly runner that discovers and run tests in a separate app domain.
/// </summary>
/// <param name="assemblyFileName">The test assembly.</param>
/// <param name="configFileName">The test assembly configuration file.</param>
/// <param name="shadowCopy">If set to <c>true</c>, runs tests in a shadow copied app domain, which allows
/// tests to be discovered and run without locking assembly files on disk.</param>
/// <param name="shadowCopyFolder">The path on disk to use for shadow copying; if <c>null</c>, a folder
/// will be automatically (randomly) generated</param>
//public static AssemblyRunner2 WithAppDomain(string assemblyFileName,
// string configFileName = null,
// bool shadowCopy = true,
// string shadowCopyFolder = null)
//{
// //Guard.ArgumentValid(nameof(shadowCopyFolder), "Cannot set shadowCopyFolder if shadowCopy is false", shadowCopy == true || shadowCopyFolder == null);
// return new AssemblyRunner2(AppDomainSupport.Required, assemblyFileName, configFileName, shadowCopy, shadowCopyFolder);
//}
/// <summary>
/// Creates an assembly runner that discovers and runs tests without a separate app domain.
/// </summary>
/// <param name="assemblyFileName">The test assembly.</param>
public static AssemblyRunner2 WithoutAppDomain(string assemblyFileName, TaskCompletionSource<string> tcs, CancellationToken cancellationToken)
{
return new AssemblyRunner2(AppDomainSupport.Denied, assemblyFileName, tcs, cancellationToken);
}
bool DispatchMessage<TMessage>(IMessageSinkMessage message, HashSet<string> messageTypes, Action<TMessage> handler)
where TMessage : class
{
if (messageTypes == null || !MessageTypeNames.TryGetValue(typeof(TMessage), out var typeName) || !messageTypes.Contains(typeName))
return false;
handler((TMessage)message);
return true;
}
bool IMessageSinkWithTypes.OnMessageWithTypes(IMessageSinkMessage message, HashSet<string> messageTypes)
{
if (cancellationToken.IsCancellationRequested)
{
cancelled = true;
}
if (DispatchMessage<ITestCaseDiscoveryMessage>(message, messageTypes, testDiscovered =>
{
++testCasesDiscovered;
if (TestCaseFilter == null || TestCaseFilter(testDiscovered.TestCase))
testCasesToRun.Add(testDiscovered.TestCase);
}))
return !cancelled;
if (DispatchMessage<IDiscoveryCompleteMessage>(message, messageTypes, discoveryComplete =>
{
OnDiscoveryComplete?.Invoke(new TestDiscoveryInfo(testCasesToRun, assemblyFileName));
tcs.TrySetResult("");
}))
return !cancelled;
if (DispatchMessage<ITestAssemblyFinished>(message, messageTypes, assemblyFinished =>
{
OnExecutionComplete?.Invoke(new ExecutionCompleteInfo(assemblyFinished.TestsRun, assemblyFinished.TestsFailed, assemblyFinished.TestsSkipped, assemblyFinished.ExecutionTime));
tcs.TrySetResult("");
}))
return !cancelled;
if (OnDiagnosticMessage != null)
if (DispatchMessage<IDiagnosticMessage>(message, messageTypes, m => OnDiagnosticMessage(new DiagnosticMessageInfo(m.Message))))
return !cancelled;
if (OnTestFailed != null)
if (DispatchMessage<ITestFailed>(message, messageTypes, m => OnTestFailed(new TestFailedInfo(m.TestClass.Class.Name, m.TestMethod.Method.Name, m.TestCase.Traits, m.Test.DisplayName, m.TestCollection.DisplayName, m.ExecutionTime, m.Output, m.ExceptionTypes.FirstOrDefault(), m.Messages.FirstOrDefault(), m.StackTraces.FirstOrDefault()))))
return !cancelled;
if (OnTestFinished != null)
if (DispatchMessage<ITestFinished>(message, messageTypes, m => OnTestFinished(new TestFinishedInfo(m.TestClass.Class.Name, m.TestMethod.Method.Name, m.TestCase.Traits, m.Test.DisplayName, m.TestCollection.DisplayName, m.ExecutionTime, m.Output))))
return !cancelled;
if (OnTestOutput != null)
if (DispatchMessage<ITestOutput>(message, messageTypes, m => OnTestOutput(new TestOutputInfo(m.TestClass.Class.Name, m.TestMethod.Method.Name, m.TestCase.Traits, m.Test.DisplayName, m.TestCollection.DisplayName, m.Output))))
return !cancelled;
if (OnTestPassed != null)
if (DispatchMessage<ITestPassed>(message, messageTypes, m => OnTestPassed(new TestPassedInfo(m.TestClass.Class.Name, m.TestMethod.Method.Name, m.TestCase.Traits, m.Test.DisplayName, m.TestCollection.DisplayName, m.ExecutionTime, m.Output))))
return !cancelled;
if (OnTestSkipped != null)
if (DispatchMessage<ITestSkipped>(message, messageTypes, m => OnTestSkipped(new TestSkippedInfo(m.TestClass.Class.Name, m.TestMethod.Method.Name, m.TestCase.Traits, m.Test.DisplayName, m.TestCollection.DisplayName, m.Reason))))
return !cancelled;
if (OnTestStarting != null)
if (DispatchMessage<ITestStarting>(message, messageTypes, m => OnTestStarting(new TestStartingInfo(m.TestClass.Class.Name, m.TestMethod.Method.Name, m.TestCase.Traits, m.Test.DisplayName, m.TestCollection.DisplayName))))
return !cancelled;
if (OnErrorMessage != null)
{
if (DispatchMessage<IErrorMessage>(message, messageTypes, m => OnErrorMessage(new ErrorMessageInfo(ErrorMessageType.CatastrophicError, m.ExceptionTypes.FirstOrDefault(), m.Messages.FirstOrDefault(), m.StackTraces.FirstOrDefault()))))
return !cancelled;
if (DispatchMessage<ITestAssemblyCleanupFailure>(message, messageTypes, m => OnErrorMessage(new ErrorMessageInfo(ErrorMessageType.TestAssemblyCleanupFailure, m.ExceptionTypes.FirstOrDefault(), m.Messages.FirstOrDefault(), m.StackTraces.FirstOrDefault()))))
return !cancelled;
if (DispatchMessage<ITestCaseCleanupFailure>(message, messageTypes, m => OnErrorMessage(new ErrorMessageInfo(ErrorMessageType.TestCaseCleanupFailure, m.ExceptionTypes.FirstOrDefault(), m.Messages.FirstOrDefault(), m.StackTraces.FirstOrDefault()))))
return !cancelled;
if (DispatchMessage<ITestClassCleanupFailure>(message, messageTypes, m => OnErrorMessage(new ErrorMessageInfo(ErrorMessageType.TestClassCleanupFailure, m.ExceptionTypes.FirstOrDefault(), m.Messages.FirstOrDefault(), m.StackTraces.FirstOrDefault()))))
return !cancelled;
if (DispatchMessage<ITestCleanupFailure>(message, messageTypes, m => OnErrorMessage(new ErrorMessageInfo(ErrorMessageType.TestCleanupFailure, m.ExceptionTypes.FirstOrDefault(), m.Messages.FirstOrDefault(), m.StackTraces.FirstOrDefault()))))
return !cancelled;
if (DispatchMessage<ITestCollectionCleanupFailure>(message, messageTypes, m => OnErrorMessage(new ErrorMessageInfo(ErrorMessageType.TestCollectionCleanupFailure, m.ExceptionTypes.FirstOrDefault(), m.Messages.FirstOrDefault(), m.StackTraces.FirstOrDefault()))))
return !cancelled;
if (DispatchMessage<ITestMethodCleanupFailure>(message, messageTypes, m => OnErrorMessage(new ErrorMessageInfo(ErrorMessageType.TestMethodCleanupFailure, m.ExceptionTypes.FirstOrDefault(), m.Messages.FirstOrDefault(), m.StackTraces.FirstOrDefault()))))
return !cancelled;
}
return !cancelled;
}
}
}
@@ -3,80 +3,80 @@ using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Xunit.Runner.Data;
namespace Xunit.Runner.Wpf.Converters
{
public class TestStateConverter : IValueConverter
public class TestStateConverter : IValueConverter
{
private static ImageSource runningSource;
private static ImageSource failedSource;
private static ImageSource passedSource;
private static ImageSource skippedSource;
private static SolidColorBrush skippedBrush = new SolidColorBrush(Color.FromRgb(0xEB, 0xCA, 0x00));
static TestStateConverter()
{
private static ImageSource runningSource;
private static ImageSource failedSource;
private static ImageSource passedSource;
private static ImageSource skippedSource;
private static SolidColorBrush skippedBrush = new SolidColorBrush(Color.FromRgb(0xEB, 0xCA, 0x00));
static TestStateConverter()
{
runningSource = LoadResourceImage("Running_small.png");
failedSource = LoadResourceImage("Failed_small.png");
passedSource = LoadResourceImage("Passed_small.png");
skippedSource = LoadResourceImage("Skipped_small.png");
}
private static BitmapImage LoadResourceImage(string resourceName)
{
var image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri("pack://application:,,,/xunit.runner.wpf;component/Artwork/" + resourceName);
image.EndInit();
return image;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var state = (TestState)value;
if (targetType == typeof(Brush))
{
switch (state)
{
case TestState.Running:
return Brushes.Blue;
case TestState.Failed:
return Brushes.Red;
case TestState.Passed:
return Brushes.Green;
case TestState.Skipped:
return skippedBrush;
default:
return Brushes.Gray;
}
}
else if (targetType == typeof(ImageSource))
{
switch (state)
{
case TestState.Running:
return runningSource;
case TestState.Failed:
return failedSource;
case TestState.Passed:
return passedSource;
case TestState.Skipped:
return skippedSource;
default:
return null;
}
}
else
{
throw new NotSupportedException();
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
runningSource = LoadResourceImage("Running_small.png");
failedSource = LoadResourceImage("Failed_small.png");
passedSource = LoadResourceImage("Passed_small.png");
skippedSource = LoadResourceImage("Skipped_small.png");
}
private static BitmapImage LoadResourceImage(string resourceName)
{
var image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri("pack://application:,,,/xunit.runner.wpf;component/Artwork/" + resourceName);
image.EndInit();
return image;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var state = (TestState)value;
if (targetType == typeof(Brush))
{
switch (state)
{
case TestState.Running:
return Brushes.Blue;
case TestState.Failed:
return Brushes.Red;
case TestState.Passed:
return Brushes.Green;
case TestState.Skipped:
return skippedBrush;
default:
return Brushes.Gray;
}
}
else if (targetType == typeof(ImageSource))
{
switch (state)
{
case TestState.Running:
return runningSource;
case TestState.Failed:
return failedSource;
case TestState.Passed:
return passedSource;
case TestState.Skipped:
return skippedSource;
default:
return null;
}
}
else
{
throw new NotSupportedException();
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
+50
View File
@@ -0,0 +1,50 @@
using mscoree;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace Xunit.Runner.Wpf
{
public static class AppDomains
{
public static IEnumerable<AppDomain> EnumAppDomains()
{
IntPtr enumHandle = IntPtr.Zero;
ICorRuntimeHost host = null;
try
{
host = GetCorRuntimeHost();
host.EnumDomains(out enumHandle);
object domain = null;
host.NextDomain(enumHandle, out domain);
while (domain != null)
{
yield return (AppDomain)domain;
host.NextDomain(enumHandle, out domain);
}
}
finally
{
if (host != null)
{
if (enumHandle != IntPtr.Zero)
{
host.CloseEnum(enumHandle);
}
Marshal.ReleaseComObject(host);
}
}
}
private static ICorRuntimeHost GetCorRuntimeHost()
{
return (ICorRuntimeHost)Activator.CreateInstance(Marshal.GetTypeFromCLSID(new Guid("CB2F6723-AB3A-11D2-9C40-00C04FA30A3E")));
}
}
}
@@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
namespace Xunit.Runner.Wpf
{
public static partial class Extensions
{
private class FuncComparer<T> : IComparer<T>
{
private readonly Func<T, T, int> _comparison;
public FuncComparer(Func<T, T, int> comparison)
{
_comparison = comparison;
}
public int Compare(T x, T y) => _comparison(x, y);
}
}
}
+105 -91
View File
@@ -4,97 +4,111 @@ using System.Collections.ObjectModel;
namespace Xunit.Runner.Wpf
{
public static partial class Extensions
public static partial class Extensions
{
public static void AddRange<TList, TEnumerable>(this ICollection<TList> list, IEnumerable<TEnumerable> items) where TEnumerable : TList
{
public static void AddRange<TList, TEnumerable>(this ICollection<TList> list, IEnumerable<TEnumerable> items) where TEnumerable : TList
{
foreach (var i in items)
{
list.Add(i);
}
}
public static void AddRange<TList, TEnumerable>(this ObservableCollection<TList> list, IEnumerable<TEnumerable> items) where TEnumerable : TList
{
foreach (var i in items)
{
list.Add(i);
}
}
public static int BinarySearch<T, TValue>(this ObservableCollection<T> collection, int index, int length, TValue value, IComparer<TValue> comparer, Func<T, TValue> selector)
{
comparer = comparer ?? Comparer<TValue>.Default;
var low = index;
var high = (index + length) - 1;
while (low <= high)
{
var mid = low + ((high - low) / 2);
var comp = comparer.Compare(selector(collection[mid]), value);
if (comp == 0)
{
return mid;
}
if (comp < 0)
{
low = mid + 1;
}
else
{
high = mid - 1;
}
}
return ~low;
}
public static int BinarySearch<T, TValue>(this ObservableCollection<T> collection, TValue value, IComparer<TValue> comparer, Func<T, TValue> selector)
{
return collection.BinarySearch(0, collection.Count, value, comparer, selector);
}
public static int BinarySearch<T, TValue>(this ObservableCollection<T> collection, int index, int length, TValue value, Func<TValue, TValue, int> comparison, Func<T, TValue> selector)
{
return collection.BinarySearch(index, length, value, new FuncComparer<TValue>(comparison), selector);
}
public static int BinarySearch<T, TValue>(this ObservableCollection<T> collection, TValue value, Func<TValue, TValue, int> comparison, Func<T, TValue> selector)
{
return collection.BinarySearch(0, collection.Count, value, new FuncComparer<TValue>(comparison), selector);
}
public static int BinarySearch<T, TValue>(this ObservableCollection<T> collection, TValue value, Func<T, TValue> selector)
{
return collection.BinarySearch(0, collection.Count, value, comparer: null, selector: selector);
}
public static int BinarySearch<T>(this ObservableCollection<T> collection, int index, int length, T value, IComparer<T> comparer)
{
return collection.BinarySearch(index, length, value, comparer, x => x);
}
public static int BinarySearch<T>(this ObservableCollection<T> collection, T value, IComparer<T> comparer)
{
return collection.BinarySearch(0, collection.Count, value, comparer, x => x);
}
public static int BinarySearch<T>(this ObservableCollection<T> collection, T value)
{
return collection.BinarySearch(0, collection.Count, value, Comparer<T>.Default, x => x);
}
public static int BinarySearch<T>(this ObservableCollection<T> collection, int index, int length, T value, Func<T, T, int> comparison)
{
return collection.BinarySearch(index, length, value, new FuncComparer<T>(comparison), x => x);
}
public static int BinarySearch<T>(this ObservableCollection<T> collection, T value, Func<T, T, int> comparison)
{
return collection.BinarySearch(0, collection.Count, value, new FuncComparer<T>(comparison), x => x);
}
foreach (var i in items)
{
list.Add(i);
}
}
public static void AddRange<TList, TEnumerable>(this ObservableCollection<TList> list, IEnumerable<TEnumerable> items) where TEnumerable : TList
{
foreach (var i in items)
{
list.Add(i);
}
}
public static int BinarySearch<T, TValue>(this ObservableCollection<T> collection, int index, int length, TValue value, IComparer<TValue> comparer, Func<T, TValue> selector)
{
comparer = comparer ?? Comparer<TValue>.Default;
var low = index;
var high = (index + length) - 1;
while (low <= high)
{
var mid = low + ((high - low) / 2);
var comp = comparer.Compare(selector(collection[mid]), value);
if (comp == 0)
{
return mid;
}
if (comp < 0)
{
low = mid + 1;
}
else
{
high = mid - 1;
}
}
return ~low;
}
public static int BinarySearch<T, TValue>(this ObservableCollection<T> collection, TValue value, IComparer<TValue> comparer, Func<T, TValue> selector)
{
return collection.BinarySearch(0, collection.Count, value, comparer, selector);
}
public static int BinarySearch<T, TValue>(this ObservableCollection<T> collection, int index, int length, TValue value, Func<TValue, TValue, int> comparison, Func<T, TValue> selector)
{
return collection.BinarySearch(index, length, value, new FuncComparer<TValue>(comparison), selector);
}
public static int BinarySearch<T, TValue>(this ObservableCollection<T> collection, TValue value, Func<TValue, TValue, int> comparison, Func<T, TValue> selector)
{
return collection.BinarySearch(0, collection.Count, value, new FuncComparer<TValue>(comparison), selector);
}
public static int BinarySearch<T, TValue>(this ObservableCollection<T> collection, TValue value, Func<T, TValue> selector)
{
return collection.BinarySearch(0, collection.Count, value, comparer: null, selector: selector);
}
public static int BinarySearch<T>(this ObservableCollection<T> collection, int index, int length, T value, IComparer<T> comparer)
{
return collection.BinarySearch(index, length, value, comparer, x => x);
}
public static int BinarySearch<T>(this ObservableCollection<T> collection, T value, IComparer<T> comparer)
{
return collection.BinarySearch(0, collection.Count, value, comparer, x => x);
}
public static int BinarySearch<T>(this ObservableCollection<T> collection, T value)
{
return collection.BinarySearch(0, collection.Count, value, Comparer<T>.Default, x => x);
}
public static int BinarySearch<T>(this ObservableCollection<T> collection, int index, int length, T value, Func<T, T, int> comparison)
{
return collection.BinarySearch(index, length, value, new FuncComparer<T>(comparison), x => x);
}
public static int BinarySearch<T>(this ObservableCollection<T> collection, T value, Func<T, T, int> comparison)
{
return collection.BinarySearch(0, collection.Count, value, new FuncComparer<T>(comparison), x => x);
}
private class FuncComparer<T> : IComparer<T>
{
private readonly Func<T, T, int> _comparison;
public FuncComparer(Func<T, T, int> comparison)
{
_comparison = comparison;
}
public int Compare(T x, T y) => _comparison(x, y);
}
}
}
+23
View File
@@ -0,0 +1,23 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace mscoree
{
[CompilerGenerated]
[Guid("CB2F6722-AB3A-11D2-9C40-00C04FA30A3E")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[TypeIdentifier]
[ComImport]
[CLSCompliant(false)]
public interface ICorRuntimeHost
{
void _VtblGap1_11();
void EnumDomains(out IntPtr enumHandle);
void NextDomain([In] IntPtr enumHandle, [MarshalAs(UnmanagedType.IUnknown)] out object appDomain);
void CloseEnum([In] IntPtr enumHandle);
}
}
-37
View File
@@ -1,37 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Xunit.Runner.Data;
namespace Xunit.Runner.Wpf
{
internal interface ITestUtil
{
/// <summary>
/// Discover the list of test cases which are available in the specified assembly.
/// </summary>
Task Discover(
string assebmlyFileName,
Action<IEnumerable<TestCaseData>> testsDiscovered,
CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Begin a run of all unit tests for the given assembly.
/// </summary>
Task RunAll(
string assemblyFileName,
Action<IEnumerable<TestResultData>> testsFinished,
CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Begin a run of specific unit tests for the given assembly.
/// </summary>
Task RunSpecific(
string assemblyFileName,
ImmutableArray<string> testCasesToRun,
Action<IEnumerable<TestResultData>> testsFinished,
CancellationToken cancellationToken = default(CancellationToken));
}
}
@@ -1,176 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
using Xunit.Runner.Data;
namespace Xunit.Runner.Wpf.Impl
{
internal partial class RemoteTestUtil
{
private sealed class BackgroundWriter<T>
{
private readonly ClientWriter _writer;
private readonly ImmutableArray<T> _data;
private readonly Action<ClientWriter, T> _writeValue;
private readonly CancellationToken _cancellationToken;
internal BackgroundWriter(ClientWriter writer, ImmutableArray<T> data, Action<ClientWriter, T> writeValue, CancellationToken cancellationToken)
{
_writer = writer;
_writeValue = writeValue;
_data = data;
_cancellationToken = cancellationToken;
}
internal Task WriteAsync()
{
return Task.Run(() => GoOnBackground(), _cancellationToken);
}
private void GoOnBackground()
{
foreach (var item in _data)
{
if (_cancellationToken.IsCancellationRequested)
{
break;
}
_writer.Write(TestDataKind.Value);
_writeValue(_writer, item);
}
_writer.Write(TestDataKind.EndOfData);
}
}
/// <summary>
/// Utility for reading a collection of <see cref="{T}"/> values from the given
/// <see cref="ClientReader"/> value.
/// </summary>
/// <typeparam name="T"></typeparam>
private sealed class BackgroundReader<T> where T : class
{
private readonly ConcurrentQueue<T> _queue;
private readonly ClientReader _reader;
private readonly Func<ClientReader, T> _readValue;
internal ClientReader Reader => _reader;
internal BackgroundReader(ConcurrentQueue<T> queue, ClientReader reader, Func<ClientReader, T> readValue)
{
_queue = queue;
_reader = reader;
_readValue = readValue;
}
internal Task ReadAsync(CancellationToken cancellationToken = default(CancellationToken))
{
return Task.Run(() => GoOnBackground(cancellationToken), cancellationToken);
}
/// <summary>
/// This will be called on a background thread to read the results of the test from the
/// named pipe client stream.
/// </summary>
/// <returns></returns>
private void GoOnBackground(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
var kind = _reader.ReadKind();
if (kind != TestDataKind.Value)
{
break;
}
var value = _readValue(_reader);
_queue.Enqueue(value);
}
catch
{
// TODO: Happens when the connection unexpectedly closes on us. Need to surface this
// to the user.
break;
}
}
// Signal we are done
_queue.Enqueue(null);
}
}
private sealed class BackgroundProducer<T> where T : class
{
private const int MaxResultPerTick = 1000;
private readonly Connection _connection;
private readonly ConcurrentQueue<T> _queue;
private readonly DispatcherTimer _timer;
private readonly Action<List<T>> _callback;
private readonly int _maxPerTick;
private readonly TaskCompletionSource<bool> _taskCompletionSource;
internal Task Task => _taskCompletionSource.Task;
internal BackgroundProducer(
Connection connection,
Dispatcher dispatcher,
ConcurrentQueue<T> queue,
Action<List<T>> callback,
int maxResultPerTick = MaxResultPerTick,
TimeSpan? interval = null)
{
_connection = connection;
_queue = queue;
_maxPerTick = maxResultPerTick;
_callback = callback;
_timer = new DispatcherTimer(
interval ?? TimeSpan.FromMilliseconds(500),
DispatcherPriority.Normal,
OnTimerTick,
dispatcher);
_taskCompletionSource = new TaskCompletionSource<bool>();
}
private void OnTimerTick(object sender, EventArgs e)
{
var i = 0;
var list = new List<T>();
var isDone = false;
T value;
while (i < _maxPerTick && _queue.TryDequeue(out value))
{
if (value == null)
{
isDone = true;
break;
}
list.Add(value);
}
_callback(list);
if (isDone)
{
try
{
_timer.Stop();
_connection.Dispose();
}
finally
{
_taskCompletionSource.SetResult(true);
}
}
}
}
}
}
@@ -1,51 +0,0 @@
using System;
using System.IO.Pipes;
using Xunit.Runner.Data;
namespace Xunit.Runner.Wpf.Impl
{
internal sealed partial class RemoteTestUtil : ITestUtil
{
private sealed class Connection : IDisposable
{
private NamedPipeClientStream _stream;
private ClientReader _reader;
internal NamedPipeClientStream Stream => _stream;
internal ClientReader Reader => _reader;
internal Connection(NamedPipeClientStream stream)
{
_stream = stream;
_reader = new ClientReader(stream);
}
internal void Dispose()
{
if (_stream == null)
{
return;
}
try
{
_stream.WriteAsync(new byte[] { 0 }, 0, 1);
}
catch
{
// Signal to server we are done with the connection. Okay to fail because
// it means the server isn't listening anymore.
}
_stream.Close();
_stream = null;
}
void IDisposable.Dispose()
{
Dispose();
}
}
}
}
-153
View File
@@ -1,153 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO.Pipes;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
using Xunit.Runner.Data;
namespace Xunit.Runner.Wpf.Impl
{
internal sealed partial class RemoteTestUtil : ITestUtil
{
private struct ProcessInfo
{
internal readonly string PipeName;
internal readonly Process Process;
internal ProcessInfo(string pipeName, Process process)
{
PipeName = pipeName;
Process = process;
}
}
private readonly Dispatcher _dispatcher;
private ProcessInfo? _processInfo;
internal RemoteTestUtil(Dispatcher dispatcher)
{
_dispatcher = dispatcher;
_processInfo = StartWorkerProcess();
}
private async Task<Connection> CreateConnection(string action, string argument, CancellationToken cancellationToken)
{
var pipeName = GetPipeName();
try
{
var stream = new NamedPipeClientStream(pipeName);
await stream.ConnectAsync(cancellationToken);
var writer = new ClientWriter(stream);
writer.Write(action);
writer.Write(argument);
return new Connection(stream);
}
catch
{
try
{
_processInfo?.Process.Kill();
}
catch
{
// Inherent race condition here. Just need to make sure the process is
// dead as it can't even handle new connections.
}
throw;
}
}
private string GetPipeName()
{
var process = _processInfo?.Process;
if (process != null && !process.HasExited)
{
return _processInfo.Value.PipeName;
}
_processInfo = StartWorkerProcess();
return _processInfo.Value.PipeName;
}
private static ProcessInfo StartWorkerProcess()
{
var pipeName = $"xunit.runner.wpf.pipe.{Guid.NewGuid()}";
var processStartInfo = new ProcessStartInfo();
processStartInfo.FileName = typeof(Xunit.Runner.Worker.Program).Assembly.Location;
processStartInfo.Arguments = $"{pipeName} {Process.GetCurrentProcess().Id}";
processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
var process = Process.Start(processStartInfo);
return new ProcessInfo(pipeName, process);
}
private void RecycleProcess()
{
var process = _processInfo?.Process;
if (process != null && !process.HasExited)
{
process.Kill();
}
_processInfo = StartWorkerProcess();
}
private async Task Discover(string assemblyPath, Action<List<TestCaseData>> callback, CancellationToken cancellationToken)
{
var connection = await CreateConnection(Constants.ActionDiscover, assemblyPath, cancellationToken);
await ProcessResultsCore(connection, r => r.ReadTestCaseData(), callback, cancellationToken);
RecycleProcess();
}
private async Task RunCore(string actionName, string assemblyPath, ImmutableArray<string> testCaseDisplayNames, Action<List<TestResultData>> callback, CancellationToken cancellationToken)
{
var connection = await CreateConnection(actionName, assemblyPath, cancellationToken);
if (!testCaseDisplayNames.IsDefaultOrEmpty)
{
var backgroundWriter = new BackgroundWriter<string>(new ClientWriter(connection.Stream), testCaseDisplayNames, (w, s) => w.Write(s), cancellationToken);
await backgroundWriter.WriteAsync();
}
await ProcessResultsCore(connection, r => r.ReadTestResultData(), callback, cancellationToken);
}
private async Task ProcessResultsCore<T>(Connection connection, Func<ClientReader, T> readValue, Action<List<T>> callback, CancellationToken cancellationToken)
where T : class
{
var queue = new ConcurrentQueue<T>();
var backgroundReader = new BackgroundReader<T>(queue, new ClientReader(connection.Stream), readValue);
var backgroundProducer = new BackgroundProducer<T>(connection, _dispatcher, queue, callback);
await backgroundReader.ReadAsync(cancellationToken);
await backgroundProducer.Task;
}
#region ITestUtil
Task ITestUtil.Discover(string assemblyFileName, Action<IEnumerable<TestCaseData>> testsDiscovered, CancellationToken cancellationToken)
{
return Discover(assemblyFileName, testsDiscovered, cancellationToken);
}
Task ITestUtil.RunAll(string assemblyFileName, Action<IEnumerable<TestResultData>> testsFinished, CancellationToken cancellationToken)
{
return RunCore(Constants.ActionRunAll, assemblyFileName, ImmutableArray<string>.Empty, testsFinished, cancellationToken);
}
Task ITestUtil.RunSpecific(string assemblyFileName, ImmutableArray<string> testCases, Action<IEnumerable<TestResultData>> testsFinished, CancellationToken cancellationToken)
{
return RunCore(Constants.ActionRunSpecific, assemblyFileName, testCases, testsFinished, cancellationToken);
}
#endregion
}
}
+263 -276
View File
@@ -1,375 +1,362 @@
<Window
x:Class="Xunit.Runner.Wpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Platform"
xmlns:converters="clr-namespace:Xunit.Runner.Wpf.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:local="clr-namespace:Xunit.Runner.Wpf"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:vm="clr-namespace:Xunit.Runner.Wpf.ViewModel"
Name="Main"
Title="xUnit.net Test Runner"
Width="525"
Height="600"
MinWidth="425"
MinHeight="525"
DataContext="{Binding Main, Source={StaticResource Locator}}"
Icon="Artwork\Application.ico"
ResizeMode="CanResizeWithGrip"
mc:Ignorable="d">
<Window x:Class="Xunit.Runner.Wpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Platform"
xmlns:converters="clr-namespace:Xunit.Runner.Wpf.Converters"
xmlns:local="clr-namespace:Xunit.Runner.Wpf"
xmlns:vm="clr-namespace:Xunit.Runner.Wpf.ViewModel"
mc:Ignorable="d"
Title="MainWindow" SizeToContent="Height" Width="800">
<!--<Grid>
-->
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<cmd:EventToCommand Command="{Binding WindowLoadedCommand}" />
</i:EventTrigger>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<cmd:EventToCommand Command="{Binding WindowLoadedCommand}" />
</i:EventTrigger>
<i:EventTrigger EventName="Closing">
<cmd:EventToCommand Command="{Binding WindowClosingCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<cmd:EventToCommand Command="{Binding WindowClosingCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Window.Resources>
<converters:TestStateConverter x:Key="TestStateConverter" />
</Window.Resources>
<Window.Resources>
<converters:TestStateConverter x:Key="TestStateConverter" />
</Window.Resources>
<Grid local:CommandBindings.Registration="{Binding CommandBindings}">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid local:CommandBindings.Registration="{Binding CommandBindings}">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Menu Grid.Row="0">
<MenuItem Header="_File">
<MenuItem Command="{Binding ExitCommand}" Header="E_xit" />
</MenuItem>
<MenuItem Header="_Assembly">
<MenuItem Command="ApplicationCommands.Open" Header="_Open" />
<MenuItem Header="R_ecent" ItemsSource="{Binding RecentAssemblies}">
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding FilePath}" />
<Setter Property="Command" Value="{Binding Command}" />
<Setter Property="CommandParameter" Value="{Binding}" />
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
<Separator />
<MenuItem Command="{Binding AssemblyRemoveAllCommand}" Header="_Unload" />
<MenuItem Command="{Binding AssemblyReloadAllCommand}" Header="_Reload" />
<Separator />
<MenuItem
<Menu Grid.Row="0">
<MenuItem Header="_File">
<MenuItem Command="{Binding ExitCommand}" Header="E_xit" />
</MenuItem>
<MenuItem Header="_Assembly">
<MenuItem Command="ApplicationCommands.Open" Header="_Open" />
<MenuItem Header="R_ecent" ItemsSource="{Binding RecentAssemblies}">
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding FilePath}" />
<Setter Property="Command" Value="{Binding Command}" />
<Setter Property="CommandParameter" Value="{Binding}" />
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
<Separator />
<MenuItem Command="{Binding AssemblyRemoveAllCommand}" Header="_Unload" />
<MenuItem Command="{Binding AssemblyReloadAllCommand}" Header="_Reload" />
<Separator />
<MenuItem
Command="{Binding AutoReloadAssembliesCommand}"
Header="_Auto Reload Test Assemblies"
IsCheckable="True"
IsChecked="{Binding AutoReloadAssemblies}" />
</MenuItem>
<MenuItem Header="_Project">
<MenuItem Header="_Open" />
<MenuItem Header="_Recent" />
<Separator />
<MenuItem Header="_Close" />
<Separator />
<MenuItem Header="_Save" />
<MenuItem Header="Save _As..." />
</MenuItem>
</Menu>
</MenuItem>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="200px" />
<ColumnDefinition Width="2*" MinWidth="200px" />
</Grid.ColumnDefinitions>
</Menu>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="200px" />
<ColumnDefinition Width="2*" MinWidth="200px" />
</Grid.ColumnDefinitions>
<GroupBox
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<GroupBox
Grid.Row="0"
Grid.Column="0"
Margin="3"
Header="Refinements">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="Search:" />
<TextBox Grid.Row="1" Text="{Binding FilterString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Label Grid.Row="0" Content="Search:" />
<TextBox Grid.Row="1" Text="{Binding FilterString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<Label Grid.Row="2" Content="Assemblies:" />
<ListBox
<Label Grid.Row="2" Content="Assemblies:" />
<ListBox
Grid.Row="3"
Height="175"
ItemsSource="{Binding Assemblies}"
SelectionMode="Extended">
<ListBox.ItemTemplate>
<DataTemplate DataType="vm:TestAssemblyViewModel">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding DisplayName}" />
<ListBox.ItemTemplate>
<DataTemplate DataType="vm:TestAssemblyViewModel">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding DisplayName}" />
<TextBlock
<TextBlock
FontStyle="Italic"
Foreground="Gray"
Text=" Discovering tests...">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding State}" Value="{x:Static vm:AssemblyState.Loading}">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding State}" Value="{x:Static vm:AssemblyState.Loading}">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Command="{Binding AssemblyReloadCommand}" Header="Reload" />
<MenuItem Command="{Binding AssemblyReloadAllCommand}" Header="Reload All" />
<Separator />
<MenuItem Command="{Binding AssemblyRemoveCommand}" Header="Remove" />
<MenuItem Command="{Binding AssemblyRemoveAllCommand}" Header="Remove All" />
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Command="{Binding AssemblyReloadCommand}" Header="Reload" />
<MenuItem Command="{Binding AssemblyReloadAllCommand}" Header="Reload All" />
<Separator />
<MenuItem Command="{Binding AssemblyRemoveCommand}" Header="Remove" />
<MenuItem Command="{Binding AssemblyRemoveAllCommand}" Header="Remove All" />
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
<Label Grid.Row="4" Content="Traits:" />
<Label Grid.Row="4" Content="Traits:" />
<TreeView Grid.Row="5" ItemsSource="{Binding Traits}">
<TreeView Grid.Row="5" ItemsSource="{Binding Traits}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type vm:TraitViewModel}" ItemsSource="{Binding Children}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type vm:TraitViewModel}" ItemsSource="{Binding Children}">
<CheckBox Content="{Binding Text}" IsChecked="{Binding IsChecked}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<cmd:EventToCommand Command="{Binding DataContext.TraitCheckedChangedCommand, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding}" />
</i:EventTrigger>
<CheckBox Content="{Binding Text}" IsChecked="{Binding IsChecked}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<cmd:EventToCommand Command="{Binding DataContext.TraitCheckedChangedCommand, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding}" />
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<cmd:EventToCommand Command="{Binding DataContext.TraitCheckedChangedCommand, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
<i:EventTrigger EventName="Unchecked">
<cmd:EventToCommand Command="{Binding DataContext.TraitCheckedChangedCommand, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
</HierarchicalDataTemplate>
</TreeView.Resources>
</HierarchicalDataTemplate>
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding IsExpanded}" />
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding IsExpanded}" />
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ContextMenu>
<ContextMenu>
<MenuItem Command="{Binding TraitsClearCommand}" Header="Clear" />
</ContextMenu>
</TreeView.ContextMenu>
<TreeView.ContextMenu>
<ContextMenu>
<MenuItem Command="{Binding TraitsClearCommand}" Header="Clear" />
</ContextMenu>
</TreeView.ContextMenu>
</TreeView>
</Grid>
</GroupBox>
</TreeView>
</Grid>
</GroupBox>
<Grid Grid.Row="1" Grid.Column="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Row="1" Grid.Column="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button
<Button
Grid.Column="0"
Margin="10,0,0,0"
Command="{Binding RunAllCommand}"
Content="_Run All" />
<Button
<Button
Grid.Column="1"
Command="{Binding RunSelectedCommand}"
Content="Run _Selected" />
<Button
<Button
Grid.Column="2"
Margin="0,0,10,0"
Command="{Binding CancelCommand}"
Content="_Cancel" />
</Grid>
</Grid>
<Grid Grid.Row="0" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="*" MinHeight="200px" />
<RowDefinition Height="auto" />
<RowDefinition Height="*" MinHeight="200px" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="*" MinHeight="200px" />
<RowDefinition Height="auto" />
<RowDefinition Height="*" MinHeight="200px" />
</Grid.RowDefinitions>
<GroupBox
<GroupBox
Grid.Row="0"
Margin="3"
Header="{Binding TestCasesCaption}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="55*"/>
<ColumnDefinition Width="244*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<ToggleButton
<StackPanel Orientation="Horizontal" Grid.ColumnSpan="2">
<ToggleButton
Grid.Column="0"
Margin="0,4,2,4"
Background="Transparent"
BorderThickness="0"
Command="{Binding TestFilterChanged}"
IsChecked="{Binding FilterPassedTests}">
<StackPanel Orientation="Horizontal">
<Image Source="Artwork\Passed_large.png" />
<TextBlock
<StackPanel Orientation="Horizontal">
<Image Source="Artwork\Passed_large.png" />
<TextBlock
Margin="4,0"
VerticalAlignment="Center"
FontSize="16"
Text="{Binding TestsPassed, StringFormat={}{0:#\,0}}" />
</StackPanel>
</ToggleButton>
</StackPanel>
</ToggleButton>
<ToggleButton
<ToggleButton
Grid.Column="1"
Margin="2,4"
Background="Transparent"
BorderThickness="0"
Command="{Binding TestFilterChanged}"
IsChecked="{Binding FilterFailedTests}">
<StackPanel Orientation="Horizontal">
<Image Source="Artwork\Failed_large.png" />
<TextBlock
<StackPanel Orientation="Horizontal">
<Image Source="Artwork\Failed_large.png" />
<TextBlock
Margin="4,0"
VerticalAlignment="Center"
FontSize="16"
Text="{Binding TestsFailed, StringFormat={}{0:#\,0}}" />
</StackPanel>
</ToggleButton>
</StackPanel>
</ToggleButton>
<ToggleButton
<ToggleButton
Grid.Column="2"
Margin="2,4,0,4"
Background="Transparent"
BorderThickness="0"
Command="{Binding TestFilterChanged}"
IsChecked="{Binding FilterSkippedTests}">
<StackPanel Orientation="Horizontal">
<Image Source="Artwork\Skipped_large.png" />
<TextBlock
<StackPanel Orientation="Horizontal">
<Image Source="Artwork\Skipped_large.png" />
<TextBlock
Margin="4,0"
VerticalAlignment="Center"
FontSize="16"
Text="{Binding TestsSkipped, StringFormat={}{0:#\,0}}" />
</StackPanel>
</ToggleButton>
</StackPanel>
</ToggleButton>
<ToggleButton
<ToggleButton
Grid.Column="2"
Margin="2,4,0,4"
Background="Transparent"
BorderThickness="0"
Command="{Binding TestFilterChanged}"
IsChecked="{Binding FilterRunningTests}">
<StackPanel Orientation="Horizontal">
<Image Source="Artwork\Running_large.png" />
<TextBlock
<StackPanel Orientation="Horizontal">
<Image Source="Artwork\Running_large.png" />
<TextBlock
Margin="4,0"
VerticalAlignment="Center"
FontSize="16"
Text="{Binding TestsRunning, StringFormat={}{0:#\,0}}" />
</StackPanel>
</ToggleButton>
</StackPanel>
</StackPanel>
</ToggleButton>
</StackPanel>
<ListBox
<ListBox
x:Name="TestCases"
Grid.Row="1"
ItemsSource="{Binding FilteredTestCases}"
SelectedItem="{Binding SelectedTestCase, Mode=TwoWay}"
SelectionChanged="TestCases_SelectionChanged"
SelectionMode="Extended">
<ListBox.ItemTemplate>
<DataTemplate DataType="vm:TestCaseViewModel">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
SelectionMode="Extended" Grid.ColumnSpan="2">
<ListBox.ItemTemplate>
<DataTemplate DataType="vm:TestCaseViewModel">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image
<Image
Grid.Column="0"
Width="16"
Margin="0,0,2,0"
Source="{Binding Path=State, Mode=OneWay, Converter={StaticResource TestStateConverter}}" />
<TextBlock
<TextBlock
Grid.Column="1"
VerticalAlignment="Center"
Text="{Binding DisplayName}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding RunSelectedCommand}" />
</ListBox.InputBindings>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<cmd:EventToCommand Command="{Binding Path=RunSelectedCommand}" PassEventArgsToCommand="False" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
</Grid>
</GroupBox>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding RunSelectedCommand}" />
</ListBox.InputBindings>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<cmd:EventToCommand Command="{Binding Path=RunSelectedCommand}" PassEventArgsToCommand="False" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
</Grid>
</GroupBox>
<GridSplitter
<GridSplitter
Grid.Row="1"
Height="3"
HorizontalAlignment="Stretch"
Background="White" />
<GroupBox
<GroupBox
Grid.Row="2"
Margin="3"
Header="Output">
<TextBox
<TextBox
FontFamily="Consolas"
HorizontalScrollBarVisibility="Auto"
IsReadOnly="True"
Text="{Binding Output}"
Text="{Binding SelectedTestCase.Output}"
VerticalScrollBarVisibility="Visible" />
</GroupBox>
</Grid>
</GroupBox>
</Grid>
<GridSplitter
<GridSplitter
Grid.Column="0"
Width="3"
VerticalAlignment="Stretch"
Background="White" />
<ProgressBar
<ProgressBar
Grid.Row="1"
Grid.Column="1"
Margin="3"
@@ -377,52 +364,52 @@
Maximum="{Binding MaximumProgress}"
Minimum="0"
Value="{Binding Path=TestsCompleted}" />
</Grid>
</Grid>
<StackPanel Grid.Row="2">
<Border
<StackPanel Grid.Row="2">
<Border
Margin="3"
BorderBrush="LightGray"
BorderThickness="1" />
<StatusBar>
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="16" />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBar>
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="16" />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem Grid.Column="1">
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="DarkGreen" Text="Tests passed: " />
<StatusBarItem Grid.Column="1">
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="DarkGreen" Text="Tests passed: " />
<TextBlock Text="{Binding TestsPassed, StringFormat={}{0:#\,0}}" />
</StackPanel>
</StatusBarItem>
<TextBlock Text="{Binding TestsPassed, StringFormat={}{0:#\,0}}" />
</StackPanel>
</StatusBarItem>
<StatusBarItem Grid.Column="2">
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="DarkRed" Text="Tests failed: " />
<StatusBarItem Grid.Column="2">
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="DarkRed" Text="Tests failed: " />
<TextBlock Text="{Binding TestsFailed, StringFormat={}{0:#\,0}}" />
</StackPanel>
</StatusBarItem>
<TextBlock Text="{Binding TestsFailed, StringFormat={}{0:#\,0}}" />
</StackPanel>
</StatusBarItem>
<StatusBarItem Grid.Column="3">
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="DarkGoldenrod" Text="Tests skipped: " />
<StatusBarItem Grid.Column="3">
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="DarkGoldenrod" Text="Tests skipped: " />
<TextBlock Text="{Binding TestsSkipped, StringFormat={}{0:#\,0}}" />
</StackPanel>
</StatusBarItem>
</StatusBar>
</StackPanel>
</Grid>
<TextBlock Text="{Binding TestsSkipped, StringFormat={}{0:#\,0}}" />
</StackPanel>
</StatusBarItem>
</StatusBar>
</StackPanel>
</Grid>
</Window>
+51 -47
View File
@@ -1,56 +1,60 @@
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using Xunit.Runner.Wpf.Persistence;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Xunit.Runner.Wpf.ViewModel;
namespace Xunit.Runner.Wpf
{
using ViewModel;
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public partial class MainWindow : Window
public MainWindow()
{
public static Window Instance { get; private set; }
public MainWindow()
{
Instance = this;
InitializeComponent();
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
Storage.RestoreWindowLayout(this);
}
protected override void OnClosing(CancelEventArgs e)
{
Storage.SaveWindowLayout(this);
base.OnClosing(e);
}
private void TestCases_SelectionChanged(Object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
foreach (var item in e.AddedItems)
{
var model = item as TestCaseViewModel;
if (model != null)
{
model.IsSelected = true;
}
}
foreach (var item in e.RemovedItems)
{
var model = item as TestCaseViewModel;
if (model != null)
{
model.IsSelected = false;
}
}
}
//in case it's loaded by an external application
this.DataContext = new ViewModelLocator().Main;
InitializeComponent();
}
private void TestCases_SelectionChanged(Object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
foreach (var item in e.AddedItems)
{
var model = item as TestCaseViewModel;
if (model != null)
{
model.IsSelected = true;
}
}
foreach (var item in e.RemovedItems)
{
var model = item as TestCaseViewModel;
if (model != null)
{
model.IsSelected = false;
}
}
}
}
}
+1 -1
View File
@@ -14,7 +14,7 @@ namespace Xunit.Runner.Wpf.Persistence
private static string GetWindowLayoutFileName(Window window) => $"{window.Name}_{WindowLayoutFileName}";
private static IsolatedStorageFile GetStorageFile() => IsolatedStorageFile.GetUserStoreForDomain();
private static IsolatedStorageFile GetStorageFile() => IsolatedStorageFile.GetUserStoreForAssembly();
public static XmlTextReader OpenXmlFile(string fileName)
{
+11 -11
View File
@@ -4,24 +4,24 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("xunit.runner.wpf")]
[assembly: AssemblyTitle("Xunit.Runner.Wpf")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("xunit.runner.wpf")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyProduct("Xunit.Runner.Wpf")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
@@ -33,10 +33,10 @@ using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
@@ -44,11 +44,11 @@ using System.Windows;
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
+1 -1
View File
@@ -19,7 +19,7 @@ namespace Xunit.Runner.Wpf.Properties {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
+26
View File
@@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Xunit.Runner.Wpf.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.5.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}
@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
+21
View File
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit.Abstractions;
namespace Xunit.Runner.Wpf
{
public class TestDiscoveryInfo
{
public IEnumerable<ITestCase> Cases { get; set; }
public string AssemblyFileName { get; set; }
public TestDiscoveryInfo(IEnumerable<ITestCase> cases, string assemblyFileName)
{
Cases = cases;
AssemblyFileName = assemblyFileName;
}
}
}
+18
View File
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Xunit.Runner.Wpf
{
public enum TestState
{
All = 0,
NotRun = 1,
Running = 2,
Passed = 3,
Skipped = 4,
Failed = 5
}
}
+45
View File
@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace Xunit.Runner.Wpf
{
public class Tests
{
[Fact]
//[Trait("TraitName1", "TraitValue1")]
public void Pass()
{
Thread.Sleep(TimeSpan.FromSeconds(1));
}
[Fact]
public void Pass2()
{
Thread.Sleep(TimeSpan.FromSeconds(3));
}
[Fact]
public void Pass3()
{
Thread.Sleep(TimeSpan.FromSeconds(3));
}
[Fact]
//[Trait("TraitName1", "TraitValue2")]
public void Fail()
{
Thread.Sleep(TimeSpan.FromSeconds(1));
Assert.True(false);
}
[Fact(Skip = "Testing")]
//[Trait("TraitName2", "TraitValue2")]
public void Skip()
{
Thread.Sleep(TimeSpan.FromSeconds(1));
}
}
}
File diff suppressed because it is too large Load Diff
+58 -32
View File
@@ -1,41 +1,67 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using GalaSoft.MvvmLight;
using Xunit.Runner.Data;
using Xunit.Abstractions;
using Xunit.Runner.Wpf;
namespace Xunit.Runner.Wpf.ViewModel
{
public class TestCaseViewModel : ViewModelBase
public class TestCaseViewModel : ViewModelBase
{
private TestState _state = TestState.NotRun;
private string _output = "";
private string _execTime = "";
public string DisplayName { get; }
public string UniqueID { get; }
public string SkipReason { get; }
public string AssemblyFileName { get; }
public string AssemblyPath { get; }
public ImmutableArray<TraitViewModel> Traits { get; }
public bool IsSelected { get; set; }
public bool HasSkipReason => !string.IsNullOrEmpty(this.SkipReason);
public ITestCase TestCase { get; }
public TestState State
{
private TestState _state = TestState.NotRun;
public string DisplayName { get; }
public string UniqueID { get; }
public string SkipReason { get; }
public string AssemblyFileName { get; }
public ImmutableArray<TraitViewModel> Traits { get; }
public bool IsSelected { get; set; }
public bool HasSkipReason => !string.IsNullOrEmpty(this.SkipReason);
public TestState State
{
get { return _state; }
set { Set(ref _state, value); }
}
public TestCaseViewModel(string displayName, string uniqueID, string skipReason, string assemblyFileName, IEnumerable<TraitViewModel> traits)
{
this.DisplayName = displayName;
this.UniqueID = uniqueID;
this.SkipReason = skipReason;
this.AssemblyFileName = assemblyFileName;
this.Traits = traits.ToImmutableArray();
if (!string.IsNullOrEmpty(skipReason))
{
_state = TestState.Skipped;
}
}
get { return _state; }
set { Set(ref _state, value); }
}
public string ExecutionTime
{
get { return _execTime; }
set
{
Set(ref _execTime, value);
}
}
public string Output
{
get { return _output; }
set
{
Set(ref _output, value);
}
}
public TestCaseViewModel(string displayName, string uniqueID, string skipReason, string assemblyFileName, string assemblyPath, ITestCase testCase, IEnumerable<TraitViewModel> traits)
{
this.DisplayName = displayName;
this.UniqueID = uniqueID;
this.SkipReason = skipReason;
this.AssemblyFileName = assemblyFileName;
this.AssemblyPath = assemblyPath;
this.TestCase = testCase;
this.Traits = traits.ToImmutableArray();
if (!string.IsNullOrEmpty(skipReason))
{
_state = TestState.Skipped;
}
}
}
}
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using GalaSoft.MvvmLight;
using Xunit.Runner.Wpf;
namespace Xunit.Runner.Wpf.ViewModel
{
+10 -4
View File
@@ -1,7 +1,7 @@
/*
In App.xaml:
<Application.Resources>
<vm:ViewModelLocator xmlns:vm="clr-namespace:xunit.runner.wpf"
<vm:ViewModelLocator xmlns:vm="clr-namespace:Xunit.Runner.Wpf"
x:Key="Locator" />
</Application.Resources>
@@ -12,8 +12,9 @@
See http://www.galasoft.ch/mvvm
*/
using CommonServiceLocator;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;
namespace Xunit.Runner.Wpf.ViewModel
{
@@ -45,8 +46,13 @@ namespace Xunit.Runner.Wpf.ViewModel
}
public MainViewModel Main
=> ServiceLocator.Current.GetInstance<MainViewModel>();
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
public static void Cleanup()
{
// TODO Clear the ViewModels
+111
View File
@@ -0,0 +1,111 @@
#if NETSTANDARD
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Xunit.Sdk
{
class XunitWorkerThread : IDisposable
{
readonly ManualResetEvent finished = new ManualResetEvent(false);
static readonly TaskFactory taskFactory = new TaskFactory();
public XunitWorkerThread(Action threadProc)
{
QueueUserWorkItem(threadProc, finished);
}
public void Dispose()
{
finished.Dispose();
}
public void Join()
{
finished.WaitOne();
}
public static void QueueUserWorkItem(Action backgroundTask, EventWaitHandle finished = null)
{
taskFactory.StartNew(_ =>
{
var state = (State)_;
try
{
state.BackgroundTask();
}
finally
{
if (state.Finished != null)
state.Finished.Set();
}
},
new State { BackgroundTask = backgroundTask, Finished = finished },
CancellationToken.None,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
}
class State
{
public Action BackgroundTask;
public EventWaitHandle Finished;
}
}
}
#else
using System;
using System.Threading;
namespace Xunit.Sdk
{
class XunitWorkerThread : IDisposable
{
readonly Thread thread;
public XunitWorkerThread(Action threadProc)
{
thread = new Thread(s => ((Action)s)()) { IsBackground = true };
thread.Start(threadProc);
}
public void Dispose() { }
public void Join()
{
if (thread != Thread.CurrentThread)
thread.Join();
}
public static void QueueUserWorkItem(Action backgroundTask, EventWaitHandle finished = null)
{
ThreadPool.QueueUserWorkItem(_ =>
{
var state = (State)_;
try
{
state.BackgroundTask();
}
finally
{
if (state.Finished != null)
state.Finished.Set();
}
},
new State { BackgroundTask = backgroundTask, Finished = finished });
}
class State
{
public Action BackgroundTask;
public EventWaitHandle Finished;
}
}
}
#endif
+18 -18
View File
@@ -1,21 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="CommonServiceLocator" version="1.3" targetFramework="net452" />
<package id="MvvmLight" version="5.3.0.0" targetFramework="net46" />
<package id="MvvmLightLibs" version="5.3.0.0" targetFramework="net46" />
<package id="NuGet.CommandLine" version="2.8.3" targetFramework="net46" />
<package id="System.Collections" version="4.3.0" targetFramework="net46" />
<package id="System.Collections.Immutable" version="1.4.0-preview1-25305-02" targetFramework="net46" />
<package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net46" />
<package id="System.Globalization" version="4.3.0" targetFramework="net46" />
<package id="System.Linq" version="4.3.0" targetFramework="net46" />
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net46" />
<package id="System.Runtime" version="4.3.0" targetFramework="net46" />
<package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net46" />
<package id="System.Threading" version="4.3.0" targetFramework="net46" />
<package id="Tvl.NuGet.BuildTasks" version="1.0.0-alpha002" targetFramework="net46" developmentDependency="true" />
<package id="WindowsAPICodePack-Core" version="1.1.2" targetFramework="net46" />
<package id="WindowsAPICodePack-Shell" version="1.1.1" targetFramework="net46" />
<package id="xunit.abstractions" version="2.0.0" targetFramework="net452" />
<package id="xunit.runner.utility" version="2.1.0" targetFramework="net46" />
<package id="CommonServiceLocator" version="2.0.2" targetFramework="net48" />
<package id="MvvmLight" version="5.4.1.1" targetFramework="net48" />
<package id="MvvmLightLibs" version="5.4.1.1" targetFramework="net48" />
<package id="System.Buffers" version="4.5.1" targetFramework="net48" />
<package id="System.Collections.Immutable" version="1.7.1" targetFramework="net48" />
<package id="System.Memory" version="4.5.4" targetFramework="net48" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.3" targetFramework="net48" />
<package id="WindowsAPICodePack-Core" version="1.1.1" targetFramework="net48" />
<package id="WindowsAPICodePack-Shell" version="1.1.1" targetFramework="net48" />
<package id="xunit" version="2.4.1" targetFramework="net48" />
<package id="xunit.abstractions" version="2.0.3" targetFramework="net48" />
<package id="xunit.analyzers" version="0.10.0" targetFramework="net48" />
<package id="xunit.assert" version="2.4.1" targetFramework="net48" />
<package id="xunit.core" version="2.4.1" targetFramework="net48" />
<package id="xunit.extensibility.core" version="2.4.1" targetFramework="net48" />
<package id="xunit.extensibility.execution" version="2.4.1" targetFramework="net48" />
<package id="xunit.runner.utility" version="2.4.1" targetFramework="net48" />
</packages>
+77 -79
View File
@@ -1,25 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Tvl.NuGet.BuildTasks.1.0.0-alpha002\build\Tvl.NuGet.BuildTasks.props" Condition="Exists('..\packages\Tvl.NuGet.BuildTasks.1.0.0-alpha002\build\Tvl.NuGet.BuildTasks.props')" />
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\xunit.core.2.4.1\build\xunit.core.props" Condition="Exists('..\packages\xunit.core.2.4.1\build\xunit.core.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{34FB519C-FB49-4B31-ACA2-7F7879311BCF}</ProjectGuid>
<ProjectGuid>{4120F4AC-1B24-4B7C-86A9-0A3C75E526CD}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Xunit.Runner.Wpf</RootNamespace>
<AssemblyName>xunit.runner.wpf</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<TargetFrameworkProfile />
<NuPkgVersion Condition="'$(appveyor_build_version)' != ''">$(appveyor_build_version)</NuPkgVersion>
<NuPkgVersion Condition="'$(NuPkgVersion)' == ''">1.0.0-local</NuPkgVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@@ -40,43 +37,45 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Artwork\Application.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="GalaSoft.MvvmLight, Version=5.3.0.19026, Culture=neutral, PublicKeyToken=e7570ab207bcb616, processorArchitecture=MSIL">
<HintPath>..\packages\MvvmLightLibs.5.3.0.0\lib\net45\GalaSoft.MvvmLight.dll</HintPath>
<Private>True</Private>
<Reference Include="CommonServiceLocator, Version=2.0.2.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0, processorArchitecture=MSIL">
<HintPath>..\packages\CommonServiceLocator.2.0.2\lib\net47\CommonServiceLocator.dll</HintPath>
</Reference>
<Reference Include="GalaSoft.MvvmLight.Extras, Version=5.3.0.19032, Culture=neutral, PublicKeyToken=669f0b5e8f868abf, processorArchitecture=MSIL">
<HintPath>..\packages\MvvmLightLibs.5.3.0.0\lib\net45\GalaSoft.MvvmLight.Extras.dll</HintPath>
<Private>True</Private>
<Reference Include="GalaSoft.MvvmLight, Version=5.4.1.0, Culture=neutral, PublicKeyToken=e7570ab207bcb616, processorArchitecture=MSIL">
<HintPath>..\packages\MvvmLightLibs.5.4.1.1\lib\net45\GalaSoft.MvvmLight.dll</HintPath>
</Reference>
<Reference Include="GalaSoft.MvvmLight.Platform, Version=5.3.0.19032, Culture=neutral, PublicKeyToken=5f873c45e98af8a1, processorArchitecture=MSIL">
<HintPath>..\packages\MvvmLightLibs.5.3.0.0\lib\net45\GalaSoft.MvvmLight.Platform.dll</HintPath>
<Private>True</Private>
<Reference Include="GalaSoft.MvvmLight.Extras, Version=5.4.1.0, Culture=neutral, PublicKeyToken=669f0b5e8f868abf, processorArchitecture=MSIL">
<HintPath>..\packages\MvvmLightLibs.5.4.1.1\lib\net45\GalaSoft.MvvmLight.Extras.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Practices.ServiceLocation, Version=1.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll</HintPath>
<Private>True</Private>
<Reference Include="GalaSoft.MvvmLight.Platform, Version=5.4.1.0, Culture=neutral, PublicKeyToken=5f873c45e98af8a1, processorArchitecture=MSIL">
<HintPath>..\packages\MvvmLightLibs.5.4.1.1\lib\net45\GalaSoft.MvvmLight.Platform.dll</HintPath>
</Reference>
<Reference Include="Microsoft.WindowsAPICodePack, Version=1.1.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\WindowsAPICodePack-Core.1.1.2\lib\Microsoft.WindowsAPICodePack.dll</HintPath>
<Private>True</Private>
<Reference Include="Microsoft.WindowsAPICodePack, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\WindowsAPICodePack-Core.1.1.1\lib\Microsoft.WindowsAPICodePack.dll</HintPath>
</Reference>
<Reference Include="Microsoft.WindowsAPICodePack.Shell, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\WindowsAPICodePack-Shell.1.1.1\lib\Microsoft.WindowsAPICodePack.Shell.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Collections.Immutable, Version=1.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Collections.Immutable.1.4.0-preview1-25305-02\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.Collections.Immutable, Version=1.2.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Collections.Immutable.1.7.1\lib\net461\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Data" />
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\MvvmLightLibs.5.3.0.0\lib\net45\System.Windows.Interactivity.dll</HintPath>
<Private>True</Private>
<HintPath>..\packages\MvvmLightLibs.5.4.1.1\lib\net45\System.Windows.Interactivity.dll</HintPath>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
@@ -90,9 +89,20 @@
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="xunit.runner.utility.desktop, Version=2.1.0.3179, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\packages\xunit.runner.utility.2.1.0\lib\net35\xunit.runner.utility.desktop.dll</HintPath>
<Private>True</Private>
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll</HintPath>
</Reference>
<Reference Include="xunit.assert, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\packages\xunit.assert.2.4.1\lib\netstandard1.1\xunit.assert.dll</HintPath>
</Reference>
<Reference Include="xunit.core, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\packages\xunit.extensibility.core.2.4.1\lib\net452\xunit.core.dll</HintPath>
</Reference>
<Reference Include="xunit.execution.desktop, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\packages\xunit.extensibility.execution.2.4.1\lib\net452\xunit.execution.desktop.dll</HintPath>
</Reference>
<Reference Include="xunit.runner.utility.net452, Version=2.4.1.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
<HintPath>..\packages\xunit.runner.utility.2.4.1\lib\net452\xunit.runner.utility.net452.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
@@ -100,30 +110,32 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="AssemblyRunner2.cs" />
<Compile Include="CommandBindings.cs" />
<Compile Include="Converters\TestStateConverter.cs" />
<Compile Include="EnumAppDomains.cs" />
<Compile Include="Extensions.cs" />
<Compile Include="FilteredCollectionView.cs" />
<Compile Include="Impl\RemoteTestUtil.Connection.cs" />
<Compile Include="Impl\RemoteTestUtil.BackgroundRunner.cs" />
<Compile Include="Impl\RemoteTestUtil.cs" />
<Compile Include="ICorRuntimeHost.cs" />
<Compile Include="Impl\TestAssemblyWatcher.cs" />
<Compile Include="ITestAssemblyWatcher.cs" />
<Compile Include="ITestUtil.cs" />
<Compile Include="Persistence\Settings.cs" />
<Compile Include="Persistence\Storage.cs" />
<Compile Include="Persistence\Storage.WindowPlacement.cs" />
<Compile Include="Extensions.FuncComparer.cs" />
<Compile Include="ViewModel\RecentAssemblyViewModel.cs" />
<Compile Include="ViewModel\TraitCollectionView.cs" />
<Compile Include="TestDiscoveredInfo.cs" />
<Compile Include="TestState.cs" />
<Compile Include="Tests.cs" />
<Compile Include="ViewModel\AssemblyAndConfigFile.cs" />
<Compile Include="ViewModel\MainViewModel.cs" />
<Compile Include="ViewModel\RecentAssemblyViewModel.cs" />
<Compile Include="ViewModel\SearchQuery.cs" />
<Compile Include="ViewModel\TestCaseViewModel.cs" />
<Compile Include="ViewModel\TestAssemblyViewModel.cs" />
<Compile Include="ViewModel\TestCaseViewModel.cs" />
<Compile Include="ViewModel\TraitCollectionView.cs" />
<Compile Include="ViewModel\TraitViewModel.Comparer.cs" />
<Compile Include="ViewModel\TraitViewModel.cs" />
<Compile Include="ViewModel\ViewModelLocator.cs" />
<Compile Include="XunitWorkerThread.cs" />
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@@ -146,61 +158,41 @@
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="packages.config" />
<AppDesigner Include="Properties\" />
<None Include="xunit.runner.wpf.targets">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<SubType>Designer</SubType>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<NuGetManifest Include="xunit.runner.wpf.nuspec">
<Version>$(NuPkgVersion)</Version>
<PackageAnalysis>False</PackageAnalysis>
</NuGetManifest>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SampleTestAssembly\SampleTestAssembly.csproj">
<Project>{bdafb5dd-ffb3-4a94-a312-dfb080010846}</Project>
<Name>SampleTestAssembly</Name>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\xunit.runner.data\xunit.runner.data.csproj">
<Project>{a1f579f4-443e-4f64-bc55-998ab86ff293}</Project>
<Name>xunit.runner.data</Name>
</ProjectReference>
<ProjectReference Include="..\xunit.runner.worker\xunit.runner.worker.csproj">
<Project>{9df97a2b-0eb5-4b12-9f81-69dfac979814}</Project>
<Name>xunit.runner.worker</Name>
</ProjectReference>
<Analyzer Include="..\packages\xunit.analyzers.0.10.0\analyzers\dotnet\cs\xunit.analyzers.dll" />
</ItemGroup>
<ItemGroup>
<Resource Include="Artwork\Passed_small.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Artwork\Passed_large.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Artwork\Failed_small.png" />
<Resource Include="Artwork\Application.ico" />
</ItemGroup>
<ItemGroup>
<Resource Include="Artwork\Failed_large.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Artwork\Skipped_small.png" />
<Resource Include="Artwork\Failed_small.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Artwork\Skipped_large.png" />
<Resource Include="Artwork\Passed_large.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Artwork\Application.ico" />
<Resource Include="Artwork\Passed_small.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Artwork\Running_large.png" />
@@ -208,13 +200,19 @@
<ItemGroup>
<Resource Include="Artwork\Running_small.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Artwork\Skipped_large.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Artwork\Skipped_small.png" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Tvl.NuGet.BuildTasks.1.0.0-alpha002\build\Tvl.NuGet.BuildTasks.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Tvl.NuGet.BuildTasks.1.0.0-alpha002\build\Tvl.NuGet.BuildTasks.props'))" />
<Error Condition="!Exists('..\packages\Tvl.NuGet.BuildTasks.1.0.0-alpha002\build\Tvl.NuGet.BuildTasks.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Tvl.NuGet.BuildTasks.1.0.0-alpha002\build\Tvl.NuGet.BuildTasks.targets'))" />
<Error Condition="!Exists('..\packages\xunit.core.2.4.1\build\xunit.core.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.4.1\build\xunit.core.props'))" />
<Error Condition="!Exists('..\packages\xunit.core.2.4.1\build\xunit.core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\xunit.core.2.4.1\build\xunit.core.targets'))" />
</Target>
<Import Project="..\packages\Tvl.NuGet.BuildTasks.1.0.0-alpha002\build\Tvl.NuGet.BuildTasks.targets" Condition="Exists('..\packages\Tvl.NuGet.BuildTasks.1.0.0-alpha002\build\Tvl.NuGet.BuildTasks.targets')" />
<Import Project="..\packages\xunit.core.2.4.1\build\xunit.core.targets" Condition="Exists('..\packages\xunit.core.2.4.1\build\xunit.core.targets')" />
</Project>
-20
View File
@@ -1,20 +0,0 @@
<?xml version="1.0"?>
<package >
<metadata>
<id>xunit.runner.wpf</id>
<version>$version$</version>
<title>xUnit.Runner.WPF</title>
<authors>Pilchie</authors>
<owners>Pilchie</owners>
<projectUrl>https://github.com/Pilchie/xunit.runner.wpf</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>XUnit Gui written in WPF</description>
<tags>XUnit Gui test runner</tags>
</metadata>
<files>
<file src="bin\$Configuration$\*.dll" target="tools\"/>
<file src="xunit.runner.wpf.targets" target="build\net45"/>
<file src="bin\$Configuration$\*.exe" target="tools\" exclude="**\*vshost*"/>
<file src="bin\$Configuration$\*.config" target="tools\" exclude="**\*vshost*"/>
</files>
</package>
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<StartAction Condition="'$(StartActions)' == ''">Program</StartAction>
<StartProgram Condition="'$(StartProgram)' == ''">$(MSBuildThisFileDirectory)..\tools\xunit.runner.wpf.exe</StartProgram>
<StartArguments Condition="'$(StartArguments)' == ''">$(AssemblyName).dll</StartArguments>
<StartWorkingDirectory Condition="'$(StartWorkingDirectory)' == ''">$(OutputDirectory)</StartWorkingDirectory>
</PropertyGroup>
</Project>