From 5d6fe31c62a5bb87239edaac9fe93ebfbb716c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Pedro?= Date: Tue, 23 Jan 2018 16:46:12 +0000 Subject: [PATCH] Added a test runner UI, built on Avalonia. --- NuGet.config | 1 + Tests/Cosmos.TestRunner.UI.Avalonia/App.xaml | 11 ++ .../Cosmos.TestRunner.UI.Avalonia/App.xaml.cs | 38 +++++ .../Cosmos.TestRunner.UI.Avalonia.csproj | 29 ++++ .../ViewModels/MainWindowViewModel.cs | 42 +++++ .../ViewModels/SettingsDialogViewModel.cs | 158 ++++++++++++++++++ .../Views/MainWindow.xaml | 10 ++ .../Views/MainWindow.xaml.cs | 42 +++++ .../Views/SettingsDialog.xaml | 49 ++++++ .../Views/SettingsDialog.xaml.cs | 24 +++ 10 files changed, 404 insertions(+) create mode 100644 Tests/Cosmos.TestRunner.UI.Avalonia/App.xaml create mode 100644 Tests/Cosmos.TestRunner.UI.Avalonia/App.xaml.cs create mode 100644 Tests/Cosmos.TestRunner.UI.Avalonia/Cosmos.TestRunner.UI.Avalonia.csproj create mode 100644 Tests/Cosmos.TestRunner.UI.Avalonia/ViewModels/MainWindowViewModel.cs create mode 100644 Tests/Cosmos.TestRunner.UI.Avalonia/ViewModels/SettingsDialogViewModel.cs create mode 100644 Tests/Cosmos.TestRunner.UI.Avalonia/Views/MainWindow.xaml create mode 100644 Tests/Cosmos.TestRunner.UI.Avalonia/Views/MainWindow.xaml.cs create mode 100644 Tests/Cosmos.TestRunner.UI.Avalonia/Views/SettingsDialog.xaml create mode 100644 Tests/Cosmos.TestRunner.UI.Avalonia/Views/SettingsDialog.xaml.cs diff --git a/NuGet.config b/NuGet.config index f4435c938..c443fb9a5 100644 --- a/NuGet.config +++ b/NuGet.config @@ -2,6 +2,7 @@ + diff --git a/Tests/Cosmos.TestRunner.UI.Avalonia/App.xaml b/Tests/Cosmos.TestRunner.UI.Avalonia/App.xaml new file mode 100644 index 000000000..438c16cbe --- /dev/null +++ b/Tests/Cosmos.TestRunner.UI.Avalonia/App.xaml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/Tests/Cosmos.TestRunner.UI.Avalonia/App.xaml.cs b/Tests/Cosmos.TestRunner.UI.Avalonia/App.xaml.cs new file mode 100644 index 000000000..fa19e5eca --- /dev/null +++ b/Tests/Cosmos.TestRunner.UI.Avalonia/App.xaml.cs @@ -0,0 +1,38 @@ +using System.Diagnostics; + +using Avalonia; +using Avalonia.Logging.Serilog; +using Avalonia.Markup.Xaml; + +using Serilog; + +using Cosmos.TestRunner.UI.Views; + +namespace Cosmos.TestRunner.UI +{ + internal class App : Application + { + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + base.Initialize(); + } + + static void Main(string[] args) + { + InitializeLogging(); + AppBuilder.Configure() + .UsePlatformDetect() + .Start(); + } + + [Conditional("DEBUG")] + private static void InitializeLogging() + { + SerilogLogger.Initialize(new LoggerConfiguration() + .MinimumLevel.Warning() + .WriteTo.Trace(outputTemplate: "{Area}: {Message}") + .CreateLogger()); + } + } +} diff --git a/Tests/Cosmos.TestRunner.UI.Avalonia/Cosmos.TestRunner.UI.Avalonia.csproj b/Tests/Cosmos.TestRunner.UI.Avalonia/Cosmos.TestRunner.UI.Avalonia.csproj new file mode 100644 index 000000000..2c9d1010f --- /dev/null +++ b/Tests/Cosmos.TestRunner.UI.Avalonia/Cosmos.TestRunner.UI.Avalonia.csproj @@ -0,0 +1,29 @@ + + + + netcoreapp2.0;net471 + Exe + win7-x86 + Cosmos.TestRunner.UI + Cosmos.TestRunner.UI + + + + + %(Filename) + + + Designer + + + + + + + + + + + + + diff --git a/Tests/Cosmos.TestRunner.UI.Avalonia/ViewModels/MainWindowViewModel.cs b/Tests/Cosmos.TestRunner.UI.Avalonia/ViewModels/MainWindowViewModel.cs new file mode 100644 index 000000000..273b03d38 --- /dev/null +++ b/Tests/Cosmos.TestRunner.UI.Avalonia/ViewModels/MainWindowViewModel.cs @@ -0,0 +1,42 @@ +using System; +using System.ComponentModel; +using System.Threading; + +using Cosmos.TestRunner.Core; + +namespace Cosmos.TestRunner.UI.ViewModels +{ + internal class MainWindowViewModel : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + public MainWindowViewModel(IEngineConfiguration aEngineConfiguration) + { + var xEngine = new Engine(aEngineConfiguration) + { + OutputHandler = new OutputHandler( + m => + { + TestRunnerLog += m + Environment.NewLine; + OnPropertyChanged(nameof(TestRunnerLog)); + }) + }; + + new Thread(() => xEngine.Execute()).Start(); + } + + public string TestRunnerLog { get; set; } + + private void OnPropertyChanged(string aPropertyName) => + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(aPropertyName)); + + internal class OutputHandler : OutputHandlerFullTextBase + { + private Action mLog; + + public OutputHandler(Action aLog) => mLog = aLog; + + protected override void Log(string message) => mLog(message); + } + } +} diff --git a/Tests/Cosmos.TestRunner.UI.Avalonia/ViewModels/SettingsDialogViewModel.cs b/Tests/Cosmos.TestRunner.UI.Avalonia/ViewModels/SettingsDialogViewModel.cs new file mode 100644 index 000000000..a0fc70986 --- /dev/null +++ b/Tests/Cosmos.TestRunner.UI.Avalonia/ViewModels/SettingsDialogViewModel.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Windows.Input; +using PropertyChangedEventArgs = System.ComponentModel.PropertyChangedEventArgs; + +using Avalonia.Controls; + +using Cosmos.Build.Common; +using Cosmos.TestRunner.Core; + +namespace Cosmos.TestRunner.UI.ViewModels +{ + internal class SettingsDialogViewModel : IEngineConfiguration, INotifyPropertyChanged + { + private static IEngineConfiguration defaultEngineConfiguration = new DefaultEngineConfiguration(); + private static IEnumerable stableKernelTypes = TestKernelSets.GetStableKernelTypes(); + + public event PropertyChangedEventHandler PropertyChanged; + + public SettingsDialogViewModel(Window aWindow) + { + KernelTypesToRun = new ObservableCollection(stableKernelTypes); + RunTests = new RunTestsCommand(aWindow, this); + } + + #region Engine Configuration + + private int mAllowedSecondsInKernel = defaultEngineConfiguration.AllowedSecondsInKernel; + public int AllowedSecondsInKernel + { + get => mAllowedSecondsInKernel; + set => SetProperty(ref mAllowedSecondsInKernel, value); + } + + public IEnumerable RunTargets + { + get + { + yield return RunTarget; + } + set => RunTarget = value.Single(); + } + + private bool mRunWithGDB = defaultEngineConfiguration.RunWithGDB; + public bool RunWithGDB + { + get => mRunWithGDB; + set => SetProperty(ref mRunWithGDB, value); + } + + private bool mStartBochsDebugGUI = defaultEngineConfiguration.StartBochsDebugGUI; + public bool StartBochsDebugGUI + { + get => mStartBochsDebugGUI; + set => SetProperty(ref mStartBochsDebugGUI, value); + } + + private bool mDebugIL2CPU = defaultEngineConfiguration.DebugIL2CPU; + public bool DebugIL2CPU + { + get => mDebugIL2CPU; + set => SetProperty(ref mDebugIL2CPU, value); + } + + private string mKernelPkg = defaultEngineConfiguration.KernelPkg; + public string KernelPkg + { + get => mKernelPkg; + set => SetProperty(ref mKernelPkg, value); + } + + private TraceAssemblies mTraceAssembliesLevel = defaultEngineConfiguration.TraceAssembliesLevel; + public TraceAssemblies TraceAssembliesLevel + { + get => mTraceAssembliesLevel; + set => SetProperty(ref mTraceAssembliesLevel, value); + } + + private bool mEnableStackCorruptionChecks = defaultEngineConfiguration.EnableStackCorruptionChecks; + public bool EnableStackCorruptionChecks + { + get => mEnableStackCorruptionChecks; + set => SetProperty(ref mEnableStackCorruptionChecks, value); + } + + private StackCorruptionDetectionLevel mStackCorruptionDetectionLevel = defaultEngineConfiguration.StackCorruptionDetectionLevel; + public StackCorruptionDetectionLevel StackCorruptionDetectionLevel + { + get => mStackCorruptionDetectionLevel; + set => SetProperty(ref mStackCorruptionDetectionLevel, value); + } + + IEnumerable IEngineConfiguration.KernelTypesToRun => KernelTypesToRun; + + #endregion + + private RunTargetEnum mRunTarget = defaultEngineConfiguration.RunTargets.FirstOrDefault(); + public RunTargetEnum RunTarget + { + get => mRunTarget; + set => SetProperty(ref mRunTarget, value); + } + + public ObservableCollection KernelTypesToRun { get; } + + #region Items + + public IEnumerable TestKernels { get; } = stableKernelTypes; + public IEnumerable RunTargetItems { get; } = Enum.GetValues(typeof(RunTargetEnum)); + public IEnumerable TraceAssembliesLevelItems { get; } = Enum.GetValues(typeof(TraceAssemblies)); + public IEnumerable StackCorruptionDetectionLevelItems { get; } = Enum.GetValues(typeof(StackCorruptionDetectionLevel)); + + #endregion + + public ICommand RunTests { get; set; } + + private void SetProperty(ref T aProperty, T aValue, [CallerMemberName]string aPropertyName = null) + { + if (!EqualityComparer.Default.Equals(aProperty, aValue)) + { + aProperty = aValue; + OnPropertyChanged(aPropertyName); + } + } + + private void OnPropertyChanged(string aPropertyName) => + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(aPropertyName)); + + internal class RunTestsCommand : ICommand + { + private Window mWindow; + private SettingsDialogViewModel mViewModel; + + public RunTestsCommand(Window aWindow, SettingsDialogViewModel aViewModel) + { + mWindow = aWindow; + mViewModel = aViewModel; + + mViewModel.KernelTypesToRun.CollectionChanged += KernelTypesToRun_CollectionChanged; + } + + public event EventHandler CanExecuteChanged; + + public bool CanExecute(object parameter) => mViewModel.KernelTypesToRun.Any(); + + public void Execute(object parameter) => mWindow.Close(mViewModel); + + private void KernelTypesToRun_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) => + CanExecuteChanged?.Invoke(this, EventArgs.Empty); + } + } +} diff --git a/Tests/Cosmos.TestRunner.UI.Avalonia/Views/MainWindow.xaml b/Tests/Cosmos.TestRunner.UI.Avalonia/Views/MainWindow.xaml new file mode 100644 index 000000000..9b694574e --- /dev/null +++ b/Tests/Cosmos.TestRunner.UI.Avalonia/Views/MainWindow.xaml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Tests/Cosmos.TestRunner.UI.Avalonia/Views/MainWindow.xaml.cs b/Tests/Cosmos.TestRunner.UI.Avalonia/Views/MainWindow.xaml.cs new file mode 100644 index 000000000..da52bd89f --- /dev/null +++ b/Tests/Cosmos.TestRunner.UI.Avalonia/Views/MainWindow.xaml.cs @@ -0,0 +1,42 @@ +using System.Threading.Tasks; + +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Avalonia.Threading; + +using Cosmos.TestRunner.Core; +using Cosmos.TestRunner.UI.ViewModels; + +namespace Cosmos.TestRunner.UI.Views +{ + internal class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + this.AttachDevTools(); + + Dispatcher.UIThread.InvokeAsync(async () => await ShowSettingsDialog().ConfigureAwait(false)); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + + private async Task ShowSettingsDialog() + { + var xSettingsDialog = new SettingsDialog(); + var xEngineConfiguration = await xSettingsDialog.ShowDialog(); + + if (xEngineConfiguration == null) + { + Application.Current.Exit(); + return; + } + + DataContext = new MainWindowViewModel(xEngineConfiguration); + } + } +} diff --git a/Tests/Cosmos.TestRunner.UI.Avalonia/Views/SettingsDialog.xaml b/Tests/Cosmos.TestRunner.UI.Avalonia/Views/SettingsDialog.xaml new file mode 100644 index 000000000..001cad0bc --- /dev/null +++ b/Tests/Cosmos.TestRunner.UI.Avalonia/Views/SettingsDialog.xaml @@ -0,0 +1,49 @@ + + + + + + + + + Allowed seconds in kernel: + + Run with GDB + Start Bochs debug GUI + Run target: + + + + + + + Debug IL2CPU + Kernel package: + + Trace assemblies level: + + Enable stack corruption checks + Stack corruption detection level: + + + + + + + + + + + + + diff --git a/Tests/Cosmos.TestRunner.UI.Avalonia/Views/SettingsDialog.xaml.cs b/Tests/Cosmos.TestRunner.UI.Avalonia/Views/SettingsDialog.xaml.cs new file mode 100644 index 000000000..075ee657c --- /dev/null +++ b/Tests/Cosmos.TestRunner.UI.Avalonia/Views/SettingsDialog.xaml.cs @@ -0,0 +1,24 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +using Cosmos.TestRunner.UI.ViewModels; + +namespace Cosmos.TestRunner.UI.Views +{ + internal class SettingsDialog : Window + { + public SettingsDialog() + { + InitializeComponent(); + this.AttachDevTools(); + + DataContext = new SettingsDialogViewModel(this); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + } +}