diff --git a/xunit.runner.wpf/Converters/TestStateConverter.cs b/xunit.runner.wpf/Converters/TestStateConverter.cs new file mode 100644 index 0000000..d267326 --- /dev/null +++ b/xunit.runner.wpf/Converters/TestStateConverter.cs @@ -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(); + } + } +} diff --git a/xunit.runner.wpf/MainWindow.xaml b/xunit.runner.wpf/MainWindow.xaml index 4c22284..67fd2e6 100644 --- a/xunit.runner.wpf/MainWindow.xaml +++ b/xunit.runner.wpf/MainWindow.xaml @@ -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"> + + + + @@ -147,12 +152,14 @@ - + - + @@ -171,11 +178,11 @@ - diff --git a/xunit.runner.wpf/ViewModel/MainViewModel.cs b/xunit.runner.wpf/ViewModel/MainViewModel.cs index ee7a24c..849d940 100644 --- a/xunit.runner.wpf/ViewModel/MainViewModel.cs +++ b/xunit.runner.wpf/ViewModel/MainViewModel.cs @@ -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 isCancelRequested; private readonly IEnumerable testCases; - public event EventHandler TestFinished; + public event EventHandler TestFinished; public TestRunVisitor(IEnumerable testCases, Func 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 } } + /// + /// Note: More severe states are higher numbers. + /// + /// public enum TestState { All = 0, + NotRun, Passed, - Failed, Skipped, - NotRun + Failed, } public class TestComparer : IComparer diff --git a/xunit.runner.wpf/ViewModel/TestStateEventArgs.cs b/xunit.runner.wpf/ViewModel/TestStateEventArgs.cs new file mode 100644 index 0000000..aaf1949 --- /dev/null +++ b/xunit.runner.wpf/ViewModel/TestStateEventArgs.cs @@ -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; } + } +} \ No newline at end of file diff --git a/xunit.runner.wpf/xunit.runner.wpf.csproj b/xunit.runner.wpf/xunit.runner.wpf.csproj index 45b5a4e..82671af 100644 --- a/xunit.runner.wpf/xunit.runner.wpf.csproj +++ b/xunit.runner.wpf/xunit.runner.wpf.csproj @@ -91,11 +91,13 @@ Designer + + MSBuild:Compile