Progress bar and test state UI
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using xunit.runner.wpf.ViewModel;
|
||||
|
||||
namespace xunit.runner.wpf.Converters
|
||||
{
|
||||
public class TestStateConverter : IValueConverter
|
||||
{
|
||||
private static ImageSource passedSource;
|
||||
private static ImageSource failedSource;
|
||||
private static ImageSource skippedSource;
|
||||
static TestStateConverter()
|
||||
{
|
||||
passedSource = LoadResourceImage("Passed.ico");
|
||||
failedSource = LoadResourceImage("Failed.ico");
|
||||
skippedSource = LoadResourceImage("Skipped.ico");
|
||||
}
|
||||
|
||||
private static BitmapImage LoadResourceImage(string resourceName)
|
||||
{
|
||||
var image = new BitmapImage();
|
||||
image.BeginInit();
|
||||
image.UriSource = new Uri("pack://application:,,,/xunit.runner.wpf;component/Artwork/" + resourceName);
|
||||
image.EndInit();
|
||||
return image;
|
||||
}
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var state = (TestState)value;
|
||||
if (targetType == typeof(Brush))
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case TestState.Failed:
|
||||
return Brushes.Red;
|
||||
case TestState.Skipped:
|
||||
return Brushes.Yellow;
|
||||
case TestState.Passed:
|
||||
return Brushes.Green;
|
||||
default:
|
||||
return Brushes.Gray;
|
||||
}
|
||||
}
|
||||
else if (targetType == typeof(ImageSource))
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case TestState.Failed:
|
||||
return failedSource;
|
||||
case TestState.Skipped:
|
||||
return skippedSource;
|
||||
case TestState.Passed:
|
||||
return passedSource;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
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"
|
||||
mc:Ignorable="d"
|
||||
DataContext="{Binding Main, Source={StaticResource Locator}}"
|
||||
@@ -13,6 +14,10 @@
|
||||
Height="600"
|
||||
Width="525">
|
||||
|
||||
<Window.Resources>
|
||||
<converters:TestStateConverter x:Key="TestStateConverter" />
|
||||
</Window.Resources>
|
||||
|
||||
<Grid local:CommandBindings.Registration="{Binding CommandBindings}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto" />
|
||||
@@ -147,12 +152,14 @@
|
||||
<DataTemplate DataType="vm:TestCaseViewModel">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="50" />
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Text="{Binding State}"
|
||||
Grid.Column="0" />
|
||||
<Image Width="16"
|
||||
Margin="2"
|
||||
Source="{Binding Path=State, Mode=OneWay, Converter={StaticResource TestStateConverter}}"
|
||||
Grid.Column="0" />
|
||||
<TextBlock Text="{Binding DisplayName}"
|
||||
Grid.Column="1" />
|
||||
</Grid>
|
||||
@@ -171,11 +178,11 @@
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
|
||||
<ProgressBar
|
||||
Minimum="0"
|
||||
Maximum="{Binding MaximumProgress}"
|
||||
Value="{Binding Path=TestsCompleted}"
|
||||
Grid.Column="1"
|
||||
<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" />
|
||||
</Grid>
|
||||
|
||||
@@ -76,6 +76,13 @@ namespace xunit.runner.wpf.ViewModel
|
||||
set { Set(ref maximumProgress, value); }
|
||||
}
|
||||
|
||||
private TestState currentRunState;
|
||||
public TestState CurrentRunState
|
||||
{
|
||||
get { return currentRunState; }
|
||||
set { Set(ref currentRunState, value); }
|
||||
}
|
||||
|
||||
private string searchQuery = string.Empty;
|
||||
public string SearchQuery
|
||||
{
|
||||
@@ -204,7 +211,7 @@ namespace xunit.runner.wpf.ViewModel
|
||||
private readonly Func<bool> isCancelRequested;
|
||||
private readonly IEnumerable<TestCaseViewModel> testCases;
|
||||
|
||||
public event EventHandler TestFinished;
|
||||
public event EventHandler<TestStateEventArgs> TestFinished;
|
||||
|
||||
public TestRunVisitor(IEnumerable<TestCaseViewModel> testCases, Func<bool> isCancelRequested)
|
||||
{
|
||||
@@ -216,7 +223,7 @@ namespace xunit.runner.wpf.ViewModel
|
||||
{
|
||||
var testCase = testCases.Single(tc => tc.DisplayName == testFailed.TestCase.DisplayName);
|
||||
testCase.State = TestState.Failed;
|
||||
TestFinished?.Invoke(this, EventArgs.Empty);
|
||||
TestFinished?.Invoke(this, TestStateEventArgs.Failed);
|
||||
return !isCancelRequested();
|
||||
}
|
||||
|
||||
@@ -224,7 +231,7 @@ namespace xunit.runner.wpf.ViewModel
|
||||
{
|
||||
var testCase = testCases.Single(tc => tc.DisplayName == testPassed.TestCase.DisplayName);
|
||||
testCase.State = TestState.Passed;
|
||||
TestFinished?.Invoke(this, EventArgs.Empty);
|
||||
TestFinished?.Invoke(this, TestStateEventArgs.Passed);
|
||||
return !isCancelRequested();
|
||||
}
|
||||
|
||||
@@ -232,7 +239,7 @@ namespace xunit.runner.wpf.ViewModel
|
||||
{
|
||||
var testCase = testCases.Single(tc => tc.DisplayName == testSkipped.TestCase.DisplayName);
|
||||
testCase.State = TestState.Skipped;
|
||||
TestFinished?.Invoke(this, EventArgs.Empty);
|
||||
TestFinished?.Invoke(this, TestStateEventArgs.Skipped);
|
||||
return !isCancelRequested();
|
||||
}
|
||||
}
|
||||
@@ -312,9 +319,13 @@ namespace xunit.runner.wpf.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
private void TestRunVisitor_TestFinished(object sender, EventArgs e)
|
||||
private void TestRunVisitor_TestFinished(object sender, TestStateEventArgs e)
|
||||
{
|
||||
TestsCompleted++;
|
||||
if (e.State > CurrentRunState)
|
||||
{
|
||||
CurrentRunState = e.State;
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanExecuteCancel() => IsBusy && !IsCancelRequested;
|
||||
@@ -325,13 +336,17 @@ namespace xunit.runner.wpf.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Note: More severe states are higher numbers.
|
||||
/// <see cref="MainViewModel.TestRunVisitor_TestFinished(object, TestStateEventArgs)"/>
|
||||
/// </summary>
|
||||
public enum TestState
|
||||
{
|
||||
All = 0,
|
||||
NotRun,
|
||||
Passed,
|
||||
Failed,
|
||||
Skipped,
|
||||
NotRun
|
||||
Failed,
|
||||
}
|
||||
|
||||
public class TestComparer : IComparer<TestCaseViewModel>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
|
||||
namespace xunit.runner.wpf.ViewModel
|
||||
{
|
||||
public class TestStateEventArgs : EventArgs
|
||||
{
|
||||
public static TestStateEventArgs Failed { get; } = new TestStateEventArgs(TestState.Failed);
|
||||
public static TestStateEventArgs Passed { get; } = new TestStateEventArgs(TestState.Passed);
|
||||
public static TestStateEventArgs Skipped { get; } = new TestStateEventArgs(TestState.Skipped);
|
||||
private TestStateEventArgs(TestState state)
|
||||
{
|
||||
this.State = state;
|
||||
}
|
||||
|
||||
public TestState State { get; }
|
||||
}
|
||||
}
|
||||
@@ -91,11 +91,13 @@
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Compile Include="CommandBindings.cs" />
|
||||
<Compile Include="Converters\TestStateConverter.cs" />
|
||||
<Compile Include="Extensions.cs" />
|
||||
<Compile Include="FilteredCollectionView.cs" />
|
||||
<Compile Include="ViewModel\MainViewModel.cs" />
|
||||
<Compile Include="ViewModel\TestCaseViewModel.cs" />
|
||||
<Compile Include="ViewModel\TestAssemblyViewModel.cs" />
|
||||
<Compile Include="ViewModel\TestStateEventArgs.cs" />
|
||||
<Compile Include="ViewModel\ViewModelLocator.cs" />
|
||||
<Page Include="MainWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
Reference in New Issue
Block a user