52 Commits

Author SHA1 Message Date
Kevin Pilch 41c9282023 Update to latest xunit, and target net472 and netstandard2.0 2018-12-02 17:01:12 -08:00
Kevin Pilch b7293a15f7 Generate AssemblyInfos, get rid of App.config, and change NuGet package to global tool 2018-12-02 16:22:07 -08:00
Kevin Pilch 8e6a0ea916 Don't create windows for worker processes 2018-12-01 12:56:01 -08:00
Kevin Pilch 709b166870 Revert to .NET 4.5.2 and xunit.runner.utility 2.1.0 2018-12-01 12:50:29 -08:00
Kevin Pilch 2251487778 Convert the rest of the projectS 2018-12-01 12:50:29 -08:00
Kevin Pilch 5e3aa442b8 Convert to .NET Core 3.0 2018-12-01 12:46:52 -08:00
Kevin Pilch c28059ca4c Merge pull request #88 from Pilchie/NoCompilerPackage
Stop using the compiler package
2018-12-01 12:42:52 -08:00
Kevin Pilch d93c706a3d Stop using the compiler package 2018-12-01 12:36:23 -08:00
Kevin Pilch e9dfb23e18 Merge pull request #84 from Eawvv/gui-enhancements
Gui enhancements - Run selected on enter or double click
2018-02-16 09:05:30 -08:00
Edwin Roerdink f6e8918bef execute test on enter key 2018-02-04 01:42:25 +01:00
Edwin Roerdink 18275067e9 execute test on double click 2018-02-04 01:19:04 +01:00
Kevin Pilch 39f89587fc Merge pull request #81 from heejaechang/fixDiscovery
made discovery to use same setting as run so that same tests are disc…
2017-11-01 09:24:29 -07:00
Heejae Chang 8c3c86d918 made wpf xunit runner to support showing/filtering running tests so that if we get deadlock or hang tests, we can see what the test it was running easily. 2017-10-31 17:23:22 -07:00
Heejae Chang 761f801e43 made discovery to use same setting as run so that same tests are discovered. 2017-10-31 14:56:33 -07:00
Kevin Pilch 643d9061c8 Merge pull request #79 from 333fred/fix-autoreload
Fix first open and default autoreload case
2017-06-05 16:17:11 -07:00
Fredric Silberberg 6d4a249a97 Fix first open and default autoreload case 2017-06-05 15:49:35 -07:00
Kevin Pilch 5ed3579b30 Merge pull request #78 from 333fred/screenshot
Added screenshot to readme.
2017-06-05 11:22:21 -07:00
Fredric Silberberg 1f55afd2e9 Added screenshot to readme. 2017-06-05 10:49:13 -07:00
Kevin Pilch c6c48067a7 Merge pull request #77 from 333fred/update-readme
Add nuget to readme
2017-06-05 10:32:28 -07:00
Fredric Silberberg ab5b3afea2 Add nuget to readme 2017-06-05 10:30:00 -07:00
Kevin Pilch feb8588961 Merge pull request #76 from sharwell/open-2017
Open solution in Visual Studio 2017
2017-06-03 14:42:28 -07:00
Kevin Pilch 08907d707c Merge pull request #75 from sharwell/include-binaries
Include binaries in the NuGet package
2017-06-03 14:42:07 -07:00
Sam Harwell de354d8095 Open solution in Visual Studio 2017
Since the project is using features from C# 7, update the solution to open
by default in a version of Visual Studio that supports them.
2017-06-03 16:40:14 -05:00
Sam Harwell dd668f753b Move .targets into a framework-specific folder
Fixes installation via project.json.
2017-06-03 16:38:56 -05:00
Sam Harwell a5712e104a Disable NuGet package analysis since this is a non-standard package layout 2017-06-03 16:30:06 -05:00
Sam Harwell f2e1c0fb5e Include binaries in NuGet package 2017-06-03 16:27:16 -05:00
Kevin Pilch 80fc0702d1 Merge pull request #74 from 333fred/autoreload
Autoreload
2017-06-03 13:57:52 -07:00
Fredric Silberberg 39c5a33d56 Use Microsoft.Net.Compilers, update all base system libraries 2017-06-02 16:40:48 -07:00
Fredric Silberberg 686404bb7f Remove from watch when removed from the program. 2017-06-02 16:25:17 -07:00
Fredric Silberberg e41071ddb0 Added autoreloading of test assemblies 2017-06-02 16:19:08 -07:00
Fredric Silberberg 13f0cedb64 Fix whitespace 2017-06-02 16:18:53 -07:00
Kevin Pilch 93601521fc Merge pull request #72 from sharwell/improved-sort
Implemented sorting for tests
2017-04-12 16:25:30 -07:00
Kevin Pilch 24522e8749 Merge pull request #71 from sharwell/cancellation
Propagate CancellationToken where applicable
2017-04-12 16:20:59 -07:00
Kevin Pilch 070d3bcb5e Merge pull request #70 from sharwell/unique-id
Fix crashes related to multiple tests with the same name
2017-04-12 16:20:16 -07:00
Sam Harwell 78501d237a Applied sort order for tests with and without filters applied 2017-03-25 17:36:20 -05:00
Sam Harwell 1e2fe65dfa Improve sort order to prefer to ignore case 2017-03-25 17:22:33 -05:00
Sam Harwell 0a52154c60 Propagate CancellationToken where applicable 2017-03-25 17:16:23 -05:00
Sam Harwell d26343057f Avoid adding duplicate tests
Fixes a crash when attempting to run tests in an assembly containing one or
more parameterized tests with duplicated parameter sets.
2017-03-25 16:06:16 -05:00
Kevin Pilch ba398d66ad Merge pull request #68 from sharwell/nuget-pack
Improved NuGet build integration
2017-03-25 12:01:23 -07:00
Sam Harwell 412c9b78fe Use the unique ID of test cases instead of display name for lookups
Fixes a crash when attempting to run the StyleCop Analyzers test suite.
2017-03-25 12:25:49 -05:00
Kevin Pilch 8eea004410 Merge pull request #69 from sharwell/fix-help
Fix unnecessarily loud typo in help text
2017-03-25 09:13:19 -07:00
Sam Harwell e52d9195ef Fix unnecessarily loud typo in help text 2017-03-25 09:02:06 -05:00
Sam Harwell 80a52c0f30 Improved NuGet build integration 2017-03-25 08:58:24 -05:00
Kevin Pilch a3ceb785fa Merge pull request #66 from mattwar/Updates
Fix progress bar and add support for running selected tests
2016-10-29 11:06:52 -07:00
Matt Warren 9a94bfd08d clear select flags on collection reset 2016-10-29 02:39:43 +00:00
Matt Warren cd411e5d56 support running selected tests 2016-10-29 02:33:26 +00:00
Matt Warren ed8641a896 Fix progress updates 2016-10-28 22:16:17 +00:00
Dustin Campbell bb9ed9106b Merge pull request #64 from DustinCampbell/fix-duplicate-recent-assembly
Fix off by one error resulting in duplicate assemblies in recent assembly list
2016-07-06 14:08:28 -07:00
Dustin Campbell 5e966ff461 Fix off by one error resulting in duplicate assemblies in recent assembly list 2016-07-06 14:02:36 -07:00
Kevin Pilch-Bisson 83bd1be9bf Add instructions on creating a release 2016-05-28 15:03:01 -07:00
Kevin Pilch-Bisson 84b0c7b4c8 Merge pull request #63 from Pilchie/nuget-props
Add targets file to make it easier to launch this from projects
2016-05-28 14:41:34 -07:00
Kevin Pilch-Bisson 7dc9b5d7d1 Add targets file to make it easier to launch this from projects 2016-05-28 14:32:33 -07:00
41 changed files with 988 additions and 825 deletions
+1
View File
@@ -214,3 +214,4 @@ FakesAssemblies/
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
/Settings.XamlStyle
+4
View File
@@ -3,4 +3,8 @@ XUnit Gui written in WPF
A simple replacement for the old winforms xunit.gui with support for xunit 2.0.
Find it on NuGet at [xunit.runner.wpf](https://www.nuget.org/packages/xunit.runner.wpf).
![Screenshot](docs/screenshot.png)
[![Build status](https://ci.appveyor.com/api/projects/status/13dshnyj592mwe9e/branch/master?svg=true)](https://ci.appveyor.com/project/Pilchie/xunit-runner-wpf/branch/master)
@@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
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("SampleTestAssembly")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SampleTestAssembly")]
[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("bdafb5dd-ffb3-4a94-a312-dfb080010846")]
// 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")]
+6 -70
View File
@@ -1,75 +1,11 @@
<?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')" />
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{BDAFB5DD-FFB3-4A94-A312-DFB080010846}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SampleTestAssembly</RootNamespace>
<AssemblyName>SampleTestAssembly</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</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>
<TargetFramework>netstandard2.0</TargetFramework>
</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, 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>
</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>
<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>
<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>
<PackageReference Include="xunit" Version="2.4.1" />
</ItemGroup>
<ItemGroup>
<Compile Include="Class1.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</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>
-9
View File
@@ -1,9 +0,0 @@
<?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" />
</packages>
+13
View File
@@ -0,0 +1,13 @@
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.

After

Width:  |  Height:  |  Size: 127 KiB

@@ -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")]
+6 -2
View File
@@ -6,13 +6,15 @@ 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 skipReason, string assemblyPath, Dictionary<string, List<string>> traitMap)
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;
@@ -21,6 +23,7 @@ namespace Xunit.Runner.Data
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();
@@ -40,12 +43,13 @@ namespace Xunit.Runner.Data
traitMap.Add(key, values);
}
return new TestCaseData(displayName, skipReason, assemblyPath, traitMap);
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);
+7 -2
View File
@@ -10,6 +10,7 @@ namespace Xunit.Runner.Data
{
All = 0,
NotRun,
Running,
Passed,
Skipped,
Failed,
@@ -18,12 +19,14 @@ namespace Xunit.Runner.Data
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, TestState state, string output = "")
public TestResultData(string displayName, string uniqueID, TestState state, string output = "")
{
TestCaseDisplayName = displayName;
TestCaseUniqueID = uniqueID;
TestState = state;
Output = output;
}
@@ -31,14 +34,16 @@ namespace Xunit.Runner.Data
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, state, output);
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);
}
+4 -55
View File
@@ -1,59 +1,8 @@
<?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')" />
<Project Sdk="Microsoft.NET.Sdk">
<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>
<TargetFramework>netstandard2.0</TargetFramework>
</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>
+110
View File
@@ -0,0 +1,110 @@
#if NETFRAMEWORK
// Taken from https://github.com/xunit/xunit/blob/master/src/common/AssemblyResolution/AssemblyHelper_Desktop.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Reflection;
using Xunit.Abstractions;
using Xunit.Sdk;
namespace Xunit
{
/// <summary>
/// This class provides assistance with assembly resolution for missing assemblies.
/// </summary>
class AssemblyHelper : LongLivedMarshalByRefObject, IDisposable
{
static readonly string[] Extensions = { ".dll", ".exe" };
readonly string directory;
readonly IMessageSink internalDiagnosticsMessageSink;
readonly Dictionary<string, Assembly> lookupCache = new Dictionary<string, Assembly>();
/// <summary>
/// Constructs an instance using the given <paramref name="directory"/> for resolution.
/// </summary>
/// <param name="directory">The directory to use for resolving assemblies.</param>
public AssemblyHelper(string directory) : this(directory, null) { }
/// <summary>
/// Constructs an instance using the given <paramref name="directory"/> for resolution.
/// </summary>
/// <param name="directory">The directory to use for resolving assemblies.</param>
/// <param name="internalDiagnosticsMessageSink">The message sink to send internal diagnostics messages to</param>
public AssemblyHelper(string directory, IMessageSink internalDiagnosticsMessageSink)
{
this.directory = directory;
this.internalDiagnosticsMessageSink = internalDiagnosticsMessageSink;
AppDomain.CurrentDomain.AssemblyResolve += Resolve;
}
/// <inheritdoc/>
public void Dispose()
=> AppDomain.CurrentDomain.AssemblyResolve -= Resolve;
Assembly LoadAssembly(AssemblyName assemblyName)
{
if (lookupCache.TryGetValue(assemblyName.Name, out var result))
return result;
var path = Path.Combine(directory, assemblyName.Name);
result = ResolveAndLoadAssembly(path, out var resolvedAssemblyPath);
if (internalDiagnosticsMessageSink != null)
{
if (result == null)
internalDiagnosticsMessageSink.OnMessage(new DiagnosticMessage($"[AssemblyHelper_Desktop.LoadAssembly] Resolution for '{assemblyName.Name}' failed, passed down to next resolver"));
else
internalDiagnosticsMessageSink.OnMessage(new DiagnosticMessage($"[AssemblyHelper_Desktop.LoadAssembly] Resolved '{assemblyName.Name}' to '{resolvedAssemblyPath}'"));
}
lookupCache[assemblyName.Name] = result;
return result;
}
Assembly Resolve(object sender, ResolveEventArgs args)
=> LoadAssembly(new AssemblyName(args.Name));
Assembly ResolveAndLoadAssembly(string pathWithoutExtension, out string resolvedAssemblyPath)
{
foreach (var extension in Extensions)
{
resolvedAssemblyPath = pathWithoutExtension + extension;
try
{
if (File.Exists(resolvedAssemblyPath))
return Assembly.LoadFrom(resolvedAssemblyPath);
}
catch { }
}
resolvedAssemblyPath = null;
return null;
}
/// <summary>
/// Subscribes to the appropriate assembly resolution event, to provide automatic assembly resolution for
/// an assembly and any of its dependencies. Depending on the target platform, this may include the use
/// of the .deps.json file generated during the build process.
/// </summary>
/// <returns>An object which, when disposed, un-subscribes.</returns>
public static IDisposable SubscribeResolveForAssembly(string assemblyFileName, IMessageSink internalDiagnosticsMessageSink = null)
=> new AssemblyHelper(Path.GetDirectoryName(Path.GetFullPath(assemblyFileName)), internalDiagnosticsMessageSink);
/// <summary>
/// Subscribes to the appropriate assembly resolution event, to provide automatic assembly resolution for
/// an assembly and any of its dependencies. Depending on the target platform, this may include the use
/// of the .deps.json file generated during the build process.
/// </summary>
/// <returns>An object which, when disposed, un-subscribes.</returns>
public static IDisposable SubscribeResolveForAssembly(Type typeInAssembly, IMessageSink internalDiagnosticsMessageSink = null)
=> new AssemblyHelper(Path.GetDirectoryName(typeInAssembly.Assembly.Location), internalDiagnosticsMessageSink);
}
}
#endif
+2 -1
View File
@@ -23,6 +23,7 @@ namespace Xunit.Runner.Worker
var testCase = testCaseDiscovered.TestCase;
var testCaseData = new TestCaseData(
testCase.DisplayName,
testCase.UniqueID,
testCase.SkipReason,
testCaseDiscovered.TestAssembly.Assembly.AssemblyPath,
testCase.Traits);
@@ -34,7 +35,7 @@ namespace Xunit.Runner.Worker
internal static void Go(string assemblyFileName, Stream stream)
{
Go(assemblyFileName, stream, AppDomainSupport.Denied,
Go(assemblyFileName, stream, AppDomainSupport.IfAvailable,
(xunit, configuration, writer) =>
{
using (var sink = new TestDiscoverySink(writer))
@@ -1,5 +1,6 @@
using System;
using Xunit.Abstractions;
using Xunit.Sdk;
namespace Xunit.Runner.Worker.MessageSinks
{
@@ -19,6 +19,12 @@ namespace Xunit.Runner.Worker.MessageSinks
protected override bool OnMessage(IMessageSinkMessage message)
{
var testStarted = message as ITestStarting;
if (testStarted != null)
{
OnTestStarted(testStarted);
}
var testFailed = message as ITestFailed;
if (testFailed != null)
{
@@ -47,6 +53,7 @@ namespace Xunit.Runner.Worker.MessageSinks
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);
+2 -2
View File
@@ -37,8 +37,8 @@ namespace Xunit.Runner.Worker
{
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("\assembly path: Path of assembly to perform the action against");
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")]
+19 -14
View File
@@ -21,15 +21,20 @@ namespace Xunit.Runner.Worker
protected override bool ShouldContinue => _writer.IsConnected;
private void Process(string displayName, TestState state, string output = "")
private void Process(string displayName, string uniqueID, TestState state, string output = "")
{
Console.WriteLine($"{state} - {displayName}");
var result = new TestResultData(displayName, state, 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;
@@ -46,35 +51,35 @@ namespace Xunit.Runner.Worker
builder.AppendLine();
Process(testFailed.TestCase.DisplayName, TestState.Failed, builder.ToString());
Process(testFailed.TestCase.DisplayName, testFailed.TestCase.UniqueID, TestState.Failed, builder.ToString());
}
protected override void OnTestPassed(ITestPassed testPassed)
{
Process(testPassed.TestCase.DisplayName, TestState.Passed);
Process(testPassed.TestCase.DisplayName, testPassed.TestCase.UniqueID, TestState.Passed);
}
protected override void OnTestSkipped(ITestSkipped testSkipped)
{
Process(testSkipped.TestCase.DisplayName, TestState.Skipped);
Process(testSkipped.TestCase.DisplayName, testSkipped.TestCase.UniqueID, TestState.Skipped);
}
}
private sealed class TestDiscoverySink : BaseTestDiscoverySink
{
private readonly HashSet<string> _testCaseNameSet;
private readonly HashSet<string> _testCaseUniqueIDSet;
private readonly List<ITestCase> _testCaseList;
internal TestDiscoverySink(HashSet<string> testCaseDisplayNameSet, List<ITestCase> testCaseList)
internal TestDiscoverySink(HashSet<string> testCaseUniqueIDSet, List<ITestCase> testCaseList)
{
_testCaseNameSet = testCaseDisplayNameSet;
_testCaseUniqueIDSet = testCaseUniqueIDSet;
_testCaseList = testCaseList;
}
protected override void OnTestDiscovered(ITestCaseDiscoveryMessage testCaseDiscovered)
{
var testCase = testCaseDiscovered.TestCase;
if (_testCaseNameSet.Contains(testCase.DisplayName))
if (_testCaseUniqueIDSet.Contains(testCase.UniqueID))
{
_testCaseList.Add(testCaseDiscovered.TestCase);
}
@@ -82,9 +87,9 @@ namespace Xunit.Runner.Worker
}
/// <summary>
/// Read out the set of test case display names to run.
/// Read out the set of test case unique IDs to run.
/// </summary>
private static List<string> ReadTestCaseDisplayNames(Stream stream)
private static List<string> ReadTestCaseUniqueIDs(Stream stream)
{
using (var reader = new ClientReader(stream))
{
@@ -133,14 +138,14 @@ namespace Xunit.Runner.Worker
internal static void RunSpecific(string assemblyFileName, Stream stream)
{
var testCaseNameSet = new HashSet<string>(ReadTestCaseDisplayNames(stream), StringComparer.Ordinal);
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, testCaseNameSet);
var testCaseList = GetTestCaseList(xunit, configuration, testCaseUniqueIDSet);
xunit.RunTests(testCaseList, sink,
executionOptions: TestFrameworkOptions.ForExecution(configuration));
+1 -1
View File
@@ -9,7 +9,7 @@ namespace Xunit.Runner.Worker
protected static void Go(string assemblyFileName, Stream stream, AppDomainSupport appDomainSupport,
Action<XunitFrontController, TestAssemblyConfiguration, ClientWriter> action)
{
using (AssemblyHelper.SubscribeResolve())
using (AssemblyHelper.SubscribeResolveForAssembly(assemblyFileName))
using (var xunit = new XunitFrontController(appDomainSupport, assemblyFileName, shadowCopy: false))
using (var writer = new ClientWriter(stream))
{
-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>
+7 -77
View File
@@ -1,84 +1,14 @@
<?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')" />
<Project Sdk="Microsoft.NET.Sdk">
<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 />
</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>
<TargetFramework>net472</TargetFramework>
</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>
<PackageReference Include="xunit.runner.utility" Version="2.4.1" />
<ProjectReference Include="..\xunit.runner.data\xunit.runner.data.csproj" />
</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>
+2 -2
View File
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
# Visual Studio 15
VisualStudioVersion = 15.0.26430.4
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}"
EndProject
-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>
Binary file not shown.

After

Width:  |  Height:  |  Size: 659 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

@@ -9,6 +9,7 @@ namespace Xunit.Runner.Wpf.Converters
{
public class TestStateConverter : IValueConverter
{
private static ImageSource runningSource;
private static ImageSource failedSource;
private static ImageSource passedSource;
private static ImageSource skippedSource;
@@ -17,6 +18,7 @@ namespace Xunit.Runner.Wpf.Converters
static TestStateConverter()
{
runningSource = LoadResourceImage("Running_small.png");
failedSource = LoadResourceImage("Failed_small.png");
passedSource = LoadResourceImage("Passed_small.png");
skippedSource = LoadResourceImage("Skipped_small.png");
@@ -38,6 +40,8 @@ namespace Xunit.Runner.Wpf.Converters
{
switch (state)
{
case TestState.Running:
return Brushes.Blue;
case TestState.Failed:
return Brushes.Red;
case TestState.Passed:
@@ -52,6 +56,8 @@ namespace Xunit.Runner.Wpf.Converters
{
switch (state)
{
case TestState.Running:
return runningSource;
case TestState.Failed:
return failedSource;
case TestState.Passed:
+15 -5
View File
@@ -15,6 +15,7 @@ namespace Xunit.Runner.Wpf
private readonly ObservableCollection<T> dataSource;
private readonly List<T> filteredList;
private readonly Func<T, TFilterArg, bool> filter;
private readonly IComparer<T> sort;
public FilteredCollectionView(ObservableCollection<T> dataSource, Func<T, TFilterArg, bool> filter, TFilterArg filterArgument, IComparer<T> sort)
{
@@ -26,6 +27,7 @@ namespace Xunit.Runner.Wpf
this.filter = filter;
this.filterArgument = filterArgument;
this.filteredList = new List<T>();
this.sort = sort;
this.dataSource.CollectionChanged += this.dataSource_CollectionChanged;
@@ -71,6 +73,7 @@ namespace Xunit.Runner.Wpf
}
}
this.filteredList.Sort(sort);
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
@@ -115,7 +118,7 @@ namespace Xunit.Runner.Wpf
{
if (this.filter(item, this.filterArgument))
{
int index = this.filteredList.IndexOf(item);
int index = this.filteredList.BinarySearch(item, sort);
if (index < 0)
{
this.filteredList.Insert(~index, item);
@@ -138,7 +141,7 @@ namespace Xunit.Runner.Wpf
observable.PropertyChanged -= this.dataSource_ItemChanged;
}
int index = this.filteredList.IndexOf(item);
int index = this.filteredList.BinarySearch(item, sort);
if (index >= 0)
{
this.filteredList.RemoveAt(index);
@@ -149,7 +152,7 @@ namespace Xunit.Runner.Wpf
private void dataSource_ItemChanged(object sender, PropertyChangedEventArgs e)
{
var item = (T)sender;
int index = this.filteredList.IndexOf(item);
int index = this.filteredList.BinarySearch(item, sort);
if (this.filter(item, this.FilterArgument))
{
if (index < 0)
@@ -196,7 +199,7 @@ namespace Xunit.Runner.Wpf
throw new NotSupportedException();
}
public bool Contains(T item) => this.filteredList.Contains(item);
public bool Contains(T item) => this.filteredList.BinarySearch(item, sort) >= 0;
public void CopyTo(T[] array, int arrayIndex)
{
@@ -216,7 +219,14 @@ namespace Xunit.Runner.Wpf
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
public int IndexOf(T item) => this.filteredList.IndexOf(item);
public int IndexOf(T item)
{
int location = this.filteredList.BinarySearch(item, sort);
if (location < 0)
return -1;
return location;
}
public void Insert(int index, T item)
{
+29
View File
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
namespace Xunit.Runner.Wpf
{
internal interface ITestAssemblyWatcher
{
/// <summary>
/// Adds a new assembly to list of assemblies to be autoreloaded.
/// </summary>
void AddAssembly(string assemblyFileName);
/// <summary>
/// Removes an assembly from the list of assemblies ot be autoreloaded.
/// </summary>
void RemoveAssembly(string assemblyFileName);
/// <summary>
/// Enables watching of all assemblies.
/// </summary>
/// <param name="reloader">Action to perform when a file change is detected</param>
void EnableWatch(Func<IEnumerable<string>, bool> reloader);
/// <summary>
/// Disables watching of all assemblies
/// </summary>
void DisableWatch();
}
}
+6 -4
View File
@@ -34,14 +34,14 @@ namespace Xunit.Runner.Wpf.Impl
_processInfo = StartWorkerProcess();
}
private async Task<Connection> CreateConnection(string action, string argument)
private async Task<Connection> CreateConnection(string action, string argument, CancellationToken cancellationToken)
{
var pipeName = GetPipeName();
try
{
var stream = new NamedPipeClientStream(pipeName);
await stream.ConnectAsync();
await stream.ConnectAsync(cancellationToken);
var writer = new ClientWriter(stream);
writer.Write(action);
@@ -84,6 +84,8 @@ namespace Xunit.Runner.Wpf.Impl
processStartInfo.FileName = typeof(Xunit.Runner.Worker.Program).Assembly.Location;
processStartInfo.Arguments = $"{pipeName} {Process.GetCurrentProcess().Id}";
processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
processStartInfo.UseShellExecute = false;
processStartInfo.CreateNoWindow = true;
var process = Process.Start(processStartInfo);
return new ProcessInfo(pipeName, process);
}
@@ -101,7 +103,7 @@ namespace Xunit.Runner.Wpf.Impl
private async Task Discover(string assemblyPath, Action<List<TestCaseData>> callback, CancellationToken cancellationToken)
{
var connection = await CreateConnection(Constants.ActionDiscover, assemblyPath);
var connection = await CreateConnection(Constants.ActionDiscover, assemblyPath, cancellationToken);
await ProcessResultsCore(connection, r => r.ReadTestCaseData(), callback, cancellationToken);
RecycleProcess();
@@ -109,7 +111,7 @@ namespace Xunit.Runner.Wpf.Impl
private async Task RunCore(string actionName, string assemblyPath, ImmutableArray<string> testCaseDisplayNames, Action<List<TestResultData>> callback, CancellationToken cancellationToken)
{
var connection = await CreateConnection(actionName, assemblyPath);
var connection = await CreateConnection(actionName, assemblyPath, cancellationToken);
if (!testCaseDisplayNames.IsDefaultOrEmpty)
{
@@ -0,0 +1,206 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
namespace Xunit.Runner.Wpf.Impl
{
internal sealed class TestAssemblyWatcher : ITestAssemblyWatcher
{
private readonly object sync = new object();
private readonly IDictionary<string, FileSystemWatcher> watchedAssemblies = new Dictionary<string, FileSystemWatcher>();
private readonly Dispatcher dispatcher;
private bool isEnabled = false;
private ReloadDebouncer debouncer;
public TestAssemblyWatcher(Dispatcher dispatcher)
{
this.dispatcher = dispatcher;
}
public void AddAssembly(string assemblyFileName)
{
// Assumptions about adding and removing assemblies are broken if this isn't true
Debug.Assert(string.Equals(assemblyFileName, Path.GetFullPath(assemblyFileName), StringComparison.Ordinal));
lock (sync)
{
if (watchedAssemblies.ContainsKey(assemblyFileName))
{
// Already watching this assembly, nothing to do but return
return;
}
FileSystemWatcher watcher = new FileSystemWatcher
{
Path = Path.GetDirectoryName(assemblyFileName),
NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.LastWrite,
Filter = Path.GetFileName(assemblyFileName)
};
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watchedAssemblies[assemblyFileName] = watcher;
if (isEnabled)
{
watcher.EnableRaisingEvents = true;
}
}
}
public void RemoveAssembly(string assemblyFileName)
{
lock (sync)
{
if (watchedAssemblies.ContainsKey(assemblyFileName))
{
watchedAssemblies[assemblyFileName].Dispose();
watchedAssemblies.Remove(assemblyFileName);
}
}
}
public void EnableWatch(Func<IEnumerable<string>, bool> reloader)
{
lock (sync)
{
isEnabled = true;
foreach (var watcher in watchedAssemblies.Values)
{
watcher.EnableRaisingEvents = true;
}
this.debouncer = new ReloadDebouncer(dispatcher, reloader);
}
}
public void DisableWatch()
{
lock (sync)
{
isEnabled = false;
foreach (var watcher in watchedAssemblies.Values)
{
watcher.EnableRaisingEvents = false;
}
this.debouncer?.Cancel();
this.debouncer = null;
}
}
private void OnChanged(object source, FileSystemEventArgs args)
{
debouncer?.AddAssembly(args.FullPath);
}
/// <summary>
/// Because, during a build of a number of projects many file system events will be triggered for potentially many
/// test assemblies, we need to batch our update requests. This class will do this, waiting for 100 ms after receiving
/// a new reload request to send the reload requests. This timer resets every time a reload request is received. Note
/// that if you continuously rebuild, this will technicially never finish batching and nothing will reload, but this
/// assumes that file events will stop at some point.
///
/// If the reloader returns false, meaning that the reload was not kicked off successfully, we back off for a full second
/// before reattempting to queue the updates.
/// </summary>
private class ReloadDebouncer
{
private readonly object sync = new object();
private readonly Dispatcher dispatcher;
private readonly Func<IEnumerable<string>, bool> reloader;
private ISet<string> assembliesToReload = new HashSet<string>();
private bool newAssemblyAdded = false;
private bool running = false;
private bool cancelled = false;
public ReloadDebouncer(Dispatcher dispatcher, Func<IEnumerable<string>, bool> reloader)
{
this.dispatcher = dispatcher;
this.reloader = reloader;
}
public void AddAssembly(string assembly)
{
lock (sync)
{
assembliesToReload.Add(assembly);
if (!Start())
{
newAssemblyAdded = true;
}
}
}
public void Cancel()
{
running = false;
}
private bool Start()
{
if (running)
{
return false;
}
running = true;
Task.Run((Action)Debounce);
return true;
}
private async void Debounce()
{
bool backOff = false;
do
{
await Task.Delay(backOff ? 1000 : 100);
backOff = false;
lock (sync)
{
void Reset()
{
assembliesToReload = new HashSet<string>();
running = false;
}
if (cancelled)
{
Reset();
return;
}
// New assemblies added, so we need to wait again
if (newAssemblyAdded)
{
newAssemblyAdded = false;
continue;
}
// No new assemblies added, time to alert and exit
if (!dispatcher.Invoke(() => reloader(assembliesToReload)))
{
// If the reloader returned false, it's still busy from the last reload request or other user action.
// Back off for a full second to give it time, then continue as previous
backOff = true;
continue;
}
Reset();
}
} while (running);
}
}
}
}
+201 -149
View File
@@ -1,24 +1,25 @@
<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:local="clr-namespace:Xunit.Runner.Wpf"
xmlns:converters="clr-namespace:Xunit.Runner.Wpf.Converters"
xmlns:vm="clr-namespace:Xunit.Runner.Wpf.ViewModel"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Platform"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
DataContext="{Binding Main, Source={StaticResource Locator}}"
Title="xUnit.net Test Runner"
Icon="Artwork\Application.ico"
ResizeMode="CanResizeWithGrip"
Height="600"
MinHeight="525"
Width="525"
MinWidth="425"
Name="Main">
<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">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
@@ -43,12 +44,10 @@
<Menu Grid.Row="0">
<MenuItem Header="_File">
<MenuItem Header="E_xit"
Command="{Binding ExitCommand}" />
<MenuItem Command="{Binding ExitCommand}" Header="E_xit" />
</MenuItem>
<MenuItem Header="_Assembly">
<MenuItem Header="_Open"
Command="ApplicationCommands.Open" />
<MenuItem Command="ApplicationCommands.Open" Header="_Open" />
<MenuItem Header="R_ecent" ItemsSource="{Binding RecentAssemblies}">
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
@@ -59,8 +58,14 @@
</MenuItem.ItemContainerStyle>
</MenuItem>
<Separator />
<MenuItem Header="_Unload" Command="{Binding AssemblyRemoveAllCommand}"/>
<MenuItem Header="_Reload" Command="{Binding AssemblyReloadAllCommand}" />
<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" />
@@ -84,10 +89,11 @@
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<GroupBox Header="Refinements"
Margin="3"
Grid.Column="0"
Grid.Row="0">
<GroupBox
Grid.Row="0"
Grid.Column="0"
Margin="3"
Header="Refinements">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
@@ -98,25 +104,24 @@
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Content="Search:"
Grid.Row="0" />
<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 Content="Assemblies:"
Grid.Row="2" />
<ListBox Height="175"
ItemsSource="{Binding Assemblies}"
SelectionMode="Extended"
Grid.Row="3">
<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}" />
<TextBlock Text=" Discovering tests..."
FontStyle="Italic"
Foreground="Gray">
<TextBlock
FontStyle="Italic"
Foreground="Gray"
Text=" Discovering tests...">
<TextBlock.Style>
<Style TargetType="TextBlock">
@@ -136,41 +141,36 @@
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}"/>
<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Reload" Command="{Binding AssemblyReloadCommand}" />
<MenuItem Header="Reload All" Command="{Binding AssemblyReloadAllCommand}" />
<MenuItem Command="{Binding AssemblyReloadCommand}" Header="Reload" />
<MenuItem Command="{Binding AssemblyReloadAllCommand}" Header="Reload All" />
<Separator />
<MenuItem Header="Remove" Command="{Binding AssemblyRemoveCommand}" />
<MenuItem Header="Remove All" Command="{Binding AssemblyRemoveAllCommand}" />
<MenuItem Command="{Binding AssemblyRemoveCommand}" Header="Remove" />
<MenuItem Command="{Binding AssemblyRemoveAllCommand}" Header="Remove All" />
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
<Label Content="Traits:"
Grid.Row="4" />
<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}">
<HierarchicalDataTemplate DataType="{x:Type vm:TraitViewModel}" ItemsSource="{Binding Children}">
<CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Text}" >
<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}" />
<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}" />
<cmd:EventToCommand Command="{Binding DataContext.TraitCheckedChangedCommand, RelativeSource={RelativeSource AncestorType=Window}}" CommandParameter="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
@@ -186,7 +186,7 @@
<TreeView.ContextMenu>
<ContextMenu>
<MenuItem Header="Clear" Command="{Binding TraitsClearCommand}" />
<MenuItem Command="{Binding TraitsClearCommand}" Header="Clear" />
</ContextMenu>
</TreeView.ContextMenu>
@@ -194,34 +194,40 @@
</Grid>
</GroupBox>
<Grid Grid.Column="0"
Grid.Row="1">
<Grid Grid.Row="1" Grid.Column="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Content="_Run All"
Command="{Binding RunCommand}"
Margin="3"
Grid.Column="0" />
<Button Content="_Cancel"
Command="{Binding CancelCommand}"
Margin="0,3,3,3"
Grid.Column="1" />
<Button
Grid.Column="0"
Margin="10,0,0,0"
Command="{Binding RunAllCommand}"
Content="_Run All" />
<Button
Grid.Column="1"
Command="{Binding RunSelectedCommand}"
Content="Run _Selected" />
<Button
Grid.Column="2"
Margin="0,0,10,0"
Command="{Binding CancelCommand}"
Content="_Cancel" />
</Grid>
<Grid Grid.Column="1"
Grid.Row="0">
<Grid Grid.Row="0" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="*" MinHeight="200px" />
<RowDefinition Height="auto" />
<RowDefinition Height="*" MinHeight="200px"/>
<RowDefinition Height="*" MinHeight="200px" />
</Grid.RowDefinitions>
<GroupBox Header="{Binding TestCasesCaption}"
Margin="3"
Grid.Row="0">
<GroupBox
Grid.Row="0"
Margin="3"
Header="{Binding TestCasesCaption}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
@@ -229,55 +235,82 @@
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<ToggleButton IsChecked="{Binding FilterPassedTests}"
BorderThickness="0"
Background="Transparent"
Margin="0,4,2,4"
Grid.Column="0"
Command="{Binding TestFilterChanged}">
<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 Margin="4,0"
FontSize="16"
Text="{Binding TestsPassed, StringFormat={}{0:#\,0}}"
VerticalAlignment="Center" />
<TextBlock
Margin="4,0"
VerticalAlignment="Center"
FontSize="16"
Text="{Binding TestsPassed, StringFormat={}{0:#\,0}}" />
</StackPanel>
</ToggleButton>
<ToggleButton IsChecked="{Binding FilterFailedTests}"
BorderThickness="0"
Background="Transparent"
Margin="2,4"
Grid.Column="1"
Command="{Binding TestFilterChanged}">
<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 Margin="4,0"
FontSize="16"
Text="{Binding TestsFailed, StringFormat={}{0:#\,0}}"
VerticalAlignment="Center" />
<TextBlock
Margin="4,0"
VerticalAlignment="Center"
FontSize="16"
Text="{Binding TestsFailed, StringFormat={}{0:#\,0}}" />
</StackPanel>
</ToggleButton>
<ToggleButton IsChecked="{Binding FilterSkippedTests}"
BorderThickness="0"
Background="Transparent"
Margin="2,4,0,4"
Grid.Column="2"
Command="{Binding TestFilterChanged}">
<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 Margin="4,0"
FontSize="16"
Text="{Binding TestsSkipped, StringFormat={}{0:#\,0}}"
VerticalAlignment="Center" />
<TextBlock
Margin="4,0"
VerticalAlignment="Center"
FontSize="16"
Text="{Binding TestsSkipped, StringFormat={}{0:#\,0}}" />
</StackPanel>
</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
Margin="4,0"
VerticalAlignment="Center"
FontSize="16"
Text="{Binding TestsRunning, StringFormat={}{0:#\,0}}" />
</StackPanel>
</ToggleButton>
</StackPanel>
<ListBox ItemsSource="{Binding FilteredTestCases}"
SelectionMode="Extended"
Grid.Row="1">
<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>
@@ -286,49 +319,71 @@
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Width="16"
Margin="0,0,2,0"
Source="{Binding Path=State, Mode=OneWay, Converter={StaticResource TestStateConverter}}"
Grid.Column="0" />
<Image
Grid.Column="0"
Width="16"
Margin="0,0,2,0"
Source="{Binding Path=State, Mode=OneWay, Converter={StaticResource TestStateConverter}}" />
<TextBlock Text="{Binding DisplayName}"
VerticalAlignment="Center"
Grid.Column="1" />
<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>
<GridSplitter Grid.Row="1" HorizontalAlignment="Stretch" Height="3" Background="White"/>
<GridSplitter
Grid.Row="1"
Height="3"
HorizontalAlignment="Stretch"
Background="White" />
<GroupBox Header="Output"
Margin="3"
Grid.Row="2">
<TextBox IsReadOnly="True"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Visible"
FontFamily="Consolas"
Text="{Binding Output}"/>
<GroupBox
Grid.Row="2"
Margin="3"
Header="Output">
<TextBox
FontFamily="Consolas"
HorizontalScrollBarVisibility="Auto"
IsReadOnly="True"
Text="{Binding Output}"
VerticalScrollBarVisibility="Visible" />
</GroupBox>
</Grid>
<GridSplitter Grid.Column="0" VerticalAlignment="Stretch" Width="3" Background="White"/>
<ProgressBar Foreground="{Binding Path=CurrentRunState, Converter={StaticResource TestStateConverter}, Mode=OneWay}"
Minimum="0"
Maximum="{Binding MaximumProgress}"
Value="{Binding Path=TestsCompleted}"
Grid.Column="1"
Grid.Row="1"
Margin="3" />
<GridSplitter
Grid.Column="0"
Width="3"
VerticalAlignment="Stretch"
Background="White" />
<ProgressBar
Grid.Row="1"
Grid.Column="1"
Margin="3"
Foreground="{Binding Path=CurrentRunState, Converter={StaticResource TestStateConverter}, Mode=OneWay}"
Maximum="{Binding MaximumProgress}"
Minimum="0"
Value="{Binding Path=TestsCompleted}" />
</Grid>
<StackPanel Grid.Row="2">
<Border BorderBrush="LightGray"
BorderThickness="1"
Margin="3" />
<Border
Margin="3"
BorderBrush="LightGray"
BorderThickness="1" />
<StatusBar>
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
@@ -338,7 +393,7 @@
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="16"/>
<ColumnDefinition Width="16" />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
@@ -346,28 +401,25 @@
<StatusBarItem Grid.Column="1">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Tests passed: "
Foreground="DarkGreen"/>
<TextBlock Foreground="DarkGreen" Text="Tests passed: " />
<TextBlock Text="{Binding TestsPassed, StringFormat={}{0:#\,0}}"/>
<TextBlock Text="{Binding TestsPassed, StringFormat={}{0:#\,0}}" />
</StackPanel>
</StatusBarItem>
<StatusBarItem Grid.Column="2">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Tests failed: "
Foreground="DarkRed"/>
<TextBlock Foreground="DarkRed" Text="Tests failed: " />
<TextBlock Text="{Binding TestsFailed, StringFormat={}{0:#\,0}}"/>
<TextBlock Text="{Binding TestsFailed, StringFormat={}{0:#\,0}}" />
</StackPanel>
</StatusBarItem>
<StatusBarItem Grid.Column="3">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Tests skipped: "
Foreground="DarkGoldenrod"/>
<TextBlock Foreground="DarkGoldenrod" Text="Tests skipped: " />
<TextBlock Text="{Binding TestsSkipped, StringFormat={}{0:#\,0}}"/>
<TextBlock Text="{Binding TestsSkipped, StringFormat={}{0:#\,0}}" />
</StackPanel>
</StatusBarItem>
</StatusBar>
+24
View File
@@ -5,6 +5,9 @@ using Xunit.Runner.Wpf.Persistence;
namespace Xunit.Runner.Wpf
{
using GalaSoft.MvvmLight.Command;
using ViewModel;
public partial class MainWindow : Window
{
public static Window Instance { get; private set; }
@@ -29,5 +32,26 @@ namespace Xunit.Runner.Wpf
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;
}
}
}
}
}
+28 -1
View File
@@ -14,21 +14,24 @@ namespace Xunit.Runner.Wpf.Persistence
private const string RecentAssemblyElementName = "recent_assembly";
private const string SettingsElementName = "settings";
private const string VersionAttributeName = "version";
private const string AutoReloadAssembliesElementName = "auto_reload_assemblies";
private const int MaxRecentAssemblies = 10;
private static readonly Version s_latestVersion = new Version(1, 0, 0, 0);
private List<string> recentAssemblies;
private bool autoReloadAssemblies;
private Settings()
{
recentAssemblies = new List<string>();
autoReloadAssemblies = true;
}
public void AddRecentAssembly(string filePath)
{
for (int i = recentAssemblies.Count - 1; i > 0; i--)
for (int i = recentAssemblies.Count - 1; i >= 0; i--)
{
if (StringComparer.OrdinalIgnoreCase.Equals(recentAssemblies[i], filePath))
{
@@ -44,6 +47,13 @@ namespace Xunit.Runner.Wpf.Persistence
}
}
public void ToggleAutoReloadAssemblies()
{
autoReloadAssemblies = !autoReloadAssemblies;
}
public bool GetAutoReloadAssemblies() => autoReloadAssemblies;
public ImmutableArray<string> GetRecentAssemblies()
{
return this.recentAssemblies.ToImmutableArray();
@@ -66,6 +76,8 @@ namespace Xunit.Runner.Wpf.Persistence
xml.Add(recentAssembliesElement);
}
xml.Add(new XElement(AutoReloadAssembliesElementName, autoReloadAssemblies));
xml.Save(xmlFile);
}
}
@@ -103,6 +115,21 @@ namespace Xunit.Runner.Wpf.Persistence
}
}
var autoReloadAssembliesElement = xml.Element(AutoReloadAssembliesElementName);
if (autoReloadAssembliesElement != null)
{
if (!bool.TryParse(autoReloadAssembliesElement.Value, out var autoReloadAssemblies))
{
autoReloadAssemblies = true;
}
settings.autoReloadAssemblies = autoReloadAssemblies;
}
else
{
settings.autoReloadAssemblies = true;
}
return settings;
}
}
+1 -36
View File
@@ -1,25 +1,4 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// 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: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("xunit.runner.wpf")]
[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)]
using System.Windows;
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
@@ -39,17 +18,3 @@ using System.Windows;
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// 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")]
+243 -51
View File
@@ -12,7 +12,7 @@ using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.CommandWpf;
using GalaSoft.MvvmLight.Command;
using Microsoft.Win32;
using Microsoft.WindowsAPICodePack.Taskbar;
using Xunit.Runner.Data;
@@ -25,26 +25,42 @@ namespace Xunit.Runner.Wpf.ViewModel
private readonly Settings settings;
private readonly ITestUtil testUtil;
private readonly ITestAssemblyWatcher assemblyWatcher;
private readonly HashSet<string> allTestCaseUniqueIDs = new HashSet<string>();
private readonly ObservableCollection<TestCaseViewModel> allTestCases = new ObservableCollection<TestCaseViewModel>();
private readonly TraitCollectionView traitCollectionView = new TraitCollectionView();
private readonly HashSet<string> runningTestSet = new HashSet<string>();
private CancellationTokenSource filterCancellationTokenSource = new CancellationTokenSource();
private CancellationTokenSource cancellationTokenSource;
private bool isBusy;
private SearchQuery searchQuery = new SearchQuery();
private bool autoReloadAssemblies;
public ObservableCollection<TestAssemblyViewModel> Assemblies { get; } = new ObservableCollection<TestAssemblyViewModel>();
public FilteredCollectionView<TestCaseViewModel, SearchQuery> FilteredTestCases { get; }
public ObservableCollection<TraitViewModel> Traits => this.traitCollectionView.Collection;
public bool AutoReloadAssemblies
{
get => autoReloadAssemblies;
set
{
var oldVal = autoReloadAssemblies;
autoReloadAssemblies = value;
RaisePropertyChanged(nameof(AutoReloadAssemblies), oldVal, autoReloadAssemblies);
}
}
public ObservableCollection<RecentAssemblyViewModel> RecentAssemblies { get; } = new ObservableCollection<RecentAssemblyViewModel>();
private ImmutableList<TestCaseViewModel> runningTests;
private ImmutableList<TestCaseViewModel> testsToRun;
public ICommand ExitCommand { get; }
public ICommand WindowLoadedCommand { get; }
public RelayCommand<CancelEventArgs> WindowClosingCommand { get; }
public RelayCommand RunCommand { get; }
public RelayCommand RunAllCommand { get; }
public RelayCommand RunSelectedCommand { get; }
public RelayCommand CancelCommand { get; }
public ICommand TraitCheckedChangedCommand { get; }
public ICommand TraitSelectionChangedCommand { get; }
@@ -53,6 +69,7 @@ namespace Xunit.Runner.Wpf.ViewModel
public ICommand AssemblyReloadAllCommand { get; }
public ICommand AssemblyRemoveCommand { get; }
public ICommand AssemblyRemoveAllCommand { get; }
public ICommand AutoReloadAssembliesCommand { get; }
public CommandBindingCollection CommandBindings { get; }
@@ -68,6 +85,7 @@ namespace Xunit.Runner.Wpf.ViewModel
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<TestCaseViewModel, SearchQuery>(
@@ -78,7 +96,8 @@ namespace Xunit.Runner.Wpf.ViewModel
this.ExitCommand = new RelayCommand(OnExecuteExit);
this.WindowLoadedCommand = new RelayCommand(OnExecuteWindowLoaded);
this.WindowClosingCommand = new RelayCommand<CancelEventArgs>(OnExecuteWindowClosing);
this.RunCommand = new RelayCommand(OnExecuteRun, CanExecuteRun);
this.RunAllCommand = new RelayCommand(OnExecuteRunAll, CanExecuteRunAll);
this.RunSelectedCommand = new RelayCommand(OnExecuteRunSelected, CanExecuteRunSelected);
this.CancelCommand = new RelayCommand(OnExecuteCancel, CanExecuteCancel);
this.TraitCheckedChangedCommand = new RelayCommand<TraitViewModel>(OnExecuteTraitCheckedChanged);
this.TraitsClearCommand = new RelayCommand(OnExecuteTraitsClear);
@@ -86,8 +105,11 @@ namespace Xunit.Runner.Wpf.ViewModel
this.AssemblyReloadAllCommand = new RelayCommand(OnExecuteAssemblyReloadAll);
this.AssemblyRemoveCommand = new RelayCommand(OnExecuteAssemblyRemove, CanExecuteAssemblyRemove);
this.AssemblyRemoveAllCommand = new RelayCommand(OnExecuteAssemblyRemoveAll);
this.AutoReloadAssembliesCommand = new RelayCommand(OnToggleAutoReloadAssemblies);
RebuildRecentAssembliesMenu();
AutoReloadAssemblies = this.settings.GetAutoReloadAssemblies();
UpdateAutoReloadStatus();
}
private void RebuildRecentAssembliesMenu()
@@ -133,10 +155,13 @@ namespace Xunit.Runner.Wpf.ViewModel
}
}
var noFilter = !(searchQuery.FilterFailedTests | searchQuery.FilterPassedTests | searchQuery.FilterSkippedTests);
var noFilter = !(searchQuery.FilterRunningTests | searchQuery.FilterFailedTests | searchQuery.FilterPassedTests | searchQuery.FilterSkippedTests);
switch (testCase.State)
{
case TestState.Running:
return noFilter || searchQuery.FilterRunningTests;
case TestState.Passed:
return noFilter || searchQuery.FilterPassedTests;
@@ -157,8 +182,32 @@ namespace Xunit.Runner.Wpf.ViewModel
private void TestCases_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
TestCasesCaption = $"Test Cases ({FilteredTestCases.Count:#,0})";
MaximumProgress = FilteredTestCases.Count;
UpdateTestCaseInfo(useSelected: false);
ClearSelectionFlags();
}
private void ClearSelectionFlags()
{
foreach (var test in this.allTestCases)
{
test.IsSelected = false;
}
}
void UpdateTestCaseInfo(bool useSelected)
{
var count = FilteredTestCases.Count;
if (useSelected)
{
var selected = FilteredTestCases.Count(tc => tc.IsSelected);
if (selected > 0)
{
count = selected;
}
}
TestCasesCaption = $"Test Cases ({count:#,0})";
MaximumProgress = count;
}
public List<TestAssemblyViewModel> SelectedAssemblies
@@ -177,14 +226,32 @@ namespace Xunit.Runner.Wpf.ViewModel
public int TestsCompleted
{
get { return testsCompleted; }
set { Set(ref testsCompleted, value);
if (TaskbarManager.IsPlatformSupported)
{
var tb = TaskbarManager.Instance;
tb.SetProgressState(GetTaskBarState());
tb.SetProgressValue(value, this.MaximumProgress);
}
set
{
Set(ref testsCompleted, value);
UpdateProgress();
}
}
private TestCaseViewModel selectedTest;
public TestCaseViewModel SelectedTestCase
{
get { return selectedTest; }
set
{
Set(ref selectedTest, value);
}
}
private void UpdateProgress()
{
if (TaskbarManager.IsPlatformSupported)
{
var tb = TaskbarManager.Instance;
tb.SetProgressState(GetTaskBarState());
tb.SetProgressValue(this.TestsCompleted, this.MaximumProgress);
}
}
@@ -201,6 +268,13 @@ namespace Xunit.Runner.Wpf.ViewModel
}
}
private int testsRunning = 0;
public int TestsRunning
{
get { return testsRunning; }
set { Set(ref testsRunning, value); }
}
private int testsPassed = 0;
public int TestsPassed
{
@@ -226,14 +300,24 @@ namespace Xunit.Runner.Wpf.ViewModel
public int MaximumProgress
{
get { return maximumProgress; }
set { Set(ref maximumProgress, value); }
set
{
Set(ref maximumProgress, value);
UpdateProgress();
}
}
private TestState currentRunState;
public TestState CurrentRunState
{
get { return currentRunState; }
set { Set(ref currentRunState, value); }
set
{
Set(ref currentRunState, value);
UpdateProgress();
}
}
private string output = string.Empty;
@@ -336,12 +420,26 @@ namespace Xunit.Runner.Wpf.ViewModel
foreach (var assemblyViewModel in newAssemblyViewModels)
{
assemblyViewModel.State = AssemblyState.Ready;
assemblyWatcher.AddAssembly(assemblyViewModel.FileName);
}
RebuildRecentAssembliesMenu();
}
}
public bool ReloadAssemblies(IEnumerable<string> assemblies)
{
if (IsBusy)
{
return false;
}
var testAssemblies = Assemblies.Where(assembly => assemblies.Contains(assembly.FileName));
Application.Current.Dispatcher.InvokeAsync(() => ReloadAssemblies(testAssemblies));
return true;
}
private async Task ReloadAssemblies(IEnumerable<TestAssemblyViewModel> assemblies)
{
try
@@ -377,6 +475,7 @@ namespace Xunit.Runner.Wpf.ViewModel
{
foreach (var assembly in assemblies.ToList())
{
assemblyWatcher.RemoveAssembly(assembly.FileName);
RemoveAssemblyTestCases(assembly.FileName);
Assemblies.Remove(assembly);
}
@@ -391,6 +490,7 @@ namespace Xunit.Runner.Wpf.ViewModel
{
if (string.Compare(this.allTestCases[i].AssemblyFileName, assemblyPath, StringComparison.OrdinalIgnoreCase) == 0)
{
this.allTestCaseUniqueIDs.Remove(this.allTestCases[i].UniqueID);
this.allTestCases.RemoveAt(i);
}
else
@@ -401,10 +501,10 @@ namespace Xunit.Runner.Wpf.ViewModel
}
/// <summary>
/// Reloading an assembly could have changed the traits. There is no easy way
/// to selectively edit this list (traits can cross assembly boundaries). Just
/// Reloading an assembly could have changed the traits. There is no easy way
/// to selectively edit this list (traits can cross assembly boundaries). Just
/// do a full reload instead.
/// way to
/// way to
/// </summary>
private void RebuildTraits()
{
@@ -421,7 +521,8 @@ namespace Xunit.Runner.Wpf.ViewModel
set
{
isBusy = value;
RunCommand.RaiseCanExecuteChanged();
RunAllCommand.RaiseCanExecuteChanged();
RunSelectedCommand.RaiseCanExecuteChanged();
CancelCommand.RaiseCanExecuteChanged();
}
}
@@ -463,61 +564,87 @@ namespace Xunit.Runner.Wpf.ViewModel
=> (fileName?.EndsWith(".config", StringComparison.OrdinalIgnoreCase) ?? false) ||
(fileName?.EndsWith(".json", StringComparison.OrdinalIgnoreCase) ?? false);
private bool CanExecuteRun()
private bool CanExecuteRunAll()
=> !IsBusy && FilteredTestCases.Any();
private async void OnExecuteRun()
private bool CanExecuteRunSelected()
=> !IsBusy && SelectedTestCase != null;
private async void OnExecuteRunAll()
{
Debug.Assert(this.runningTests == null);
Debug.Assert(this.testsToRun == null);
UpdateTestCaseInfo(useSelected: false);
await ExecuteTestSessionOperation(RunTests);
await ExecuteTestSessionOperation(RunFilteredTests);
this.runningTests = null;
this.testsToRun = null;
}
private List<Task> RunTests()
private List<Task> RunFilteredTests()
{
return RunTests(FilteredTestCases.ToImmutableList());
}
private async void OnExecuteRunSelected()
{
Debug.Assert(this.testsToRun == null);
Debug.Assert(this.SelectedTestCase != null);
UpdateTestCaseInfo(useSelected: true);
await ExecuteTestSessionOperation(RunSelectedTests);
this.testsToRun = null;
}
private List<Task> RunSelectedTests()
{
return RunTests(ImmutableList.CreateRange(this.FilteredTestCases.Where(tc => tc.IsSelected)));
}
private List<Task> RunTests(ImmutableList<TestCaseViewModel> tests)
{
Debug.Assert(this.isBusy);
Debug.Assert(this.cancellationTokenSource != null);
Debug.Assert(this.runningTests == null);
Debug.Assert(this.testsToRun == null);
TestsCompleted = 0;
TestsRunning = 0;
TestsPassed = 0;
TestsFailed = 0;
TestsSkipped = 0;
CurrentRunState = TestState.NotRun;
Output = string.Empty;
this.runningTests = FilteredTestCases.ToImmutableList();
this.testsToRun = tests;
foreach (var tc in this.runningTests)
foreach (var tc in this.testsToRun)
{
tc.State = TestState.NotRun;
}
var runAll = this.runningTests.Count == this.allTestCases.Count;
var runAll = this.testsToRun.Count == this.allTestCases.Count;
var testSessionList = new List<Task>();
foreach (var assemblyFileName in this.runningTests.Select(x => x.AssemblyFileName).Distinct())
foreach (var assemblyFileName in this.testsToRun.Select(x => x.AssemblyFileName).Distinct())
{
Task task;
if (runAll)
{
task = this.testUtil.RunAll(assemblyFileName, OnTestsFinished, this.cancellationTokenSource.Token);
task = this.testUtil.RunAll(assemblyFileName, OnTestStateChange, this.cancellationTokenSource.Token);
}
else
{
var builder = ImmutableArray.CreateBuilder<string>();
foreach (var testCase in this.runningTests)
foreach (var testCase in this.testsToRun)
{
if (testCase.AssemblyFileName == assemblyFileName)
{
builder.Add(testCase.DisplayName);
builder.Add(testCase.UniqueID);
}
}
task = this.testUtil.RunSpecific(assemblyFileName, builder.ToImmutable(), OnTestsFinished, this.cancellationTokenSource.Token);
task = this.testUtil.RunSpecific(assemblyFileName, builder.ToImmutable(), OnTestStateChange, this.cancellationTokenSource.Token);
}
testSessionList.Add(task);
@@ -557,6 +684,9 @@ namespace Xunit.Runner.Wpf.ViewModel
foreach (var testCase in testCases)
{
if (this.allTestCaseUniqueIDs.Contains(testCase.UniqueID))
continue;
traitWorkerList.Clear();
// Get or create traits.
@@ -579,6 +709,7 @@ namespace Xunit.Runner.Wpf.ViewModel
var testCaseViewModel = new TestCaseViewModel(
testCase.DisplayName,
testCase.UniqueID,
testCase.SkipReason,
testCase.AssemblyPath,
traitWorkerList);
@@ -588,32 +719,48 @@ namespace Xunit.Runner.Wpf.ViewModel
TestsSkipped++;
}
this.allTestCaseUniqueIDs.Add(testCase.UniqueID);
this.allTestCases.Add(testCaseViewModel);
}
}
private void OnTestsFinished(IEnumerable<TestResultData> testResultData)
private void OnTestStateChange(IEnumerable<TestResultData> testResultData)
{
Debug.Assert(this.runningTests != null);
Debug.Assert(this.testsToRun != null);
foreach (var result in testResultData)
{
var testCase = this.runningTests.Single(x => x.DisplayName == result.TestCaseDisplayName);
var testCase = this.testsToRun.Single(x => x.UniqueID == result.TestCaseUniqueID);
testCase.State = result.TestState;
TestsCompleted++;
switch (result.TestState)
if (result.TestState == TestState.Running)
{
case TestState.Passed:
TestsPassed++;
break;
case TestState.Failed:
TestsFailed++;
Output = Output + result.Output;
break;
case TestState.Skipped:
TestsSkipped++;
break;
if (runningTestSet.Add(result.TestCaseUniqueID))
{
TestsRunning++;
}
}
else
{
if (runningTestSet.Remove(result.TestCaseUniqueID))
{
TestsRunning--;
}
TestsCompleted++;
switch (result.TestState)
{
case TestState.Passed:
TestsPassed++;
break;
case TestState.Failed:
TestsFailed++;
Output = Output + result.Output;
break;
case TestState.Skipped:
TestsSkipped++;
break;
}
}
if (result.TestState > CurrentRunState)
@@ -677,6 +824,41 @@ namespace Xunit.Runner.Wpf.ViewModel
{
RemoveAssemblies(Assemblies.ToArray());
}
private void OnToggleAutoReloadAssemblies()
{
ToggleReloadAssemblies();
}
private void ToggleReloadAssemblies()
{
this.settings.ToggleAutoReloadAssemblies();
AutoReloadAssemblies = this.settings.GetAutoReloadAssemblies();
UpdateAutoReloadStatus();
}
private void UpdateAutoReloadStatus()
{
if (AutoReloadAssemblies)
{
assemblyWatcher.EnableWatch(ReloadAssemblies);
}
else
{
assemblyWatcher.DisableWatch();
}
}
public bool FilterRunningTests
{
get { return searchQuery.FilterRunningTests; }
set
{
if (Set(ref searchQuery.FilterRunningTests, value))
{
FilterAfterDelay();
}
}
}
public bool FilterPassedTests
{
@@ -720,7 +902,17 @@ namespace Xunit.Runner.Wpf.ViewModel
public static TestComparer Instance { get; } = new TestComparer();
public int Compare(TestCaseViewModel x, TestCaseViewModel y)
=> StringComparer.Ordinal.Compare(x.DisplayName, y.DisplayName);
{
int result = StringComparer.OrdinalIgnoreCase.Compare(x.DisplayName, y.DisplayName);
if (result != 0)
return result;
result = StringComparer.Ordinal.Compare(x.DisplayName, y.DisplayName);
if (result != 0)
return result;
return StringComparer.Ordinal.Compare(x.UniqueID, y.UniqueID);
}
private TestComparer() { }
}
@@ -4,6 +4,7 @@ namespace Xunit.Runner.Wpf.ViewModel
{
public class SearchQuery
{
public bool FilterRunningTests = false;
public bool FilterFailedTests = false;
public bool FilterPassedTests = false;
public bool FilterSkippedTests = false;
@@ -10,9 +10,11 @@ namespace Xunit.Runner.Wpf.ViewModel
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);
@@ -22,9 +24,10 @@ namespace Xunit.Runner.Wpf.ViewModel
set { Set(ref _state, value); }
}
public TestCaseViewModel(string displayName, string skipReason, string assemblyFileName, IEnumerable<TraitViewModel> traits)
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();
@@ -12,8 +12,8 @@
See http://www.galasoft.ch/mvvm
*/
using CommonServiceLocator;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;
namespace Xunit.Runner.Wpf.ViewModel
{
-20
View File
@@ -1,20 +0,0 @@
<?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="3.4.3" targetFramework="net46" developmentDependency="true" />
<package id="System.Collections" version="4.0.10" targetFramework="net46" />
<package id="System.Collections.Immutable" version="1.1.37" targetFramework="net452" />
<package id="System.Diagnostics.Debug" version="4.0.10" targetFramework="net46" />
<package id="System.Globalization" version="4.0.10" targetFramework="net46" />
<package id="System.Linq" version="4.0.0" targetFramework="net46" />
<package id="System.Resources.ResourceManager" version="4.0.0" targetFramework="net46" />
<package id="System.Runtime" version="4.0.20" targetFramework="net46" />
<package id="System.Runtime.Extensions" version="4.0.10" targetFramework="net46" />
<package id="System.Threading" version="4.0.10" targetFramework="net46" />
<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" />
</packages>
+31 -186
View File
@@ -1,201 +1,46 @@
<?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')" />
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{34FB519C-FB49-4B31-ACA2-7F7879311BCF}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UseWpf>true</UseWpf>
<RootNamespace>Xunit.Runner.Wpf</RootNamespace>
<AssemblyName>xunit.runner.wpf</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<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>
<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>
<PropertyGroup>
<NoWarn>NU1701;$(NoWarn)</NoWarn>
<ApplicationIcon>Artwork\Application.ico</ApplicationIcon>
<Authors>Pilchie</Authors>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackAsTool>true</PackAsTool>
<AssetTargetFallback>net472</AssetTargetFallback>
<Description>XUnit Gui written in WPF</Description>
<PackageProjectUrl>https://github.com/Pilchie/xunit.runner.wpf</PackageProjectUrl>
<RepositoryUrl>https://github.com/Pilchie/xunit.runner.wpf</RepositoryUrl>
<PackageTags>XUnit Gui test runner</PackageTags>
<NeutralLanguage>en-us</NeutralLanguage>
<PackageVersion Condition="'$(appveyor_build_vzersion)' != ''">$(appveyor_build_version)</PackageVersion>
<PackageVersion Condition="'$(NuPkgVersion)' == ''">1.0.0-local</PackageVersion>
<AssemblyVersion Condition="'$(appveyor_build_version)' != ''">$(appveyor_build_version)</AssemblyVersion>
<FileVersion Condition="'$(appveyor_build_version)' != ''">$(appveyor_build_version)</FileVersion>
</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>
<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>
<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>
<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>
<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>
<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.1.37.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Collections.Immutable.1.1.37\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Data" />
<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>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<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>
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="CommandBindings.cs" />
<Compile Include="Converters\TestStateConverter.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="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="ViewModel\AssemblyAndConfigFile.cs" />
<Compile Include="ViewModel\MainViewModel.cs" />
<Compile Include="ViewModel\SearchQuery.cs" />
<Compile Include="ViewModel\TestCaseViewModel.cs" />
<Compile Include="ViewModel\TestAssemblyViewModel.cs" />
<Compile Include="ViewModel\TraitViewModel.Comparer.cs" />
<Compile Include="ViewModel\TraitViewModel.cs" />
<Compile Include="ViewModel\ViewModelLocator.cs" />
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</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.nuspec">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<PackageReference Include="CommonServiceLocator" Version="2.0.2" />
<PackageReference Include="Microsoft.Windows.Compatibility" Version="2.1.0-preview.18571.3" />
<PackageReference Include="MvvmLightLibs" Version="5.4.1.1" />
<PackageReference Include="System.Collections.Immutable" Version="1.4.0-preview1-25305-02" />
<PackageReference Include="System.Windows.Interactivity.WPF" Version="2.0.20525" />
<PackageReference Include="WindowsAPICodePack" Version="1.1.0" />
</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>
</ItemGroup>
<ItemGroup>
<Resource Include="Artwork\Passed_small.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Artwork\Passed_large.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Artwork\Failed_small.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Artwork\Failed_large.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Artwork\Skipped_small.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Artwork\Skipped_large.png" />
<ProjectReference Include="..\xunit.runner.data\xunit.runner.data.csproj" />
<ProjectReference Include="..\xunit.runner.worker\xunit.runner.worker.csproj" />
</ItemGroup>
<ItemGroup>
<Resource Include="Artwork\**\*.png" />
<Resource Include="Artwork\Application.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="AfterBuild">
<Exec Command="&quot;$(SolutionDir)packages\NuGet.CommandLine.3.4.3\tools\NuGet.exe&quot; pack xunit.runner.wpf.nuspec -Version $(NuPkgVersion) -OutputDirectory ." WorkingDirectory="$(OutDir)" LogStandardErrorAsError="true" ConsoleToMSBuild="true">
<Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" />
</Exec>
</Target>
</Project>
</Project>
-19
View File
@@ -1,19 +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="*.dll" target="tools\"/>
<file src="*.exe" target="tools\" exclude="*vshost*"/>
<file src="*.config" target="tools\" exclude="*vshost*"/>
</files>
</package>