diff --git a/SampleTestAssembly/Class1.cs b/SampleTestAssembly/Class1.cs
index 0581428..c7187f5 100644
--- a/SampleTestAssembly/Class1.cs
+++ b/SampleTestAssembly/Class1.cs
@@ -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")]
diff --git a/SampleTestAssembly/SampleTestAssembly.csproj b/SampleTestAssembly/SampleTestAssembly.csproj
index 88b95d7..090170b 100644
--- a/SampleTestAssembly/SampleTestAssembly.csproj
+++ b/SampleTestAssembly/SampleTestAssembly.csproj
@@ -1,5 +1,6 @@
+
Debug
@@ -41,20 +42,16 @@
- ..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll
- True
+ ..\packages\xunit.abstractions.2.0.3\lib\net35\xunit.abstractions.dll
-
- ..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll
- True
+
+ ..\packages\xunit.assert.2.4.1\lib\netstandard1.1\xunit.assert.dll
-
- ..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll
- True
+
+ ..\packages\xunit.extensibility.core.2.4.1\lib\net452\xunit.core.dll
-
- ..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll
- True
+
+ ..\packages\xunit.extensibility.execution.2.4.1\lib\net452\xunit.execution.desktop.dll
@@ -64,7 +61,18 @@
+
+
+
+
+
+ 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}.
+
+
+
+
+
-
\ No newline at end of file
diff --git a/xunit.runner.worker/App.config b/xunit.runner.worker/App.config
deleted file mode 100644
index 2d2a12d..0000000
--- a/xunit.runner.worker/App.config
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/xunit.runner.worker/Connection.cs b/xunit.runner.worker/Connection.cs
deleted file mode 100644
index 3902e99..0000000
--- a/xunit.runner.worker/Connection.cs
+++ /dev/null
@@ -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()
- {
-
- }
- }
-}
diff --git a/xunit.runner.worker/DiscoverUtil.cs b/xunit.runner.worker/DiscoverUtil.cs
deleted file mode 100644
index 4ba4bac..0000000
--- a/xunit.runner.worker/DiscoverUtil.cs
+++ /dev/null
@@ -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);
- }
- });
- }
- }
-}
diff --git a/xunit.runner.worker/Listener.cs b/xunit.runner.worker/Listener.cs
deleted file mode 100644
index 0ec1c00..0000000
--- a/xunit.runner.worker/Listener.cs
+++ /dev/null
@@ -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 _taskList = new List();
-
- 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");
- }
- }
-}
diff --git a/xunit.runner.worker/MessageSinks/BaseMessageSink.cs b/xunit.runner.worker/MessageSinks/BaseMessageSink.cs
deleted file mode 100644
index 47d17e9..0000000
--- a/xunit.runner.worker/MessageSinks/BaseMessageSink.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using System;
-using Xunit.Abstractions;
-
-namespace Xunit.Runner.Worker.MessageSinks
-{
- ///
- /// An Xunit implementation without the dispatch overhead of
- /// and .
- ///
- 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);
- }
- }
-}
diff --git a/xunit.runner.worker/MessageSinks/BaseTestDiscoverySink.cs b/xunit.runner.worker/MessageSinks/BaseTestDiscoverySink.cs
deleted file mode 100644
index 4a21c39..0000000
--- a/xunit.runner.worker/MessageSinks/BaseTestDiscoverySink.cs
+++ /dev/null
@@ -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);
- }
-}
diff --git a/xunit.runner.worker/MessageSinks/BaseTestRunSink.cs b/xunit.runner.worker/MessageSinks/BaseTestRunSink.cs
deleted file mode 100644
index 3f3d5a6..0000000
--- a/xunit.runner.worker/MessageSinks/BaseTestRunSink.cs
+++ /dev/null
@@ -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);
- }
-}
diff --git a/xunit.runner.worker/MessageSinks/DiagnosticSink.cs b/xunit.runner.worker/MessageSinks/DiagnosticSink.cs
deleted file mode 100644
index a34958d..0000000
--- a/xunit.runner.worker/MessageSinks/DiagnosticSink.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using Xunit.Abstractions;
-
-namespace Xunit.Runner.Worker.MessageSinks
-{
- internal class DiagnosticSink : BaseMessageSink
- {
- protected override bool OnMessage(IMessageSinkMessage message)
- {
- return true;
- }
- }
-}
diff --git a/xunit.runner.worker/Program.cs b/xunit.runner.worker/Program.cs
deleted file mode 100644
index dd3c290..0000000
--- a/xunit.runner.worker/Program.cs
+++ /dev/null
@@ -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");
- }
- }
-}
diff --git a/xunit.runner.worker/Properties/AssemblyInfo.cs b/xunit.runner.worker/Properties/AssemblyInfo.cs
deleted file mode 100644
index 5aa7b35..0000000
--- a/xunit.runner.worker/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -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")]
diff --git a/xunit.runner.worker/RunUtil.cs b/xunit.runner.worker/RunUtil.cs
deleted file mode 100644
index aab3b60..0000000
--- a/xunit.runner.worker/RunUtil.cs
+++ /dev/null
@@ -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 _testCaseUniqueIDSet;
- private readonly List _testCaseList;
-
- internal TestDiscoverySink(HashSet testCaseUniqueIDSet, List testCaseList)
- {
- _testCaseUniqueIDSet = testCaseUniqueIDSet;
- _testCaseList = testCaseList;
- }
-
- protected override void OnTestDiscovered(ITestCaseDiscoveryMessage testCaseDiscovered)
- {
- var testCase = testCaseDiscovered.TestCase;
- if (_testCaseUniqueIDSet.Contains(testCase.UniqueID))
- {
- _testCaseList.Add(testCaseDiscovered.TestCase);
- }
- }
- }
-
- ///
- /// Read out the set of test case unique IDs to run.
- ///
- private static List ReadTestCaseUniqueIDs(Stream stream)
- {
- using (var reader = new ClientReader(stream))
- {
- var list = new List();
- while (reader.ReadKind() == TestDataKind.Value)
- {
- list.Add(reader.ReadString());
- }
-
- return list;
- }
- }
-
- private static List GetTestCaseList(XunitFrontController xunit, TestAssemblyConfiguration configuration, HashSet testCaseNameSet)
- {
- var testCaseList = new List();
-
- 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(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);
- }
- });
- }
- }
-}
diff --git a/xunit.runner.worker/XunitUtil.cs b/xunit.runner.worker/XunitUtil.cs
deleted file mode 100644
index f3e8e74..0000000
--- a/xunit.runner.worker/XunitUtil.cs
+++ /dev/null
@@ -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 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);
- }
- }
- }
-}
diff --git a/xunit.runner.worker/packages.config b/xunit.runner.worker/packages.config
deleted file mode 100644
index f3e206d..0000000
--- a/xunit.runner.worker/packages.config
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/xunit.runner.worker/xunit.runner.worker.csproj b/xunit.runner.worker/xunit.runner.worker.csproj
deleted file mode 100644
index 5f90231..0000000
--- a/xunit.runner.worker/xunit.runner.worker.csproj
+++ /dev/null
@@ -1,86 +0,0 @@
-
-
-
-
- Debug
- AnyCPU
- {9DF97A2B-0EB5-4B12-9F81-69DFAC979814}
- Exe
- Properties
- Xunit.Runner.Worker
- xunit.runner.worker
- v4.6
- 512
- true
-
-
-
-
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- AnyCPU
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
-
-
-
-
-
-
-
-
- ..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll
-
-
- ..\packages\xunit.runner.utility.2.1.0\lib\net35\xunit.runner.utility.desktop.dll
- True
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {a1f579f4-443e-4f64-bc55-998ab86ff293}
- xunit.runner.data
-
-
-
-
-
\ No newline at end of file
diff --git a/xunit.runner.wpf.sln b/xunit.runner.wpf.sln
index 294990a..181b20f 100644
--- a/xunit.runner.wpf.sln
+++ b/xunit.runner.wpf.sln
@@ -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
diff --git a/xunit.runner.wpf/App.config b/xunit.runner.wpf/App.config
index 2d2a12d..193aecc 100644
--- a/xunit.runner.wpf/App.config
+++ b/xunit.runner.wpf/App.config
@@ -1,6 +1,6 @@
-
+
-
+
-
+
\ No newline at end of file
diff --git a/xunit.runner.wpf/App.xaml b/xunit.runner.wpf/App.xaml
index dc724ff..8a42ee1 100644
--- a/xunit.runner.wpf/App.xaml
+++ b/xunit.runner.wpf/App.xaml
@@ -1,14 +1,7 @@
-
-
-
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/xunit.runner.wpf/App.xaml.cs b/xunit.runner.wpf/App.xaml.cs
index 5d8df6e..ba26f22 100644
--- a/xunit.runner.wpf/App.xaml.cs
+++ b/xunit.runner.wpf/App.xaml.cs
@@ -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
- {
- }
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+ }
}
diff --git a/xunit.runner.wpf/AssemblyRunner2.cs b/xunit.runner.wpf/AssemblyRunner2.cs
new file mode 100644
index 0000000..30a1d39
--- /dev/null
+++ b/xunit.runner.wpf/AssemblyRunner2.cs
@@ -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
+{
+ ///
+ /// 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
+ ///
+ public class AssemblyRunner2 : LongLivedMarshalByRefObject, IDisposable, IMessageSinkWithTypes
+ {
+ static readonly Dictionary MessageTypeNames;
+
+ private TaskCompletionSource 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 testCasesToRun = new List();
+
+ static AssemblyRunner2()
+ {
+ MessageTypeNames = new Dictionary();
+
+ AddMessageTypeName();
+ AddMessageTypeName();
+ AddMessageTypeName();
+ AddMessageTypeName();
+ AddMessageTypeName();
+ AddMessageTypeName();
+ AddMessageTypeName();
+ AddMessageTypeName();
+ AddMessageTypeName();
+ AddMessageTypeName();
+ AddMessageTypeName();
+ AddMessageTypeName();
+ AddMessageTypeName();
+ AddMessageTypeName();
+ AddMessageTypeName();
+ AddMessageTypeName();
+ AddMessageTypeName();
+ }
+
+ AssemblyRunner2(AppDomainSupport appDomainSupport,
+ string assemblyFileName,
+ TaskCompletionSource 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);
+ }
+
+ ///
+ /// Set to get notification of diagnostic messages.
+ ///
+ public Action OnDiagnosticMessage { get; set; }
+
+ ///
+ /// Set to get notification of when test discovery is complete.
+ ///
+ public Action OnDiscoveryComplete { get; set; }
+
+ ///
+ /// Set to get notification of error messages (unhandled exceptions outside of tests).
+ ///
+ public Action OnErrorMessage { get; set; }
+
+ ///
+ /// Set to get notification of when test execution is complete.
+ ///
+ public Action OnExecutionComplete { get; set; }
+
+ ///
+ /// Set to get notification of failed tests.
+ ///
+ public Action OnTestFailed { get; set; }
+
+ ///
+ /// Set to get notification of finished tests (regardless of outcome).
+ ///
+ public Action OnTestFinished { get; set; }
+
+ ///
+ /// 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>.
+ ///
+ public Action OnTestOutput { get; set; }
+
+ ///
+ /// Set to get notification of passing tests.
+ ///
+ public Action OnTestPassed { get; set; }
+
+ ///
+ /// Set to get notification of skipped tests.
+ ///
+ public Action OnTestSkipped { get; set; }
+
+ ///
+ /// Set to get notification of when tests start running.
+ ///
+ public Action OnTestStarting { get; set; }
+
+ ///
+ /// 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.
+ ///
+ public Func TestCaseFilter { get; set; }
+
+ static void AddMessageTypeName() => MessageTypeNames.Add(typeof(T), typeof(T).FullName);
+
+ ///
+ /// 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.
+ ///
+ public void Cancel()
+ {
+ cancelled = true;
+ }
+
+ ///
+ 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;
+ }
+
+ ///
+ /// 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
+ /// to find out the current status.
+ ///
+ /// The (optional) type name of the single test class to run
+ /// Set to true to enable diagnostic messages; set to false to disable them.
+ /// By default, uses the value from the assembly configuration file.
+ /// 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.)
+ /// 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.)
+ /// Set to true to pre-enumerate individual theory tests; set to false 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.)
+ /// Set to true to run test collections in parallel; set to false to run them sequentially.
+ /// By default, uses the value from the assembly configuration file. (This parameter is ignored for xUnit.net v1 tests.)
+ /// 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.)
+ /// Set to true to enable internal diagnostic messages; set to false to disable them.
+ /// By default, uses the value from the assembly configuration file.
+ 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 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);
+ });
+ }
+
+
+ ///
+ /// Creates an assembly runner that discovers and run tests in a separate app domain.
+ ///
+ /// The test assembly.
+ /// The test assembly configuration file.
+ /// If set to true, runs tests in a shadow copied app domain, which allows
+ /// tests to be discovered and run without locking assembly files on disk.
+ /// The path on disk to use for shadow copying; if null, a folder
+ /// will be automatically (randomly) generated
+ //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);
+ //}
+
+
+ ///
+ /// Creates an assembly runner that discovers and runs tests without a separate app domain.
+ ///
+ /// The test assembly.
+ public static AssemblyRunner2 WithoutAppDomain(string assemblyFileName, TaskCompletionSource tcs, CancellationToken cancellationToken)
+ {
+ return new AssemblyRunner2(AppDomainSupport.Denied, assemblyFileName, tcs, cancellationToken);
+ }
+
+ bool DispatchMessage(IMessageSinkMessage message, HashSet messageTypes, Action 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 messageTypes)
+ {
+ if (cancellationToken.IsCancellationRequested)
+ {
+ cancelled = true;
+ }
+
+ if (DispatchMessage(message, messageTypes, testDiscovered =>
+ {
+ ++testCasesDiscovered;
+ if (TestCaseFilter == null || TestCaseFilter(testDiscovered.TestCase))
+ testCasesToRun.Add(testDiscovered.TestCase);
+ }))
+ return !cancelled;
+
+ if (DispatchMessage(message, messageTypes, discoveryComplete =>
+ {
+ OnDiscoveryComplete?.Invoke(new TestDiscoveryInfo(testCasesToRun, assemblyFileName));
+ tcs.TrySetResult("");
+ }))
+ return !cancelled;
+
+ if (DispatchMessage(message, messageTypes, assemblyFinished =>
+ {
+
+ OnExecutionComplete?.Invoke(new ExecutionCompleteInfo(assemblyFinished.TestsRun, assemblyFinished.TestsFailed, assemblyFinished.TestsSkipped, assemblyFinished.ExecutionTime));
+ tcs.TrySetResult("");
+ }))
+ return !cancelled;
+
+ if (OnDiagnosticMessage != null)
+ if (DispatchMessage(message, messageTypes, m => OnDiagnosticMessage(new DiagnosticMessageInfo(m.Message))))
+ return !cancelled;
+ if (OnTestFailed != null)
+ if (DispatchMessage(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(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(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(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(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(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(message, messageTypes, m => OnErrorMessage(new ErrorMessageInfo(ErrorMessageType.CatastrophicError, m.ExceptionTypes.FirstOrDefault(), m.Messages.FirstOrDefault(), m.StackTraces.FirstOrDefault()))))
+ return !cancelled;
+ if (DispatchMessage(message, messageTypes, m => OnErrorMessage(new ErrorMessageInfo(ErrorMessageType.TestAssemblyCleanupFailure, m.ExceptionTypes.FirstOrDefault(), m.Messages.FirstOrDefault(), m.StackTraces.FirstOrDefault()))))
+ return !cancelled;
+ if (DispatchMessage(message, messageTypes, m => OnErrorMessage(new ErrorMessageInfo(ErrorMessageType.TestCaseCleanupFailure, m.ExceptionTypes.FirstOrDefault(), m.Messages.FirstOrDefault(), m.StackTraces.FirstOrDefault()))))
+ return !cancelled;
+ if (DispatchMessage(message, messageTypes, m => OnErrorMessage(new ErrorMessageInfo(ErrorMessageType.TestClassCleanupFailure, m.ExceptionTypes.FirstOrDefault(), m.Messages.FirstOrDefault(), m.StackTraces.FirstOrDefault()))))
+ return !cancelled;
+ if (DispatchMessage(message, messageTypes, m => OnErrorMessage(new ErrorMessageInfo(ErrorMessageType.TestCleanupFailure, m.ExceptionTypes.FirstOrDefault(), m.Messages.FirstOrDefault(), m.StackTraces.FirstOrDefault()))))
+ return !cancelled;
+ if (DispatchMessage(message, messageTypes, m => OnErrorMessage(new ErrorMessageInfo(ErrorMessageType.TestCollectionCleanupFailure, m.ExceptionTypes.FirstOrDefault(), m.Messages.FirstOrDefault(), m.StackTraces.FirstOrDefault()))))
+ return !cancelled;
+ if (DispatchMessage(message, messageTypes, m => OnErrorMessage(new ErrorMessageInfo(ErrorMessageType.TestMethodCleanupFailure, m.ExceptionTypes.FirstOrDefault(), m.Messages.FirstOrDefault(), m.StackTraces.FirstOrDefault()))))
+ return !cancelled;
+ }
+
+ return !cancelled;
+ }
+ }
+}
\ No newline at end of file
diff --git a/xunit.runner.wpf/Converters/TestStateConverter.cs b/xunit.runner.wpf/Converters/TestStateConverter.cs
index 46f1cc3..95b03cc 100644
--- a/xunit.runner.wpf/Converters/TestStateConverter.cs
+++ b/xunit.runner.wpf/Converters/TestStateConverter.cs
@@ -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();
+ }
+ }
+
}
diff --git a/xunit.runner.wpf/EnumAppDomains.cs b/xunit.runner.wpf/EnumAppDomains.cs
new file mode 100644
index 0000000..b2e6b28
--- /dev/null
+++ b/xunit.runner.wpf/EnumAppDomains.cs
@@ -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 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")));
+ }
+ }
+}
diff --git a/xunit.runner.wpf/Extensions.FuncComparer.cs b/xunit.runner.wpf/Extensions.FuncComparer.cs
deleted file mode 100644
index e24fb96..0000000
--- a/xunit.runner.wpf/Extensions.FuncComparer.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace Xunit.Runner.Wpf
-{
- public static partial class Extensions
- {
- private class FuncComparer : IComparer
- {
- private readonly Func _comparison;
-
- public FuncComparer(Func comparison)
- {
- _comparison = comparison;
- }
-
- public int Compare(T x, T y) => _comparison(x, y);
- }
- }
-}
diff --git a/xunit.runner.wpf/Extensions.cs b/xunit.runner.wpf/Extensions.cs
index 38db713..26e3078 100644
--- a/xunit.runner.wpf/Extensions.cs
+++ b/xunit.runner.wpf/Extensions.cs
@@ -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(this ICollection list, IEnumerable items) where TEnumerable : TList
{
- public static void AddRange(this ICollection list, IEnumerable items) where TEnumerable : TList
- {
- foreach (var i in items)
- {
- list.Add(i);
- }
- }
-
- public static void AddRange(this ObservableCollection list, IEnumerable items) where TEnumerable : TList
- {
- foreach (var i in items)
- {
- list.Add(i);
- }
- }
-
- public static int BinarySearch(this ObservableCollection collection, int index, int length, TValue value, IComparer comparer, Func selector)
- {
- comparer = comparer ?? Comparer.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(this ObservableCollection collection, TValue value, IComparer comparer, Func selector)
- {
- return collection.BinarySearch(0, collection.Count, value, comparer, selector);
- }
-
- public static int BinarySearch(this ObservableCollection collection, int index, int length, TValue value, Func comparison, Func selector)
- {
- return collection.BinarySearch(index, length, value, new FuncComparer(comparison), selector);
- }
-
- public static int BinarySearch(this ObservableCollection collection, TValue value, Func comparison, Func selector)
- {
- return collection.BinarySearch(0, collection.Count, value, new FuncComparer(comparison), selector);
- }
-
- public static int BinarySearch(this ObservableCollection collection, TValue value, Func selector)
- {
- return collection.BinarySearch(0, collection.Count, value, comparer: null, selector: selector);
- }
-
- public static int BinarySearch(this ObservableCollection collection, int index, int length, T value, IComparer comparer)
- {
- return collection.BinarySearch(index, length, value, comparer, x => x);
- }
-
- public static int BinarySearch(this ObservableCollection collection, T value, IComparer comparer)
- {
- return collection.BinarySearch(0, collection.Count, value, comparer, x => x);
- }
-
- public static int BinarySearch(this ObservableCollection collection, T value)
- {
- return collection.BinarySearch(0, collection.Count, value, Comparer.Default, x => x);
- }
-
- public static int BinarySearch(this ObservableCollection collection, int index, int length, T value, Func comparison)
- {
- return collection.BinarySearch(index, length, value, new FuncComparer(comparison), x => x);
- }
-
- public static int BinarySearch(this ObservableCollection collection, T value, Func comparison)
- {
- return collection.BinarySearch(0, collection.Count, value, new FuncComparer(comparison), x => x);
- }
+ foreach (var i in items)
+ {
+ list.Add(i);
+ }
}
+
+ public static void AddRange(this ObservableCollection list, IEnumerable items) where TEnumerable : TList
+ {
+ foreach (var i in items)
+ {
+ list.Add(i);
+ }
+ }
+
+ public static int BinarySearch(this ObservableCollection collection, int index, int length, TValue value, IComparer comparer, Func selector)
+ {
+ comparer = comparer ?? Comparer.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(this ObservableCollection collection, TValue value, IComparer comparer, Func selector)
+ {
+ return collection.BinarySearch(0, collection.Count, value, comparer, selector);
+ }
+
+ public static int BinarySearch(this ObservableCollection collection, int index, int length, TValue value, Func comparison, Func selector)
+ {
+ return collection.BinarySearch(index, length, value, new FuncComparer(comparison), selector);
+ }
+
+ public static int BinarySearch(this ObservableCollection collection, TValue value, Func comparison, Func selector)
+ {
+ return collection.BinarySearch(0, collection.Count, value, new FuncComparer(comparison), selector);
+ }
+
+ public static int BinarySearch(this ObservableCollection collection, TValue value, Func selector)
+ {
+ return collection.BinarySearch(0, collection.Count, value, comparer: null, selector: selector);
+ }
+
+ public static int BinarySearch(this ObservableCollection collection, int index, int length, T value, IComparer comparer)
+ {
+ return collection.BinarySearch(index, length, value, comparer, x => x);
+ }
+
+ public static int BinarySearch(this ObservableCollection collection, T value, IComparer comparer)
+ {
+ return collection.BinarySearch(0, collection.Count, value, comparer, x => x);
+ }
+
+ public static int BinarySearch(this ObservableCollection collection, T value)
+ {
+ return collection.BinarySearch(0, collection.Count, value, Comparer.Default, x => x);
+ }
+
+ public static int BinarySearch(this ObservableCollection collection, int index, int length, T value, Func comparison)
+ {
+ return collection.BinarySearch(index, length, value, new FuncComparer(comparison), x => x);
+ }
+
+ public static int BinarySearch(this ObservableCollection collection, T value, Func comparison)
+ {
+ return collection.BinarySearch(0, collection.Count, value, new FuncComparer(comparison), x => x);
+ }
+
+ private class FuncComparer : IComparer
+ {
+ private readonly Func _comparison;
+
+ public FuncComparer(Func comparison)
+ {
+ _comparison = comparison;
+ }
+
+ public int Compare(T x, T y) => _comparison(x, y);
+ }
+ }
+
+
}
diff --git a/xunit.runner.wpf/ICorRuntimeHost.cs b/xunit.runner.wpf/ICorRuntimeHost.cs
new file mode 100644
index 0000000..27d6c7e
--- /dev/null
+++ b/xunit.runner.wpf/ICorRuntimeHost.cs
@@ -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);
+ }
+}
\ No newline at end of file
diff --git a/xunit.runner.wpf/ITestUtil.cs b/xunit.runner.wpf/ITestUtil.cs
deleted file mode 100644
index 1cf8880..0000000
--- a/xunit.runner.wpf/ITestUtil.cs
+++ /dev/null
@@ -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
- {
- ///
- /// Discover the list of test cases which are available in the specified assembly.
- ///
- Task Discover(
- string assebmlyFileName,
- Action> testsDiscovered,
- CancellationToken cancellationToken = default(CancellationToken));
-
- ///
- /// Begin a run of all unit tests for the given assembly.
- ///
- Task RunAll(
- string assemblyFileName,
- Action> testsFinished,
- CancellationToken cancellationToken = default(CancellationToken));
-
- ///
- /// Begin a run of specific unit tests for the given assembly.
- ///
- Task RunSpecific(
- string assemblyFileName,
- ImmutableArray testCasesToRun,
- Action> testsFinished,
- CancellationToken cancellationToken = default(CancellationToken));
- }
-}
diff --git a/xunit.runner.wpf/Impl/RemoteTestUtil.BackgroundRunner.cs b/xunit.runner.wpf/Impl/RemoteTestUtil.BackgroundRunner.cs
deleted file mode 100644
index 6e4907a..0000000
--- a/xunit.runner.wpf/Impl/RemoteTestUtil.BackgroundRunner.cs
+++ /dev/null
@@ -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
- {
- private readonly ClientWriter _writer;
- private readonly ImmutableArray _data;
- private readonly Action _writeValue;
- private readonly CancellationToken _cancellationToken;
-
- internal BackgroundWriter(ClientWriter writer, ImmutableArray data, Action 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);
- }
- }
-
- ///
- /// Utility for reading a collection of values from the given
- /// value.
- ///
- ///
- private sealed class BackgroundReader where T : class
- {
- private readonly ConcurrentQueue _queue;
- private readonly ClientReader _reader;
- private readonly Func _readValue;
-
- internal ClientReader Reader => _reader;
-
- internal BackgroundReader(ConcurrentQueue queue, ClientReader reader, Func readValue)
- {
- _queue = queue;
- _reader = reader;
- _readValue = readValue;
- }
-
- internal Task ReadAsync(CancellationToken cancellationToken = default(CancellationToken))
- {
- return Task.Run(() => GoOnBackground(cancellationToken), cancellationToken);
- }
-
- ///
- /// This will be called on a background thread to read the results of the test from the
- /// named pipe client stream.
- ///
- ///
- 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 where T : class
- {
- private const int MaxResultPerTick = 1000;
-
- private readonly Connection _connection;
- private readonly ConcurrentQueue _queue;
- private readonly DispatcherTimer _timer;
- private readonly Action> _callback;
- private readonly int _maxPerTick;
- private readonly TaskCompletionSource _taskCompletionSource;
-
- internal Task Task => _taskCompletionSource.Task;
-
- internal BackgroundProducer(
- Connection connection,
- Dispatcher dispatcher,
- ConcurrentQueue queue,
- Action> 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();
- }
-
- private void OnTimerTick(object sender, EventArgs e)
- {
- var i = 0;
- var list = new List();
- 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);
- }
- }
- }
- }
- }
-}
diff --git a/xunit.runner.wpf/Impl/RemoteTestUtil.Connection.cs b/xunit.runner.wpf/Impl/RemoteTestUtil.Connection.cs
deleted file mode 100644
index 7b93849..0000000
--- a/xunit.runner.wpf/Impl/RemoteTestUtil.Connection.cs
+++ /dev/null
@@ -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();
- }
- }
- }
-}
diff --git a/xunit.runner.wpf/Impl/RemoteTestUtil.cs b/xunit.runner.wpf/Impl/RemoteTestUtil.cs
deleted file mode 100644
index 0c97f1c..0000000
--- a/xunit.runner.wpf/Impl/RemoteTestUtil.cs
+++ /dev/null
@@ -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 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> 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 testCaseDisplayNames, Action> callback, CancellationToken cancellationToken)
- {
- var connection = await CreateConnection(actionName, assemblyPath, cancellationToken);
-
- if (!testCaseDisplayNames.IsDefaultOrEmpty)
- {
- var backgroundWriter = new BackgroundWriter(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(Connection connection, Func readValue, Action> callback, CancellationToken cancellationToken)
- where T : class
- {
- var queue = new ConcurrentQueue();
- var backgroundReader = new BackgroundReader(queue, new ClientReader(connection.Stream), readValue);
- var backgroundProducer = new BackgroundProducer(connection, _dispatcher, queue, callback);
-
- await backgroundReader.ReadAsync(cancellationToken);
- await backgroundProducer.Task;
- }
-
- #region ITestUtil
-
- Task ITestUtil.Discover(string assemblyFileName, Action> testsDiscovered, CancellationToken cancellationToken)
- {
- return Discover(assemblyFileName, testsDiscovered, cancellationToken);
- }
-
- Task ITestUtil.RunAll(string assemblyFileName, Action> testsFinished, CancellationToken cancellationToken)
- {
- return RunCore(Constants.ActionRunAll, assemblyFileName, ImmutableArray.Empty, testsFinished, cancellationToken);
- }
-
- Task ITestUtil.RunSpecific(string assemblyFileName, ImmutableArray testCases, Action> testsFinished, CancellationToken cancellationToken)
- {
- return RunCore(Constants.ActionRunSpecific, assemblyFileName, testCases, testsFinished, cancellationToken);
- }
-
- #endregion
- }
-}
diff --git a/xunit.runner.wpf/MainWindow.xaml b/xunit.runner.wpf/MainWindow.xaml
index 878a482..3285738 100644
--- a/xunit.runner.wpf/MainWindow.xaml
+++ b/xunit.runner.wpf/MainWindow.xaml
@@ -1,375 +1,362 @@
-
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
+
-
-
-
-
+
+
+
+
+
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
-
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
+
+
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
+
-
-
-
+
+
-
-
+
+
-
-
-
-
+
+
-
-
+
+
-
-
-
-
+
+
-
-
+
+
-
-
-
-
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
+ SelectionMode="Extended" Grid.ColumnSpan="2">
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
-
-
-
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/xunit.runner.wpf/MainWindow.xaml.cs b/xunit.runner.wpf/MainWindow.xaml.cs
index d46e4e1..a39b402 100644
--- a/xunit.runner.wpf/MainWindow.xaml.cs
+++ b/xunit.runner.wpf/MainWindow.xaml.cs
@@ -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;
+ ///
+ /// Interaction logic for MainWindow.xaml
+ ///
+ 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;
+ }
+ }
+ }
+ }
}
diff --git a/xunit.runner.wpf/Persistence/Storage.cs b/xunit.runner.wpf/Persistence/Storage.cs
index dd79b19..8bdbee2 100644
--- a/xunit.runner.wpf/Persistence/Storage.cs
+++ b/xunit.runner.wpf/Persistence/Storage.cs
@@ -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)
{
diff --git a/xunit.runner.wpf/Properties/AssemblyInfo.cs b/xunit.runner.wpf/Properties/AssemblyInfo.cs
index 2252cdb..8eea671 100644
--- a/xunit.runner.wpf/Properties/AssemblyInfo.cs
+++ b/xunit.runner.wpf/Properties/AssemblyInfo.cs
@@ -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
//CultureYouAreCodingWith in your .csproj file
//inside a . For example, if you are using US english
//in your source files, set the 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")]
diff --git a/xunit.runner.wpf/Properties/Resources.Designer.cs b/xunit.runner.wpf/Properties/Resources.Designer.cs
index 6059a19..818f27f 100644
--- a/xunit.runner.wpf/Properties/Resources.Designer.cs
+++ b/xunit.runner.wpf/Properties/Resources.Designer.cs
@@ -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 {
diff --git a/xunit.runner.wpf/Properties/Settings.Designer.cs b/xunit.runner.wpf/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..3f5f090
--- /dev/null
+++ b/xunit.runner.wpf/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+//
+// 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.
+//
+//------------------------------------------------------------------------------
+
+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;
+ }
+ }
+ }
+}
diff --git a/xunit.runner.wpf/Properties/Settings.settings b/xunit.runner.wpf/Properties/Settings.settings
new file mode 100644
index 0000000..033d7a5
--- /dev/null
+++ b/xunit.runner.wpf/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/xunit.runner.wpf/TestDiscoveredInfo.cs b/xunit.runner.wpf/TestDiscoveredInfo.cs
new file mode 100644
index 0000000..244934d
--- /dev/null
+++ b/xunit.runner.wpf/TestDiscoveredInfo.cs
@@ -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 Cases { get; set; }
+ public string AssemblyFileName { get; set; }
+
+ public TestDiscoveryInfo(IEnumerable cases, string assemblyFileName)
+ {
+ Cases = cases;
+ AssemblyFileName = assemblyFileName;
+ }
+ }
+}
diff --git a/xunit.runner.wpf/TestState.cs b/xunit.runner.wpf/TestState.cs
new file mode 100644
index 0000000..4712bc0
--- /dev/null
+++ b/xunit.runner.wpf/TestState.cs
@@ -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
+ }
+}
diff --git a/xunit.runner.wpf/Tests.cs b/xunit.runner.wpf/Tests.cs
new file mode 100644
index 0000000..1de6b1f
--- /dev/null
+++ b/xunit.runner.wpf/Tests.cs
@@ -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));
+ }
+ }
+}
diff --git a/xunit.runner.wpf/ViewModel/MainViewModel.cs b/xunit.runner.wpf/ViewModel/MainViewModel.cs
index 6da0ad2..fbda3c9 100644
--- a/xunit.runner.wpf/ViewModel/MainViewModel.cs
+++ b/xunit.runner.wpf/ViewModel/MainViewModel.cs
@@ -1,919 +1,988 @@
+using GalaSoft.MvvmLight;
+using GalaSoft.MvvmLight.CommandWpf;
+using Microsoft.Win32;
+using Microsoft.WindowsAPICodePack.Taskbar;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
+using System.Data;
using System.Diagnostics;
using System.Linq;
+using System.Reflection;
+using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
-using GalaSoft.MvvmLight;
-using GalaSoft.MvvmLight.CommandWpf;
-using Microsoft.Win32;
-using Microsoft.WindowsAPICodePack.Taskbar;
-using Xunit.Runner.Data;
using Xunit.Runner.Wpf.Persistence;
+using Xunit.Runners;
namespace Xunit.Runner.Wpf.ViewModel
{
- public class MainViewModel : ViewModelBase
+ public class MainViewModel : ViewModelBase
+ {
+
+ //public IAssemblyInjector Injector { get; set; }
+ public List StartupAssemblies { get; set; }
+
+ #region commands
+ public ICommand ExitCommand { get; }
+ public ICommand WindowLoadedCommand { get; }
+ public RelayCommand WindowClosingCommand { get; }
+ public RelayCommand RunAllCommand { get; }
+ public RelayCommand RunSelectedCommand { get; }
+ public RelayCommand CancelCommand { get; }
+ public ICommand TraitCheckedChangedCommand { get; }
+ public ICommand TraitSelectionChangedCommand { get; }
+ public ICommand TraitsClearCommand { get; }
+ public ICommand AssemblyReloadCommand { get; }
+ public ICommand AssemblyReloadAllCommand { get; }
+ public ICommand AssemblyRemoveCommand { get; }
+ public ICommand AssemblyRemoveAllCommand { get; }
+ public ICommand AutoReloadAssembliesCommand { get; }
+
+ public CommandBindingCollection CommandBindings { get; }
+
+ #endregion
+
+ private readonly Settings settings;
+
+
+ private readonly ITestAssemblyWatcher assemblyWatcher;
+ private readonly HashSet allTestCaseUniqueIDs = new HashSet();
+ private readonly ObservableCollection allTestCases = new ObservableCollection();
+ private readonly TraitCollectionView traitCollectionView = new TraitCollectionView();
+ private readonly HashSet runningTestSet = new HashSet();
+
+ private CancellationTokenSource filterCancellationTokenSource = new CancellationTokenSource();
+
+ private CancellationTokenSource cancellationTokenSource;
+ private bool isBusy;
+ private SearchQuery searchQuery = new SearchQuery();
+ private bool autoReloadAssemblies;
+
+ public ObservableCollection Assemblies { get; } = new ObservableCollection();
+ public FilteredCollectionView FilteredTestCases { get; }
+ public ObservableCollection Traits => this.traitCollectionView.Collection;
+ public bool AutoReloadAssemblies
{
- private readonly Settings settings;
+ get => autoReloadAssemblies;
+ set
+ {
+ var oldVal = autoReloadAssemblies;
+ autoReloadAssemblies = value;
+ RaisePropertyChanged(nameof(AutoReloadAssemblies), oldVal, autoReloadAssemblies);
+ }
+ }
- private readonly ITestUtil testUtil;
- private readonly ITestAssemblyWatcher assemblyWatcher;
- private readonly HashSet allTestCaseUniqueIDs = new HashSet();
- private readonly ObservableCollection allTestCases = new ObservableCollection();
- private readonly TraitCollectionView traitCollectionView = new TraitCollectionView();
- private readonly HashSet runningTestSet = new HashSet();
+ public ObservableCollection RecentAssemblies { get; } = new ObservableCollection();
- private CancellationTokenSource filterCancellationTokenSource = new CancellationTokenSource();
+ SynchronizationContext uiContext;
+ ///
+ /// Initializes a new instance of the MainViewModel class.
+ ///
+ public MainViewModel()
+ {
+ this.settings = Settings.Load();
- private CancellationTokenSource cancellationTokenSource;
- private bool isBusy;
- private SearchQuery searchQuery = new SearchQuery();
- private bool autoReloadAssemblies;
+ if (IsInDesignMode)
+ {
+ this.Assemblies.Add(new TestAssemblyViewModel(new AssemblyAndConfigFile(@"C:\Code\xunit.runner.wpf\SampleTestAssembly\bin\Debug\SampleTestAssembly.dll", null)));
+ }
- public ObservableCollection Assemblies { get; } = new ObservableCollection();
- public FilteredCollectionView FilteredTestCases { get; }
- public ObservableCollection Traits => this.traitCollectionView.Collection;
- public bool AutoReloadAssemblies
- {
- get => autoReloadAssemblies;
- set
- {
- var oldVal = autoReloadAssemblies;
- autoReloadAssemblies = value;
- RaisePropertyChanged(nameof(AutoReloadAssemblies), oldVal, autoReloadAssemblies);
- }
- }
+ //Commands
+ CommandBindings = CreateCommandBindings();
+ this.ExitCommand = new RelayCommand(OnExecuteExit);
+ this.WindowLoadedCommand = new RelayCommand(OnExecuteWindowLoaded);
+ this.WindowClosingCommand = new RelayCommand(OnExecuteWindowClosing);
+ this.RunAllCommand = new RelayCommand(OnExecuteRunAll, CanExecuteRunAll);
+ this.RunSelectedCommand = new RelayCommand(OnExecuteRunSelected, CanExecuteRunSelected);
+ this.CancelCommand = new RelayCommand(OnExecuteCancel, CanExecuteCancel);
+ this.TraitCheckedChangedCommand = new RelayCommand(OnExecuteTraitCheckedChanged);
+ this.TraitsClearCommand = new RelayCommand(OnExecuteTraitsClear);
+ this.AssemblyReloadCommand = new RelayCommand(OnExecuteAssemblyReload, CanExecuteAssemblyReload);
+ this.AssemblyReloadAllCommand = new RelayCommand(OnExecuteAssemblyReloadAll);
+ this.AssemblyRemoveCommand = new RelayCommand(OnExecuteAssemblyRemove, CanExecuteAssemblyRemove);
+ this.AssemblyRemoveAllCommand = new RelayCommand(OnExecuteAssemblyRemoveAll);
+ this.AutoReloadAssembliesCommand = new RelayCommand(OnToggleAutoReloadAssemblies);
- public ObservableCollection RecentAssemblies { get; } = new ObservableCollection();
-
- private ImmutableList testsToRun;
-
- public ICommand ExitCommand { get; }
- public ICommand WindowLoadedCommand { get; }
- public RelayCommand WindowClosingCommand { get; }
- public RelayCommand RunAllCommand { get; }
- public RelayCommand RunSelectedCommand { get; }
- public RelayCommand CancelCommand { get; }
- public ICommand TraitCheckedChangedCommand { get; }
- public ICommand TraitSelectionChangedCommand { get; }
- public ICommand TraitsClearCommand { get; }
- public ICommand AssemblyReloadCommand { get; }
- public ICommand AssemblyReloadAllCommand { get; }
- public ICommand AssemblyRemoveCommand { get; }
- public ICommand AssemblyRemoveAllCommand { get; }
- public ICommand AutoReloadAssembliesCommand { get; }
-
- public CommandBindingCollection CommandBindings { get; }
-
- public MainViewModel()
- {
- this.settings = Settings.Load();
-
- if (IsInDesignMode)
- {
- this.Assemblies.Add(new TestAssemblyViewModel(new AssemblyAndConfigFile(@"C:\Code\TestAssembly.dll", null)));
- }
-
- CommandBindings = CreateCommandBindings();
-
- this.testUtil = new Xunit.Runner.Wpf.Impl.RemoteTestUtil(Dispatcher.CurrentDispatcher);
- this.assemblyWatcher = new Impl.TestAssemblyWatcher(Dispatcher.CurrentDispatcher);
- this.TestCasesCaption = "Test Cases (0)";
-
- this.FilteredTestCases = new FilteredCollectionView(
+ this.FilteredTestCases = new FilteredCollectionView(
allTestCases, TestCaseMatches, searchQuery, TestComparer.Instance);
- this.FilteredTestCases.CollectionChanged += TestCases_CollectionChanged;
+ this.FilteredTestCases.CollectionChanged += TestCases_CollectionChanged;
- this.ExitCommand = new RelayCommand(OnExecuteExit);
- this.WindowLoadedCommand = new RelayCommand(OnExecuteWindowLoaded);
- this.WindowClosingCommand = new RelayCommand(OnExecuteWindowClosing);
- this.RunAllCommand = new RelayCommand(OnExecuteRunAll, CanExecuteRunAll);
- this.RunSelectedCommand = new RelayCommand(OnExecuteRunSelected, CanExecuteRunSelected);
- this.CancelCommand = new RelayCommand(OnExecuteCancel, CanExecuteCancel);
- this.TraitCheckedChangedCommand = new RelayCommand(OnExecuteTraitCheckedChanged);
- this.TraitsClearCommand = new RelayCommand(OnExecuteTraitsClear);
- this.AssemblyReloadCommand = new RelayCommand(OnExecuteAssemblyReload, CanExecuteAssemblyReload);
- this.AssemblyReloadAllCommand = new RelayCommand(OnExecuteAssemblyReloadAll);
- this.AssemblyRemoveCommand = new RelayCommand(OnExecuteAssemblyRemove, CanExecuteAssemblyRemove);
- this.AssemblyRemoveAllCommand = new RelayCommand(OnExecuteAssemblyRemoveAll);
- this.AutoReloadAssembliesCommand = new RelayCommand(OnToggleAutoReloadAssemblies);
+ this.assemblyWatcher = new Impl.TestAssemblyWatcher(Dispatcher.CurrentDispatcher);
+ this.TestCasesCaption = "Test Cases (0)";
- RebuildRecentAssembliesMenu();
- AutoReloadAssemblies = this.settings.GetAutoReloadAssemblies();
- UpdateAutoReloadStatus();
- }
- private void RebuildRecentAssembliesMenu()
+ RebuildRecentAssembliesMenu();
+ AutoReloadAssemblies = this.settings.GetAutoReloadAssemblies();
+ UpdateAutoReloadStatus();
+
+ uiContext = SynchronizationContext.Current;
+ }
+
+
+
+ private Task Discover(string assemblyPath)
+ {
+ var tcs = new TaskCompletionSource();
+ try
+ {
+ using (var runner = AssemblyRunner2.WithoutAppDomain(assemblyPath, tcs, cancellationTokenSource.Token))
{
- this.RecentAssemblies.Clear();
+ runner.OnDiscoveryComplete = OnTestsDiscovered;
+ runner.Discover();
+ }
+ }
+ catch (Exception e)
+ {
+ }
+ return tcs.Task;
+ }
- foreach (var recentAssembly in this.settings.GetRecentAssemblies())
+
+
+ private List RunTests(IEnumerable testsToRun)
+ {
+ Debug.Assert(this.isBusy);
+ Debug.Assert(this.cancellationTokenSource != null);
+
+ TestsCompleted = 0;
+ TestsRunning = 0;
+ TestsPassed = 0;
+ TestsFailed = 0;
+ TestsSkipped = 0;
+ CurrentRunState = TestState.NotRun;
+
+ foreach (var test in testsToRun)
+ test.State = TestState.NotRun;
+
+
+ var taskList = new List();
+ var assemblies = testsToRun.GroupBy(x => x.AssemblyFileName).ToDictionary(x => x.Key, y => y.ToList());
+
+ foreach (var key in assemblies.Keys)
+ {
+ var path = assemblies[key].FirstOrDefault().AssemblyPath;
+ taskList.Add(Run(path, key, assemblies[key]));
+ }
+ return taskList;
+
+ }
+
+ private Task Run(string assemblyPath, string assemblyName, IEnumerable testsToRun)
+ {
+
+ var tcs = new TaskCompletionSource();
+
+ try
+ {
+ ////inject stuff into assembly
+ //if (Injector != null)
+ //{
+ // Assembly ass = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.FullName == assemblyName);
+ // if (ass != null)
+ // Injector.Inject(ass);
+ //}
+
+ using (var runner = AssemblyRunner2.WithoutAppDomain(assemblyPath, tcs, cancellationTokenSource.Token))
+ {
+ runner.OnExecutionComplete = OnExecutionComplete;
+ runner.OnTestStarting = OnTestStarting;
+ runner.OnTestFailed = OnTestFailed;
+ runner.OnTestSkipped = OnTestSkipped;
+ runner.OnTestPassed = OnTestPassed;
+ runner.OnTestFinished = OnTestFinished;
+
+ runner.Run(testsToRun.Select(x => x.TestCase).ToList(), maxParallelThreads:1);
+ }
+
+ }
+ catch (Exception e)
+ {
+ }
+
+ return tcs.Task;
+ }
+
+ #region commands
+ private bool CanExecuteCancel()
+ {
+ return this.cancellationTokenSource != null && !this.cancellationTokenSource.IsCancellationRequested;
+ }
+
+ private void OnExecuteCancel()
+ {
+ Debug.Assert(CanExecuteCancel());
+ this.cancellationTokenSource.Cancel();
+ }
+
+
+ private async void OnExecuteOpen(object sender, ExecutedRoutedEventArgs e)
+ {
+ var fileDialog = new OpenFileDialog
+ {
+ Filter = "Unit Test Assemblies|*.dll",
+ Multiselect = true
+ };
+
+ if (fileDialog.ShowDialog() != true)
+ {
+ return;
+ }
+
+ var assemblies = fileDialog.FileNames.Select(x => new AssemblyAndConfigFile(x, configFileName: null));
+ await AddAssemblies(assemblies);
+ }
+
+ private static void OnExecuteExit()
+ {
+ //Application.Current.Shutdown();
+ }
+
+ private async void OnExecuteWindowLoaded()
+ {
+ if (StartupAssemblies == null)
+ return;
+ var assemblies = StartupAssemblies.Select(x => new AssemblyAndConfigFile(x, configFileName: null));
+ await AddAssemblies(assemblies);
+ //await AddAssemblies(ParseCommandLine(Environment.GetCommandLineArgs().Skip(1)));
+ }
+
+ private void OnExecuteWindowClosing(CancelEventArgs e)
+ {
+ this.settings.Save();
+ }
+
+ private bool CanExecuteRunAll()
+ => !IsBusy && FilteredTestCases.Any();
+
+ private bool CanExecuteRunSelected()
+ => !IsBusy && SelectedTestCase != null;
+ private async void OnExecuteRunAll()
+ {
+ UpdateTestCaseInfo(useSelected: false);
+
+ await ExecuteTestSessionOperation(RunFilteredTests);
+ }
+ private async void OnExecuteRunSelected()
+ {
+ Debug.Assert(this.SelectedTestCase != null);
+ UpdateTestCaseInfo(useSelected: true);
+
+ await ExecuteTestSessionOperation(RunSelectedTests);
+
+ }
+ private List