Commit 6d05e428 authored by Ghislain MARY's avatar Ghislain MARY

Redesign UI of tester on Windows 10.

parent fdf3bac2
<Application
x:Class="belle_sip_tester.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:belle_sip_tester"
xmlns:model="using:belle_sip_tester.DataModel" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
x:Class="belle_sip_tester.App"
RequestedTheme="Light">
<Application.Resources>
<ResourceDictionary>
<model:UnitTestCaseStateToSymbolConverter x:Key="UnitTestCaseStateToSymbol"/>
<model:UnitTestCaseStateToSymbolColorConverter x:Key="UnitTestCaseStateToSymbolColor"/>
<model:OutputTraceLevelToColorConverter x:Key="OutputTraceLevelToColor"/>
</ResourceDictionary>
</Application.Resources>
</Application>
......@@ -41,8 +41,6 @@ namespace belle_sip_tester
this.InitializeComponent();
this.Suspending += OnSuspending;
run();
}
/// <summary>
......@@ -114,32 +112,5 @@ namespace belle_sip_tester
//TODO: Save application state and stop any background activity
deferral.Complete();
}
private async void run()
{
try
{
await ApplicationData.Current.LocalFolder.GetFileAsync("autolaunch");
tester = new BelleSipTester(true);
if (tester.AsyncAction != null)
{
tester.AsyncAction.Completed += (asyncInfo, asyncStatus) => {
Current.Exit();
};
}
}
catch (Exception)
{
tester = new BelleSipTester(false);
}
}
public bool suiteRunning()
{
return (suiteRunner != null) && (suiteRunner.running);
}
public BelleSipTester tester { get; set; }
public UnitTestSuiteRunner suiteRunner { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using belle_sip_tester_runtime_component;
using System.Collections.ObjectModel;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
using System.ComponentModel;
using Windows.UI;
using Windows.UI.Xaml.Documents;
using Windows.UI.Core;
namespace belle_sip_tester.DataModel
{
public class OutputTrace
{
public OutputTrace(String lev, String msg)
{
Level = lev;
Msg = msg;
}
public String Level { get; private set; }
public String Msg { get; private set; }
}
public class UnitTestSuite
{
public UnitTestSuite(string name)
{
Name = name;
Cases = new ObservableCollection<UnitTestCase>();
Selected = false;
}
public string Name { get; private set; }
public bool Selected
{
get { return Cases.All(x => x.Selected); }
set
{
foreach (UnitTestCase c in Cases)
{
c.Selected = value;
}
}
}
public ObservableCollection<UnitTestCase> Cases { get; private set; }
}
public enum UnitTestCaseState
{
NotRun,
Success,
Failure
}
public class UnitTestCase : INotifyPropertyChanged
{
public UnitTestCase(UnitTestSuite suite, string name)
{
_suite = new WeakReference(suite);
Name = name;
Selected = false;
State = UnitTestCaseState.NotRun;
Traces = new ObservableCollection<OutputTrace>();
}
public UnitTestSuite Suite
{
get { return _suite.Target as UnitTestSuite; }
}
public string Name { get; private set; }
public bool Selected
{
get { return _selected; }
set
{
_selected = value;
RaisePropertyChanged("Selected");
}
}
public UnitTestCaseState State
{
get { return _state; }
set
{
_state = value;
RaisePropertyChanged("State");
}
}
public ObservableCollection<OutputTrace> Traces
{
get { return _traces; }
set
{
_traces = value;
RaisePropertyChanged("Traces");
}
}
public CoreDispatcher Dispatcher { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
private WeakReference _suite;
private bool _selected;
private UnitTestCaseState _state;
private ObservableCollection<OutputTrace> _traces;
}
public sealed class UnitTestDataSource
{
private static UnitTestDataSource _unitTestDataSource = new UnitTestDataSource();
private ObservableCollection<UnitTestSuite> _suites = new ObservableCollection<UnitTestSuite>();
public ObservableCollection<UnitTestSuite> Suites
{
get { return this._suites; }
}
public static IEnumerable<UnitTestSuite> GetSuites(BelleSipTester tester)
{
return _unitTestDataSource.FillSuites(tester);
}
private IEnumerable<UnitTestSuite> FillSuites(BelleSipTester tester)
{
if (this.Suites.Count != 0) return this.Suites;
for (int i = 0; i < tester.nbTestSuites(); i++)
{
UnitTestSuite suite = new UnitTestSuite(tester.testSuiteName(i));
for (int j = 0; j < tester.nbTests(suite.Name); j++)
{
suite.Cases.Add(new UnitTestCase(suite, tester.testName(suite.Name, j)));
}
this.Suites.Add(suite);
}
return this.Suites;
}
}
public sealed class UnitTestCaseStateToSymbolConverter : IValueConverter
{
object IValueConverter.Convert(object value, Type targetType, object parametr, string language)
{
if (!value.GetType().Equals(typeof(UnitTestCaseState)))
{
throw new ArgumentException("Only UnitTestCaseState is supported");
}
if (targetType.Equals(typeof(Symbol)))
{
switch ((UnitTestCaseState)value)
{
case UnitTestCaseState.Success:
return Symbol.Like;
case UnitTestCaseState.Failure:
return Symbol.Dislike;
case UnitTestCaseState.NotRun:
default:
return Symbol.Help;
}
}
else
{
throw new ArgumentException(string.Format("Unsupported type {0}", targetType.FullName));
}
}
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
public sealed class UnitTestCaseStateToSymbolColorConverter : IValueConverter
{
object IValueConverter.Convert(object value, Type targetType, object parameter, string language)
{
if (!value.GetType().Equals(typeof(UnitTestCaseState)))
{
throw new ArgumentException("Only UnitTestCaseState is supported");
}
if (targetType.Equals(typeof(Brush)))
{
switch ((UnitTestCaseState)value)
{
case UnitTestCaseState.Success:
return new SolidColorBrush(Colors.ForestGreen);
case UnitTestCaseState.Failure:
return new SolidColorBrush(Colors.IndianRed);
case UnitTestCaseState.NotRun:
default:
return new SolidColorBrush(Colors.LightGray);
}
}
else
{
throw new ArgumentException(string.Format("Unsupported format {0}", targetType.FullName));
}
}
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
public sealed class OutputTraceLevelToColorConverter : IValueConverter
{
object IValueConverter.Convert(object value, Type targetType, object parameter, string language)
{
if (!value.GetType().Equals(typeof(String)))
{
throw new ArgumentException("Only String is supported");
}
if (targetType.Equals(typeof(Brush)))
{
if ((String)value == "Error")
{
return new SolidColorBrush(Colors.IndianRed);
}
else if ((String)value == "Warning")
{
return new SolidColorBrush(Colors.Orange);
}
return new SolidColorBrush(Colors.Black);
}
else
{
throw new ArgumentException(string.Format("Unsupported format {0}", targetType.FullName));
}
}
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
}
<Page
x:Class="belle_sip_tester.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:belle_sip_tester"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
xmlns:model="using:belle_sip_tester.DataModel"
xmlns:uixdata="using:Windows.UI.Xaml.Data" x:Name="page"
x:Class="belle_sip_tester.MainPage">
<Page.Resources>
<CollectionViewSource x:Name="UnitTestCVS"
Source="{x:Bind Suites}"
ItemsPath="Cases"
IsSourceGrouped="True"/>
<DataTemplate x:Key="ZoomedInTemplate" x:DataType="model:UnitTestCase">
<Grid Width="320">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0"
Content="{x:Bind Name}"
IsChecked="{Binding Selected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<SymbolIcon Grid.Column="1"
Symbol="{Binding State, Mode=OneWay, Converter={StaticResource UnitTestCaseStateToSymbol}, UpdateSourceTrigger=PropertyChanged}"
Foreground="{Binding State, Mode=OneWay, Converter={StaticResource UnitTestCaseStateToSymbolColor}, UpdateSourceTrigger=PropertyChanged}" Margin="16,0,32,0"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="ZoomedInGroupHeaderTemplate" x:DataType="model:UnitTestSuite">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{x:Bind Name}" Foreground="{ThemeResource ApplicationForegroundThemeBrush}" Style="{StaticResource SubtitleTextBlockStyle}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="ZoomedOutTemplate" x:DataType="uixdata:ICollectionViewGroup">
<TextBlock Text="{x:Bind Group.(model:UnitTestSuite.Name)}" Style="{StaticResource SubtitleTextBlockStyle}" TextWrapping="Wrap"/>
</DataTemplate>
<DataTemplate x:Key="TraceTemplate">
<TextBlock FontFamily="Courier New">
<Run Text="{Binding Msg}" Foreground="{Binding Level, Converter={StaticResource OutputTraceLevelToColor}}"/>
</TextBlock>
</DataTemplate>
</Page.Resources>
<Page.BottomAppBar>
<CommandBar x:Name="CommandBar">
<AppBarButton x:Name="Run" Icon="Play" Label="Run" Click="RunSelected_Click"/>
<AppBarButton x:Name="SelectAll" Icon="SelectAll" Label="Select all" Click="SelectAll_Click"/>
<AppBarToggleButton x:Name="Verbose" Icon="Comment" IsChecked="True" Label="Verbose"/>
</CommandBar>
</Page.BottomAppBar>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="BELLE-SIP TESTER"/>
<TextBlock Text="Test Suite"/>
</StackPanel>
<CheckBox Grid.Row="1" x:Name="Verbose" Content="Verbose" HorizontalAlignment="Right" IsChecked="True"></CheckBox>
<ListView Grid.Row="2" x:Name="Suites" ItemsSource="{Binding}" Tapped="Suite_Tapped">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<SplitView x:Name="splitView" Grid.Row="0" IsPaneOpen="True" DisplayMode="Inline">
<SplitView.Pane>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Test selection" Style="{StaticResource HeaderTextBlockStyle}" Margin="12,0,0,0"/>
<SemanticZoom x:Name="SemanticZoom" Grid.Row="1">
<SemanticZoom.ZoomedInView>
<ListView ItemsSource="{x:Bind UnitTestCVS.View}"
ScrollViewer.IsHorizontalScrollChainingEnabled="False"
SelectionMode="None"
ItemTemplate="{StaticResource ZoomedInTemplate}"
IsItemClickEnabled="True"
ItemClick="UnitTestCase_Click">
<ListView.GroupStyle>
<GroupStyle HeaderTemplate="{StaticResource ZoomedInGroupHeaderTemplate}" />
</ListView.GroupStyle>
</ListView>
</SemanticZoom.ZoomedInView>
<SemanticZoom.ZoomedOutView>
<ListView ItemsSource="{x:Bind UnitTestCVS.View.CollectionGroups}"
SelectionMode="None"
ItemTemplate="{StaticResource ZoomedOutTemplate}">
</ListView>
</SemanticZoom.ZoomedOutView>
</SemanticZoom>
</Grid>
</SplitView.Pane>
<Grid x:Name="TestResultPage">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Test result" Style="{StaticResource HeaderTextBlockStyle}" Margin="12,0,0,0"/>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Style="{StaticResource SubheaderTextBlockStyle}" Margin="16,0,0,0" Text="{Binding Name, Mode=OneWay}"/>
<SymbolIcon Grid.Column="1" x:Name="TestResultState"
Visibility="Collapsed"
Symbol="{Binding State, Mode=OneWay, Converter={StaticResource UnitTestCaseStateToSymbol}, UpdateSourceTrigger=PropertyChanged}"
Foreground="{Binding State, Mode=OneWay, Converter={StaticResource UnitTestCaseStateToSymbolColor}, UpdateSourceTrigger=PropertyChanged}" Margin="16,0,32,0"/>
<AppBarButton Grid.Column="2" x:Name="TestResultRun"
Icon="Play" Label="Run"
IsEnabled="{Binding IsEnabled, ElementName=CommandBar}"
Click="RunSingle_Click" Visibility="Collapsed"/>
</Grid>
<ScrollViewer Grid.Row="2">
<ItemsControl ItemsSource="{Binding Traces}" ItemTemplate="{StaticResource TraceTemplate}" Margin="20,12,0,0"/>
</ScrollViewer>
</Grid>
</SplitView>
<ProgressBar x:Name="ProgressIndicator" Grid.Row="1"
Width="{Binding ActualWidth, ElementName=CommandBar, Mode=OneWay}" Margin="16,0,0,0"/>
</Grid>
</Page>
......@@ -13,6 +13,12 @@ using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using belle_sip_tester.DataModel;
using belle_sip_tester_runtime_component;
using System.Threading.Tasks;
using Windows.UI.Core;
using Windows.UI.Xaml.Documents;
using Windows.Storage;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
......@@ -21,56 +27,171 @@ namespace belle_sip_tester
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
public sealed partial class MainPage : Page, OutputTraceListener
{
public MainPage()
{
this.InitializeComponent();
Suites.DataContext = new UnitTestSuites();
this.InitializeComponent();
}
private void Suite_Tapped(object sender, TappedRoutedEventArgs e)
protected override void OnNavigatedTo(NavigationEventArgs e)
{
UnitTestSuite suite = (sender as ListView).SelectedItem as UnitTestSuite;
if (suite == null) return;
Dictionary<string, string> parameters = new Dictionary<string, string>();
parameters.Add("suite", suite.Name);
parameters.Add("verbose", Verbose.IsChecked.ToString());
if (suite.Name == "ALL")
base.OnNavigatedTo(e);
_suites = UnitTestDataSource.GetSuites(BelleSipTester.Instance);
TryAutoLaunch();
}
public IEnumerable<UnitTestSuite> Suites
{
get { return _suites; }
}
private IEnumerable<UnitTestSuite> _suites;
private void SelectAll_Click(object sender, RoutedEventArgs e)
{
bool allSelected = Suites.All(x => x.Selected);
foreach (UnitTestSuite suite in Suites)
{
suite.Selected = !allSelected;
}
}
private void RunSelected_Click(object sender, RoutedEventArgs e)
{
int nbCases = 0;
foreach (UnitTestSuite suite in Suites)
{
foreach (UnitTestCase c in suite.Cases)
{
if (c.Selected) nbCases++;
}
}
if (nbCases == 0) return;
PrepareRun(nbCases);
var tup = new Tuple<IEnumerable<UnitTestSuite>, bool?>(Suites, Verbose.IsChecked);
var t = Task.Factory.StartNew(async (object parameters) =>
{
var p = parameters as Tuple<IEnumerable<UnitTestSuite>, bool?>;
IEnumerable<UnitTestSuite> suites = p.Item1;
bool verbose = p.Item2 != null ? (bool)p.Item2 : false;
foreach (UnitTestSuite suite in suites)
{
foreach (UnitTestCase c in suite.Cases)
{
if (c.Selected)
{
await RunUnitTestCase(c, verbose);
}
}
}
}, tup);
}
private void RunSingle_Click(object sender, RoutedEventArgs e)
{
PrepareRun(1);
var tup = new Tuple<UnitTestCase, bool?>(DisplayedTestCase, Verbose.IsChecked);
var t = Task.Factory.StartNew(async (object parameters) =>
{
var p = parameters as Tuple<UnitTestCase, bool?>;
UnitTestCase c = p.Item1;
bool verbose = p.Item2 != null ? (bool)p.Item2 : false;
await RunUnitTestCase(c, verbose);
}, tup);
}
private void PrepareRun(int nbCases)
{
CommandBar.IsEnabled = false;
ProgressIndicator.IsEnabled = true;
ProgressIndicator.Minimum = 0;
ProgressIndicator.Maximum = nbCases;
ProgressIndicator.Value = 0;
BelleSipTester.Instance.setOutputTraceListener(this);
}
private async Task RunUnitTestCase(UnitTestCase c, bool verbose)
{
UnitTestCaseState newState = UnitTestCaseState.NotRun;
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
RunningTestCase = c;
});
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
c.Traces.Clear();
});
c.Dispatcher = Dispatcher;
if (BelleSipTester.Instance.run(c.Suite.Name, c.Name, verbose))
{
Frame.Navigate(typeof(ResultPage), parameters);
newState = UnitTestCaseState.Failure;
}
else
{
Frame.Navigate(typeof(TestPage), parameters);
newState = UnitTestCaseState.Success;
}
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
c.State = newState;
ProgressIndicator.Value += 1;
if (ProgressIndicator.Value == ProgressIndicator.Maximum)
{
UnprepareRun();
}
});
}
}
public class UnitTestSuite
{
public string Name
private void UnprepareRun()
{
get;
set;
BelleSipTester.Instance.setOutputTraceListener(null);
RunningTestCase = null;
ProgressIndicator.IsEnabled = false;
CommandBar.IsEnabled = true;
}
public UnitTestSuite(string name)
private void UnitTestCase_Click(object sender, ItemClickEventArgs e)
{
this.Name = name;
DisplayedTestCase = (e.ClickedItem as UnitTestCase);
TestResultPage.DataContext = DisplayedTestCase;
TestResultState.Visibility = Visibility.Visible;
TestResultRun.Visibility = Visibility.Visible;
}
}
public class UnitTestSuites : ObservableCollection<UnitTestSuite>
{
public UnitTestSuites()
public async void outputTrace(String lev, String msg)
{
var tester = (Application.Current as App).tester;
Add(new UnitTestSuite("ALL"));
for (int i = 0; i < tester.nbTestSuites(); i++)
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
Add(new UnitTestSuite(tester.testSuiteName(i)));
if (RunningTestCase != null)
{
RunningTestCase.Traces.Add(new OutputTrace(lev, msg));
}
});
}
private async void TryAutoLaunch()
{
try
{
await ApplicationData.Current.LocalFolder.GetFileAsync("autolaunch");
CommandBar.IsEnabled = false;
ProgressIndicator.IsIndeterminate = true;
ProgressIndicator.IsEnabled = true;
BelleSipTester.Instance.runAllToXml();
if (BelleSipTester.Instance.AsyncAction != null)
{
BelleSipTester.Instance.AsyncAction.Completed += (asyncInfo, asyncStatus) => {
App.Current.Exit();
};
}
}
catch (Exception) { }
}