Push coverage up to 99.7%

This commit is contained in:
Antony Male 2014-05-10 20:11:02 +01:00
parent 256198d3c0
commit fc4a7fb61c
33 changed files with 791 additions and 512 deletions

View File

@ -47,7 +47,7 @@ task :test => [:nunit_test_runner] do |t|
end
desc "Launch the NUnit gui pointing at the correct DLL for CONFIG (or Debug)"
task :nunit do |t|
task :nunit => [:test_environment] do |t|
sh NUNIT_EXE, UNIT_TESTS_DLL
end

View File

@ -30,13 +30,20 @@ namespace Stylet
this.Application = Application.Current;
// Call this before calling our Start method
this.Application.Startup += this.OnStartup;
this.Application.Startup += (o, e) => this.Start();
// Allows for unit testing
if (this.Application != null)
{
// Call this before calling our Start method
this.Application.Startup += (o, e) =>
{
this.OnStartup(o, e);
this.Start();
};
// Make life nice for the app - they can handle these by overriding Bootstrapper methods, rather than adding event handlers
this.Application.Exit += OnExit;
this.Application.DispatcherUnhandledException += OnUnhandledExecption;
// Make life nice for the app - they can handle these by overriding Bootstrapper methods, rather than adding event handlers
this.Application.Exit += OnExit;
this.Application.DispatcherUnhandledException += OnUnhandledExecption;
}
}
/// <summary>
@ -61,8 +68,11 @@ namespace Stylet
protected virtual void ConfigureResources()
{
if (this.Application == null)
return;
var rc = new ResourceDictionary() { Source = new Uri("pack://application:,,,/Stylet;component/Xaml/StyletResourceDictionary.xaml", UriKind.Absolute) };
Application.Resources.MergedDictionaries.Add(rc);
this.Application.Resources.MergedDictionaries.Add(rc);
}
/// <summary>
@ -95,9 +105,9 @@ namespace Stylet
/// Initial contents of AssemblySource.Assemblies, defaults to the entry assembly
/// </summary>
/// <returns></returns>
protected IEnumerable<Assembly> SelectAssemblies()
protected virtual IEnumerable<Assembly> SelectAssemblies()
{
return new[] { Assembly.GetEntryAssembly() };
return new[] { this.GetType().Assembly };
}
/// <summary>
@ -110,7 +120,7 @@ namespace Stylet
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected virtual void OnExit(object sender, EventArgs e) { }
protected virtual void OnExit(object sender, ExitEventArgs e) { }
/// <summary>
/// Hook called on an unhandled exception

View File

@ -43,7 +43,9 @@ namespace StyletIoC
var memberAccess = Expression.MakeMemberAccess(objExpression, member);
var memberValue = this.container.GetExpression(new TypeKey(memberType, attribute.Key), true);
return Expression.Assign(memberAccess, memberValue);
var assign = Expression.Assign(memberAccess, memberValue);
// Only actually do the assignment if the field/property is currently null
return Expression.IfThen(Expression.Equal(memberAccess, Expression.Constant(null, memberType)), assign);
}
public Action<object> GetImplementor()

View File

@ -255,7 +255,7 @@ namespace StyletIoC
public override void Build(StyletIoCContainer container)
{
var candidates = from type in assemblies.SelectMany(x => x.GetTypes())
var candidates = from type in assemblies.Distinct().SelectMany(x => x.GetTypes())
let baseType = type.GetBaseTypesAndInterfaces().FirstOrDefault(x => x == this.serviceType || x.IsGenericType && x.GetGenericTypeDefinition() == this.serviceType)
where baseType != null
select new { Type = type, Base = baseType.ContainsGenericParameters ? baseType.GetGenericTypeDefinition() : baseType };
@ -377,18 +377,13 @@ namespace StyletIoC
assemblies = new[] { Assembly.GetCallingAssembly() };
// We self-bind concrete classes only
var classes = assemblies.SelectMany(x => x.GetTypes()).Where(c => c.IsClass && !c.IsAbstract);
var classes = assemblies.Distinct().SelectMany(x => x.GetTypes()).Where(c => c.IsClass && !c.IsAbstract);
foreach (var cls in classes)
{
// Don't care if binding fails - we're likely to hit a few of these
try
{
this.BindWeak(cls).To(cls);
}
catch (StyletIoCRegistrationException e)
{
Debug.WriteLine(String.Format("Unable to auto-bind type {0}: {1}", cls.Description(), e.Message), "StyletIoC");
}
// It's not actually possible for this to fail with a StyletIoCRegistrationException (at least currently)
// It's a self-binding, and those are always safe (at this stage - it could fall over when the containing's actually build)
this.BindWeak(cls).To(cls);
}
}
@ -412,7 +407,7 @@ namespace StyletIoC
{
var container = new StyletIoCContainer();
container.AddRegistration(new TypeKey(typeof(IContainer), null), new SingletonRegistration(new FactoryCreator<StyletIoCContainer>(c => container, container)));
container.AddRegistration(new TypeKey(typeof(StyletIoCContainer), null), new SingletonRegistration(new FactoryCreator<StyletIoCContainer>(c => container, container)));
//container.AddRegistration(new TypeKey(typeof(StyletIoCContainer), null), new SingletonRegistration(new FactoryCreator<StyletIoCContainer>(c => container, container)));
// For each TypeKey, we remove any weak bindings if there are any strong bindings
var groups = this.bindings.GroupBy(x => new { Key = x.Key, Type = x.ServiceType });

View File

@ -174,8 +174,9 @@ namespace StyletIoC
throw new ArgumentNullException("type");
var typeKey = new TypeKey(type, key);
IRegistration registration;
if (!this.TryRetrieveGetAllRegistrationFromElementType(typeKey, null, out registration))
throw new StyletIoCRegistrationException(String.Format("Could not find registration for type {0} and key '{1}'", typeKey.Type.Description(), typeKey.Key));
// This can currently never fail, since we pass in null
var result = this.TryRetrieveGetAllRegistrationFromElementType(typeKey, null, out registration);
Debug.Assert(result);
var generator = registration.GetGenerator();
return (IEnumerable<object>)generator();
}
@ -345,8 +346,8 @@ namespace StyletIoC
newType = unboundGeneric.Type.MakeGenericType(unboundGeneric.Type.GetTypeInfo().GenericTypeParameters.Select(x => mapping.Single(t => t.Name.Name == x.Name).Type).ToArray());
}
if (!type.IsAssignableFrom(newType))
continue;
// The binder should have made sure of this
Debug.Assert(type.IsAssignableFrom(newType));
// Right! We've made a new generic type we can use
var registration = unboundGeneric.CreateRegistrationForType(newType);
@ -571,14 +572,9 @@ namespace StyletIoC
public static IEnumerable<Type> GetBaseTypes(this Type type)
{
if (type == typeof(object))
yield break;
var baseType = type.BaseType ?? typeof(object);
while (baseType != null)
for (var baseType = type.BaseType; baseType != null; baseType = baseType.BaseType)
{
yield return baseType;
baseType = baseType.BaseType;
}
}
@ -635,7 +631,6 @@ namespace StyletIoC
public class StyletIoCFindConstructorException : StyletIoCException
{
public StyletIoCFindConstructorException(string message) : base(message) { }
public StyletIoCFindConstructorException(string message, Exception innerException) : base(message, innerException) { }
}
public class StyletIoCCreateFactoryException : StyletIoCException

View File

@ -18,6 +18,13 @@ namespace Stylet
public class WindowManager : IWindowManager
{
private IViewManager viewManager;
public WindowManager(IViewManager viewManager)
{
this.viewManager = viewManager;
}
public void ShowWindow(object viewModel)
{
this.CreateWindow(viewModel, false).Show();
@ -28,16 +35,14 @@ namespace Stylet
return this.CreateWindow(viewModel, true).ShowDialog();
}
private Window CreateWindow(object viewModel, bool isDialog)
protected virtual Window CreateWindow(object viewModel, bool isDialog)
{
var viewManager = IoC.Get<IViewManager>();
var view = viewManager.CreateViewForModel(viewModel);
var view = this.viewManager.CreateViewForModel(viewModel);
var window = view as Window;
if (window == null)
throw new Exception(String.Format("Tried to show {0} as a window, but it isn't a Window", view == null ? "(null)" : view.GetType().Name));
viewManager.BindViewToModel(window, viewModel);
this.viewManager.BindViewToModel(window, viewModel);
var haveDisplayName = viewModel as IHaveDisplayName;
if (haveDisplayName != null)
@ -139,9 +144,8 @@ namespace Stylet
if (await task)
{
this.window.Closing -= this.WindowClosing;
this.window.StateChanged -= this.WindowStateChanged;
ScreenExtensions.TryClose(this.viewModel);
this.window.Close();
// The Closed event handler handles unregistering the events, and closing the ViewModel
}
}
}

View File

@ -1,30 +0,0 @@
<Window x:Class="StyletIntegrationTests.Actions.ActionsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="https://github.com/canton7/Stylet"
Title="ActionsView" Height="300" Width="300">
<DockPanel LastChildFill="False">
<GroupBox DockPanel.Dock="Top" Header="CommandAction" Padding="10">
<StackPanel>
<TextBlock TextWrapping="WrapWithOverflow">Verify that the checkbox enables/disables the button, and that clicking the button shows a message box, containing the parameter in the textbox.</TextBlock>
<DockPanel>
<Button DockPanel.Dock="Left" Command="{s:Action CommandButton}" CommandParameter="{Binding ElementName=Parameter, Path=Text}">Button</Button>
<CheckBox DockPanel.Dock="Left" IsChecked="{Binding CheckboxIsChecked}" Margin="10,0,0,0">Enabled</CheckBox>
<TextBox DockPanel.Dock="Left" x:Name="Parameter" Margin="10,0,0,0">Parameter</TextBox>
</DockPanel>
</StackPanel>
</GroupBox>
<GroupBox DockPanel.Dock="Top" Header="EventAction">
<StackPanel>
<TextBlock TextWrapping="Wrap">Verify that both buttons show message boxes.</TextBlock>
<DockPanel LastChildFill="False">
<Button DockPanel.Dock="Left" Click="{s:Action EventButtonNoArgs}">Button 1</Button>
<Button DockPanel.Dock="Left" Click="{s:Action EventButtonWithArgs}">Button 2</Button>
</DockPanel>
</StackPanel>
</GroupBox>
</DockPanel>
</Window>

View File

@ -1,50 +0,0 @@
using Stylet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace StyletIntegrationTests.Actions
{
public class ActionsViewModel : Screen
{
private bool _checkboxIsChecked;
public bool CheckboxIsChecked
{
get { return this._checkboxIsChecked; }
set
{
this.SetAndNotify(ref this._checkboxIsChecked, value);
this.NotifyOfPropertyChange(() => this.CanCommandButton);
}
}
public ActionsViewModel()
{
this.DisplayName = "Actions";
}
public bool CanCommandButton
{
get { return this.CheckboxIsChecked; }
}
public void CommandButton(string parameter)
{
MessageBox.Show(String.Format("Parameter is '{0}'", parameter));
}
public void EventButtonNoArgs()
{
MessageBox.Show("Success!");
}
public void EventButtonWithArgs(RoutedEventArgs e)
{
string buttonText = (string)(((Button)e.Source).Content);
MessageBox.Show(buttonText == "Button 2" ? "Success!" : "Fail: Sender was not sent successfully");
}
}
}

View File

@ -1,5 +1,4 @@
using Stylet;
using StyletIntegrationTests.BootstrapperIoC;
using System;
using System.Collections.Generic;
using System.Linq;
@ -12,12 +11,6 @@ namespace StyletIntegrationTests
{
public class Bootstrapper : Bootstrapper<ShellViewModel>
{
protected override void ConfigureIoC(StyletIoC.IStyletIoCBuilder builder)
{
base.ConfigureIoC(builder); // Calling this just to trigger some code coverage
builder.Bind<BootstrapperIoCI1>().ToAllImplementations();
}
protected override void OnUnhandledExecption(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
base.OnUnhandledExecption(sender, e); // Calling this just to trigger some code coverage

View File

@ -1,12 +0,0 @@
<Window x:Class="StyletIntegrationTests.BootstrapperIoC.WindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="https://github.com/canton7/Stylet"
Title="DialogView" Width="300" SizeToContent="Height">
<DockPanel Margin="20" LastChildFill="False">
<TextBlock DockPanel.Dock="Top" TextWrapping="WrapWithOverflow">Make sure that pressing the following buttons has no visible effect (no dialogs, crashes, etc).</TextBlock>
<Button DockPanel.Dock="Top" Command="{s:Action GetSingle}" Margin="0,10,0,0">GetSingle</Button>
<Button DockPanel.Dock="Top" Command="{s:Action GetAll}" Margin="0,10,0,0">GetAll</Button>
<Button DockPanel.Dock="Top" Command="{s:Action BuildUp}" Margin="0,10,0,0">BuildUp</Button>
</DockPanel>
</Window>

View File

@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace StyletIntegrationTests.BootstrapperIoC
{
/// <summary>
/// Interaction logic for WindowView.xaml
/// </summary>
public partial class WindowView : Window
{
public WindowView()
{
InitializeComponent();
}
}
}

View File

@ -1,44 +0,0 @@
using Stylet;
using StyletIoC;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StyletIntegrationTests.BootstrapperIoC
{
interface BootstrapperIoCI1 { }
class BootstrapperIoCC1 : BootstrapperIoCI1 { }
class BootstrapperIoCC2 : BootstrapperIoCI1 { }
class BootstrapperIoCC3
{
[Inject]
public BootstrapperIoCC1 C1 { get; set; }
}
public class WindowViewModel : Screen
{
public void GetSingle()
{
var result = IoC.Get<BootstrapperIoCC1>();
if (result == null)
throw new Exception("IoC.Get failed");
}
public void GetAll()
{
var result = IoC.GetAll<BootstrapperIoCI1>().ToList();
if (result.Count != 2 || !(result[0] is BootstrapperIoCC1) || !(result[1] is BootstrapperIoCC2))
throw new Exception("IoC.GetAll failed");
}
public void BuildUp()
{
var c3 = new BootstrapperIoCC3();
IoC.BuildUp(c3);
if (c3.C1 == null)
throw new Exception("IoC.BuildUp failed");
}
}
}

View File

@ -1,10 +0,0 @@
<Window x:Class="StyletIntegrationTests.OnUnhandledException.WindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="https://github.com/canton7/Stylet"
Title="WindowView" Width="300" SizeToContent="Height">
<DockPanel Margin="20" LastChildFill="False">
<TextBlock DockPanel.Dock="Top" TextWrapping="WrapWithOverflow">Verify that pressing the button below shows a dialog, containing the message 'Unhandled Exception: Hello'.</TextBlock>
<Button DockPanel.Dock="Top" Command="{s:Action ThrowException}">Throw Exception</Button>
</DockPanel>
</Window>

View File

@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace StyletIntegrationTests.OnUnhandledException
{
/// <summary>
/// Interaction logic for WindowView.xaml
/// </summary>
public partial class WindowView : Window
{
public WindowView()
{
InitializeComponent();
}
}
}

View File

@ -1,17 +0,0 @@
using Stylet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StyletIntegrationTests.OnUnhandledException
{
public class WindowViewModel : Screen
{
public void ThrowException()
{
throw new Exception("Hello");
}
}
}

View File

@ -12,28 +12,22 @@
</StackPanel>
</GroupBox>
<GroupBox DockPanel.Dock="Top" Header="Window DisplayName Bound" Padding="10">
<Button Command="{s:Action ShowWindowsDisplayNameBound}">Show Window</Button>
</GroupBox>
<GroupBox DockPanel.Dock="Top" Header="Window Guard Close" Padding="10">
<Button Command="{s:Action ShowWindowGuardClose}">Show Window</Button>
</GroupBox>
<GroupBox DockPanel.Dock="Top" Header="Window Lifecycle" Padding="10">
<Button Command="{s:Action ShowWindowLifecycle}">Show Window</Button>
</GroupBox>
<GroupBox DockPanel.Dock="Top" Header="Bootstrapper IoC" Padding="10">
<Button Command="{s:Action ShowBootstrapperIoC}">Show Window</Button>
</GroupBox>
<GroupBox DockPanel.Dock="Top" Header="OnUnhandledException" Padding="10">
<Button Command="{s:Action ShowOnUnhandledException}">Show Window</Button>
<DockPanel>
<TextBlock DockPanel.Dock="Top" TextWrapping="WrapWithOverflow">Verify that pressing the button below shows a dialog, containing the message 'Unhandled Exception: Hello'.</TextBlock>
<Button DockPanel.Dock="Top" Command="{s:Action ThrowException}">Throw Exception</Button>
</DockPanel>
</GroupBox>
<GroupBox DockPanel.Dock="Top" Header="Actions" Padding="10">
<Button Command="{s:Action ShowActions}">Show Window</Button>
<GroupBox DockPanel.Dock="Top" Header="Dispatcher" Padding="10">
<DockPanel>
<TextBlock DockPanel.Dock="Top" TextWrapping="WrapWithOverflow">Verify that pressing the button shows a MessageBox saying 'Success'.</TextBlock>
<Button DockPanel.Dock="Top" Command="{s:Action TestDispatcher}">Test Dispatcher</Button>
</DockPanel>
</GroupBox>
</DockPanel>
</Window>

View File

@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace StyletIntegrationTests
{
@ -32,40 +33,36 @@ namespace StyletIntegrationTests
this.ShowDialogAndDialogResultDialogResult = this.windowManager.ShowDialog(dialog);
}
public void ShowWindowsDisplayNameBound()
{
var window = new WindowDisplayNameBound.WindowViewModel();
this.windowManager.ShowWindow(window);
}
public void ShowWindowGuardClose()
{
var window = new WindowGuardClose.WindowViewModel();
this.windowManager.ShowWindow(window);
}
public void ShowWindowLifecycle()
{
var window = new WindowLifecycle.WindowViewModel();
this.windowManager.ShowWindow(window);
}
public void ShowBootstrapperIoC()
public void ThrowException()
{
var window = new BootstrapperIoC.WindowViewModel();
this.windowManager.ShowWindow(window);
throw new Exception("Hello");
}
public void ShowOnUnhandledException()
public async void TestDispatcher()
{
var window = new OnUnhandledException.WindowViewModel();
this.windowManager.ShowWindow(window);
}
var dispatcher = Execute.Dispatcher;
var log = new List<string>();
public void ShowActions()
{
var window = new Actions.ActionsViewModel();
this.windowManager.ShowDialog(window);
await Task.Run(() => dispatcher.Send(() => { lock(log) { log.Add("One"); }; }));
lock (log) { log.Add("Two"); };
await Task.Run(() => dispatcher.Post(() => { lock (log) { log.Add("Three"); }; }));
lock (log) { log.Add("Four"); };
// OK, so at this point there's a queued message saying to add Three to the log
// Give the main thread time to process that message
await Task.Delay(100);
if (log.SequenceEqual(new[] { "One", "Two", "Four", "Three" }))
MessageBox.Show("Success");
else
MessageBox.Show("Failure");
}
}
}

View File

@ -55,16 +55,7 @@
</ApplicationDefinition>
</ItemGroup>
<ItemGroup>
<Compile Include="Actions\ActionsViewModel.cs" />
<Compile Include="Bootstrapper.cs" />
<Compile Include="BootstrapperIoC\WindowView.xaml.cs">
<DependentUpon>WindowView.xaml</DependentUpon>
</Compile>
<Compile Include="BootstrapperIoC\WindowViewModel.cs" />
<Compile Include="OnUnhandledException\WindowView.xaml.cs">
<DependentUpon>WindowView.xaml</DependentUpon>
</Compile>
<Compile Include="OnUnhandledException\WindowViewModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
@ -80,8 +71,6 @@
</Compile>
<Compile Include="ShellViewModel.cs" />
<Compile Include="ShowDialogAndDialogResult\DialogViewModel.cs" />
<Compile Include="WindowDisplayNameBound\WindowViewModel.cs" />
<Compile Include="WindowGuardClose\WindowViewModel.cs" />
<Compile Include="WindowLifecycle\WindowViewModel.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
@ -103,18 +92,6 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Page Include="Actions\ActionsView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="BootstrapperIoC\WindowView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="OnUnhandledException\WindowView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="ShellView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -123,14 +100,6 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="WindowDisplayNameBound\WindowView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="WindowGuardClose\WindowView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="WindowLifecycle\WindowView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>

View File

@ -1,10 +0,0 @@
<Window x:Class="StyletIntegrationTests.WindowDisplayNameBound.WindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="https://github.com/canton7/Stylet"
Title="WindowView" Height="300" Width="300">
<DockPanel Margin="10" LastChildFill="False">
<TextBlock DockPanel.Dock="Top" TextWrapping="WrapWithOverflow">Press the button, and verify that the count in the window title increases. When you are done, close the window.</TextBlock>
<Button DockPanel.Dock="Top" Command="{s:Action AddCount}">Press Me</Button>
</DockPanel>
</Window>

View File

@ -1,25 +0,0 @@
using Stylet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StyletIntegrationTests.WindowDisplayNameBound
{
public class WindowViewModel : Screen
{
private int count = 0;
public WindowViewModel()
{
this.DisplayName = String.Format("Count: {0}", this.count);
}
public void AddCount()
{
this.count++;
this.DisplayName = String.Format("Count: {0}", this.count);
}
}
}

View File

@ -1,11 +0,0 @@
<Window x:Class="StyletIntegrationTests.WindowGuardClose.WindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="https://github.com/canton7/Stylet"
Title="WindowView" Height="300" Width="300">
<DockPanel Margin="10">
<TextBlock DockPanel.Dock="Top" TextWrapping="WrapWithOverflow">Leave the checkbox unchecked, then close the window using the red X at the top. It should not close.</TextBlock>
<TextBlock DockPanel.Dock="Top" TextWrapping="WrapWithOverflow">Check the checkbox, then close the window again. It should close after 3 seconds.</TextBlock>
<CheckBox DockPanel.Dock="Top" IsChecked="{Binding AllowClose}" Margin="0,10,0,0">Allow Close</CheckBox>
</DockPanel>
</Window>

View File

@ -1,24 +0,0 @@
using Stylet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace StyletIntegrationTests.WindowGuardClose
{
public class WindowViewModel : Screen
{
public bool AllowClose { get; set; }
public WindowViewModel()
{
this.DisplayName = "Window Guard Close";
}
public override Task<bool> CanCloseAsync()
{
return this.AllowClose ? Task.Delay(2000).ContinueWith(t => true) : Task.FromResult(false);
}
}
}

View File

@ -16,6 +16,7 @@ namespace StyletUnitTests
public void SetUpFixture()
{
Execute.TestExecuteSynchronously = true;
AssemblySource.Assemblies.Clear();
}
[Test]

View File

@ -0,0 +1,162 @@
using Moq;
using NUnit.Framework;
using Stylet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace StyletUnitTests
{
[TestFixture, RequiresSTA]
public class BootstrapperBaseTests
{
private class RootViewModel { }
private class MyBootstrapperBase<T> : BootstrapperBase<T> where T : class
{
private IViewManager viewManager;
private IWindowManager windowManager;
public MyBootstrapperBase(IViewManager viewManager, IWindowManager windowManager)
{
this.viewManager = viewManager;
this.windowManager = windowManager;
}
public bool GetInstanceCalled;
protected override object GetInstance(Type service, string key = null)
{
this.GetInstanceCalled = true;
if (service == typeof(IViewManager))
return this.viewManager;
if (service == typeof(IWindowManager))
return this.windowManager;
if (service == typeof(RootViewModel))
return new RootViewModel();
return new object();
}
public bool GetAllInstancesCalled;
protected override IEnumerable<object> GetAllInstances(Type service)
{
this.GetAllInstancesCalled = true;
return Enumerable.Empty<object>();
}
public bool BuildUpCalled;
protected override void BuildUp(object instance)
{
this.BuildUpCalled = true;
}
public bool OnExitCalled;
protected override void OnExit(object sender, ExitEventArgs e)
{
this.OnExitCalled = true;
}
public bool ConfigureResourcesCalled;
protected override void ConfigureResources()
{
this.ConfigureResourcesCalled = true;
base.ConfigureResources();
}
public bool ConfigureCalled;
protected override void Configure()
{
this.ConfigureCalled = true;
base.Configure();
}
public new void Start()
{
base.Start();
}
}
private MyBootstrapperBase<RootViewModel> bootstrapper;
private Mock<IViewManager> viewManager;
private Mock<IWindowManager> windowManager;
[TestFixtureSetUp]
public void FixtureSetUp()
{
Execute.TestExecuteSynchronously = true;
AssemblySource.Assemblies.Clear();
}
[SetUp]
public void SetUp()
{
this.viewManager = new Mock<IViewManager>();
this.windowManager = new Mock<IWindowManager>();
this.bootstrapper = new MyBootstrapperBase<RootViewModel>(this.viewManager.Object, this.windowManager.Object);
}
[Test]
public void SetsUpOnExitHandler()
{
var ctor = typeof(ExitEventArgs).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0];
var ea = (ExitEventArgs)ctor.Invoke(new object[] { 3 });
//this.application.OnExit(ea);
//Assert.True(this.bootstrapper.OnExitCalled);
}
[Test]
public void AssignsIoCGetInstanceToGetInstance()
{
IoC.GetInstance(typeof(string), null);
Assert.True(this.bootstrapper.GetInstanceCalled);
}
[Test]
public void AssignsIoCGetAllInstancesToGetAllInstances()
{
IoC.GetAllInstances(typeof(string));
Assert.True(this.bootstrapper.GetAllInstancesCalled);
}
[Test]
public void AssignsIoCBuildUpToBuildUp()
{
IoC.BuildUp(new object());
Assert.True(this.bootstrapper.BuildUpCalled);
}
[Test]
public void StartAssignsExecuteDispatcher()
{
Execute.Dispatcher = null;
this.bootstrapper.Start();
Assert.NotNull(Execute.Dispatcher); // Can't test any further, unfortunately
}
[Test]
public void StartSetsUpAssemblySource()
{
AssemblySource.Assemblies.Add(null);
this.bootstrapper.Start();
Assert.That(AssemblySource.Assemblies, Is.EquivalentTo(new[] { this.bootstrapper.GetType().Assembly }));
}
[Test]
public void StartCallsConfigureResources()
{
this.bootstrapper.Start();
Assert.True(this.bootstrapper.ConfigureResourcesCalled);
}
[Test]
public void StartCallsConfigure()
{
this.bootstrapper.Start();
Assert.True(this.bootstrapper.ConfigureCalled);
}
}
}

View File

@ -0,0 +1,136 @@
using Moq;
using NUnit.Framework;
using Stylet;
using StyletIoC;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace StyletUnitTests
{
[TestFixture]
public class BootstrapperTests
{
private interface I1 { }
private class C1 : I1 { }
private class RootViewModel { }
private class MyBootstrapper<T> : Bootstrapper<T> where T : class
{
public IContainer Container
{
get { return base.container; }
set { base.container = value; }
}
public new void Configure()
{
base.Configure();
}
public bool ConfigureIoCCalled;
protected override void ConfigureIoC(IStyletIoCBuilder builder)
{
this.ConfigureIoCCalled = true;
builder.Bind<I1>().To<C1>();
base.ConfigureIoC(builder);
}
public new object GetInstance(Type service, string key)
{
return base.GetInstance(service, key);
}
public new IEnumerable<object> GetAllInstances(Type service)
{
return base.GetAllInstances(service);
}
public new void BuildUp(object instance)
{
base.BuildUp(instance);
}
}
private MyBootstrapper<RootViewModel> bootstrapper;
[TestFixtureSetUp]
public void FixtureSetUp()
{
Execute.TestExecuteSynchronously = true;
AssemblySource.Assemblies.Clear();
}
[SetUp]
public void SetUp()
{
this.bootstrapper = new MyBootstrapper<RootViewModel>();
}
[Test]
public void ConfigureBindsRequiredTypes()
{
AssemblySource.Assemblies.Add(this.GetType().Assembly);
this.bootstrapper.Configure();
var ioc = this.bootstrapper.Container;
Assert.IsInstanceOf<WindowManager>(ioc.Get<IWindowManager>());
Assert.IsInstanceOf<IEventAggregator>(ioc.Get<IEventAggregator>());
Assert.IsInstanceOf<ViewManager>(ioc.Get<IViewManager>());
// Test autobinding
Assert.DoesNotThrow(() => ioc.Get<RootViewModel>());
}
[Test]
public void ConfigureCallsConfigureIoCWithCorrectBuilder()
{
AssemblySource.Assemblies.Add(this.GetType().Assembly);
this.bootstrapper.Configure();
var ioc = this.bootstrapper.Container;
Assert.True(this.bootstrapper.ConfigureIoCCalled);
Assert.IsInstanceOf<C1>(ioc.Get<I1>());
}
[Test]
public void GetInstanceMappedToContainer()
{
var container = new Mock<IContainer>();
this.bootstrapper.Container = container.Object;
container.Setup(x => x.Get(typeof(string), "test")).Returns("hello").Verifiable();
var result = this.bootstrapper.GetInstance(typeof(string), "test");
Assert.AreEqual("hello", result);
container.Verify();
}
[Test]
public void GetAllInstancesMappedToContainer()
{
var container = new Mock<IContainer>();
this.bootstrapper.Container = container.Object;
container.Setup(x => x.GetAll(typeof(int), null)).Returns(new object[] { 1, 2, 3 }).Verifiable();
var result = this.bootstrapper.GetAllInstances(typeof(int));
Assert.That(result, Is.EquivalentTo(new[] { 1, 2, 3 }));
container.Verify();
}
[Test]
public void BuildUpMappedToContainer()
{
var container = new Mock<IContainer>();
this.bootstrapper.Container = container.Object;
var instance = new object();
container.Setup(x => x.BuildUp(instance)).Verifiable();
this.bootstrapper.BuildUp(instance);
container.Verify();
}
}
}

View File

@ -9,108 +9,108 @@ using System.Threading.Tasks;
namespace StyletUnitTests
{
interface I1 { }
class C1 : I1 { }
class C2 : I1
{
public C1 C1;
public C2(C1 c1)
{
this.C1 = c1;
}
}
class C3
{
public C1 C1;
public C2 C2;
public C3(C1 c1, C2 c2)
{
this.C1 = c1;
this.C2 = c2;
}
}
class C4
{
public C1 C1;
public C4([Inject("key1")] C1 c1)
{
this.C1 = c1;
}
}
class C5
{
public bool RightConstructorCalled;
public C5(C1 c1, C2 c2 = null, C3 c3 = null, C4 c4 = null)
{
}
public C5(C1 c1, C2 c2, C3 c3 = null)
{
this.RightConstructorCalled = true;
}
public C5(C1 c1, C2 c2)
{
}
}
class C6
{
public bool RightConstructorCalled;
[Inject]
public C6(C1 c1)
{
this.RightConstructorCalled = true;
}
public C6(C1 c1, C2 c2)
{
}
}
class C7
{
[Inject]
public C7()
{
}
[Inject]
public C7(C1 c1)
{
}
}
class C8
{
public IEnumerable<I1> I1s;
public C8(IEnumerable<I1> i1s)
{
this.I1s = i1s;
}
}
class C9
{
public C9(I1 i1)
{
}
}
class C10
{
public C10(ObservableCollection<C10> c1s)
{
}
}
[TestFixture]
public class StyletIoCConstructorInjectionTests
{
interface I1 { }
class C1 : I1 { }
class C2 : I1
{
public C1 C1;
public C2(C1 c1)
{
this.C1 = c1;
}
}
class C3
{
public C1 C1;
public C2 C2;
public C3(C1 c1, C2 c2)
{
this.C1 = c1;
this.C2 = c2;
}
}
class C4
{
public C1 C1;
public C4([Inject("key1")] C1 c1)
{
this.C1 = c1;
}
}
class C5
{
public bool RightConstructorCalled;
public C5(C1 c1, C2 c2 = null, C3 c3 = null, C4 c4 = null)
{
}
public C5(C1 c1, C2 c2, C3 c3 = null)
{
this.RightConstructorCalled = true;
}
public C5(C1 c1, C2 c2)
{
}
}
class C6
{
public bool RightConstructorCalled;
[Inject]
public C6(C1 c1)
{
this.RightConstructorCalled = true;
}
public C6(C1 c1, C2 c2)
{
}
}
class C7
{
[Inject]
public C7()
{
}
[Inject]
public C7(C1 c1)
{
}
}
class C8
{
public IEnumerable<I1> I1s;
public C8(IEnumerable<I1> i1s)
{
this.I1s = i1s;
}
}
class C9
{
public C9(I1 i1)
{
}
}
class C10
{
public C10(ObservableCollection<C10> c1s)
{
}
}
[Test]
public void RecursivelyPopulatesConstructorParams()
{

View File

@ -20,6 +20,15 @@ namespace StyletUnitTests
class C21 : IC2 { }
class C22 : IC2 { }
class C3
{
public List<IC2> C2s;
public C3(IEnumerable<IC2> c2s)
{
this.C2s = c2s.ToList();
}
}
// Tests that Bind() and friends worked was done in StyletIoCGetSingleTests
[Test]
@ -172,5 +181,24 @@ namespace StyletUnitTests
var ioc = builder.BuildContainer();
Assert.Throws<ArgumentNullException>(() => ioc.GetTypeOrAll(null));
}
[Test]
public void CachedGetAllExpressionWorks()
{
// The GetAll creator's instance expression can be cached. This ensures that that works
var builder = new StyletIoCBuilder();
builder.Bind<IC2>().To<C21>();
builder.Bind<IC2>().To<C22>();
builder.Bind<C3>().ToSelf();
var ioc = builder.BuildContainer();
var c2s = ioc.GetAll<IC2>().ToList();
var c3 = ioc.Get<C3>();
Assert.NotNull(c3.C2s);
Assert.AreEqual(2, c3.C2s.Count);
Assert.AreNotEqual(c2s[0], c3.C2s[0]);
Assert.AreNotEqual(c2s[1], c3.C2s[1]);
}
}
}

View File

@ -14,6 +14,14 @@ namespace StyletUnitTests
interface IC1 { }
class C1 : IC1 { }
class C12 : IC1 { }
class C2
{
public C1 C1;
public C2(C1 c1)
{
this.C1 = c1;
}
}
[Test]
public void SelfTransientBindingResolvesGeneric()
@ -210,5 +218,21 @@ namespace StyletUnitTests
var ioc = builder.BuildContainer();
Assert.Throws<ArgumentNullException>(() => ioc.Get(null));
}
[Test]
public void CachedFactoryInstanceExpressionWorks()
{
// The factory's instance expression can be cached. This ensures that that works
var builder = new StyletIoCBuilder();
builder.Bind<C1>().ToFactory(x => new C1());
builder.Bind<C2>().ToSelf();
var ioc = builder.BuildContainer();
var c1 = ioc.Get<C1>();
var c2 = ioc.Get<C2>();
Assert.NotNull(c2.C1);
Assert.AreNotEqual(c1, c2.C1);
}
}
}

View File

@ -188,5 +188,19 @@ namespace StyletUnitTests
Assert.IsInstanceOf<C1>(subject.C1);
}
[Test]
public void BuildUpDoesNotReplaceAlreadySetProperties()
{
var builder = new StyletIoCBuilder();
builder.Bind<C1>().ToSelf();
var ioc = builder.BuildContainer();
var s = new Subject1();
ioc.BuildUp(s);
var firstC1 = s.C1;
ioc.BuildUp(s);
Assert.AreEqual(s.C1, firstC1);
}
}
}

View File

@ -13,6 +13,7 @@ namespace StyletUnitTests
{
interface I1<T> { }
class C1<T> : I1<T> { }
class C12<T> { }
interface I2<T, U> { }
class C2<T, U> : I2<U, T> { }
@ -77,5 +78,12 @@ namespace StyletUnitTests
builder.Bind(typeof(C1<>)).ToSelf();
Assert.Throws<StyletIoCRegistrationException>(() => builder.BuildContainer());
}
[Test]
public void ThrowsIfUnboundGenericDoesNotImplementService()
{
var builder = new StyletIoCBuilder();
Assert.Throws<StyletIoCRegistrationException>(() => builder.Bind(typeof(I1<>)).To(typeof(C12<>)));
}
}
}

View File

@ -55,6 +55,8 @@
<Compile Include="AssemblySourceTests.cs" />
<Compile Include="BindableCollectionTests.cs" />
<Compile Include="BoolToVisibilityConverterTests.cs" />
<Compile Include="BootstrapperBaseTests.cs" />
<Compile Include="BootstrapperTests.cs" />
<Compile Include="CommandActionTests.cs" />
<Compile Include="ConductorAllActiveTests.cs" />
<Compile Include="ConductorNavigatingTests.cs" />

View File

@ -67,6 +67,12 @@ namespace StyletUnitTests
private ViewManager viewManager;
[TestFixtureSetUp]
public void FixtureSetUp()
{
AssemblySource.Assemblies.Clear();
}
[SetUp]
public void SetUp()
{
@ -120,13 +126,13 @@ namespace StyletUnitTests
}
[Test]
public void LocateViewforModelThrowsIfViewNotFound()
public void LocateViewForModelThrowsIfViewNotFound()
{
Assert.Throws<Exception>(() => this.viewManager.LocateViewForModel(typeof(C1)));
}
[Test]
public void LocateViewforModelFindsViewForModel()
public void LocateViewForModelFindsViewForModel()
{
Execute.TestExecuteSynchronously = true;
AssemblySource.Assemblies.Add(Assembly.GetExecutingAssembly());

View File

@ -3,45 +3,271 @@ using NUnit.Framework;
using Stylet;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
namespace StyletUnitTests
{
[TestFixture, RequiresSTA]
public class WindowManagerTests
{
private class MyWindowManager : WindowManager
{
public MyWindowManager(IViewManager viewManager) : base(viewManager) { }
public new Window CreateWindow(object viewModel, bool isDialog)
{
return base.CreateWindow(viewModel, isDialog);
}
}
private class MyWindow : Window
{
public new void OnClosing(CancelEventArgs e)
{
base.OnClosing(e);
}
public bool OnClosedCalled;
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
this.OnClosedCalled = true;
}
public new void OnStateChanged(EventArgs e)
{
base.OnStateChanged(e);
}
}
private Mock<IViewManager> viewManager;
private WindowManager windowManager;
private MyWindowManager windowManager;
[SetUp]
public void SetUp()
{
this.viewManager = new Mock<IViewManager>();
this.windowManager = new WindowManager();
this.windowManager = new MyWindowManager(this.viewManager.Object);
IoC.GetInstance = (service, key) => this.viewManager.Object;
}
[Test]
public void ShowWindowAsksViewManagerForView()
public void CreateWindowAsksViewManagerForView()
{
var model = new object();
this.viewManager.Setup(x => x.CreateViewForModel(model)).Verifiable();
// Don't care if this throws - that's OK
try { this.windowManager.ShowWindow(model); }
try { this.windowManager.CreateWindow(model, false); }
catch (Exception) { }
this.viewManager.VerifyAll();
}
[Test]
public void ShowWindowThrowsIfViewIsntAWindow()
public void CreateWindowThrowsIfViewIsntAWindow()
{
var model = new object();
this.viewManager.Setup(x => x.CreateViewForModel(model)).Returns(new UIElement());
Assert.Throws<Exception>(() => this.windowManager.ShowWindow(model));
Assert.Throws<Exception>(() => this.windowManager.CreateWindow(model, false));
}
[Test]
public void CreateWindowBindsViewToModel()
{
var model = new object();
var window = new Window();
this.viewManager.Setup(x => x.CreateViewForModel(model)).Returns(window);
this.windowManager.CreateWindow(model, false);
this.viewManager.Verify(x => x.BindViewToModel(window, model));
}
[Test]
public void CreateWindowSetsUpTitleBindingIfViewModelIsIHaveDisplayName()
{
var model = new Screen();
var window = new Window();
this.viewManager.Setup(x => x.CreateViewForModel(model)).Returns(window);
this.windowManager.CreateWindow(model, false);
var e = window.GetBindingExpression(Window.TitleProperty);
Assert.AreEqual(BindingMode.TwoWay, e.ParentBinding.Mode);
Assert.AreEqual("DisplayName", e.ParentBinding.Path.Path);
}
[Test]
public void CreateWindowActivatesViewModel()
{
var model = new Mock<IScreen>();
this.viewManager.Setup(x => x.CreateViewForModel(model.Object)).Returns(new Window());
this.windowManager.CreateWindow(model.Object, false);
model.Verify(x => x.Activate());
}
[Test]
public void WindowStateChangedActivatesIfMaximized()
{
var model = new Mock<IScreen>();
var window = new MyWindow();
this.viewManager.Setup(x => x.CreateViewForModel(model.Object)).Returns(window);
this.windowManager.CreateWindow(model.Object, false);
window.WindowState = WindowState.Maximized;
window.OnStateChanged(EventArgs.Empty);
model.Verify(x => x.Activate());
}
[Test]
public void WindowStateChangedActivatesIfNormal()
{
var model = new Mock<IScreen>();
var window = new MyWindow();
this.viewManager.Setup(x => x.CreateViewForModel(model.Object)).Returns(window);
this.windowManager.CreateWindow(model.Object, false);
window.WindowState = WindowState.Normal;
window.OnStateChanged(EventArgs.Empty);
model.Verify(x => x.Activate());
}
[Test]
public void WindowStateChangedDeactivatesIfMinimized()
{
var model = new Mock<IScreen>();
var window = new MyWindow();
this.viewManager.Setup(x => x.CreateViewForModel(model.Object)).Returns(window);
this.windowManager.CreateWindow(model.Object, false);
window.WindowState = WindowState.Minimized;
window.OnStateChanged(EventArgs.Empty);
model.Verify(x => x.Deactivate());
}
[Test]
public void WindowClosingDoesNothingIfAlreadyCancelled()
{
var model = new Screen();
var window = new MyWindow();
this.viewManager.Setup(x => x.CreateViewForModel(model)).Returns(window);
this.windowManager.CreateWindow(model, false);
window.OnClosing(new CancelEventArgs(true));
}
[Test]
public void WindowClosingCancelsIfCanCloseAsyncReturnsSynchronousFalse()
{
var model = new Mock<IScreen>();
var window = new MyWindow();
this.viewManager.Setup(x => x.CreateViewForModel(model.Object)).Returns(window);
this.windowManager.CreateWindow(model.Object, false);
model.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(false));
var ea = new CancelEventArgs();
window.OnClosing(ea);
Assert.True(ea.Cancel);
}
[Test]
public void WindowClosingDoesNotCancelIfCanCloseAsyncReturnsSynchronousTrue()
{
var model = new Mock<IScreen>();
var window = new MyWindow();
this.viewManager.Setup(x => x.CreateViewForModel(model.Object)).Returns(window);
this.windowManager.CreateWindow(model.Object, false);
model.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(true));
var ea = new CancelEventArgs();
window.OnClosing(ea);
Assert.False(ea.Cancel);
}
[Test]
public void WindowClosingCancelsIfCanCloseAsyncReturnsAsynchronousFalse()
{
var model = new Mock<IScreen>();
var window = new MyWindow();
this.viewManager.Setup(x => x.CreateViewForModel(model.Object)).Returns(window);
this.windowManager.CreateWindow(model.Object, false);
model.Setup(x => x.CanCloseAsync()).Returns(Task.Delay(1).ContinueWith(t => false));
var ea = new CancelEventArgs();
window.OnClosing(ea);
Assert.True(ea.Cancel);
}
[Test]
public void WindowClosingCancelsIfCanCloseAsyncReturnsAsynchronousTrue()
{
var model = new Mock<IScreen>();
var window = new MyWindow();
this.viewManager.Setup(x => x.CreateViewForModel(model.Object)).Returns(window);
this.windowManager.CreateWindow(model.Object, false);
model.Setup(x => x.CanCloseAsync()).Returns(Task.Delay(1).ContinueWith(t => true));
var ea = new CancelEventArgs();
window.OnClosing(ea);
Assert.True(ea.Cancel);
}
[Test]
public void WindowClosingClosesWindowIfCanCloseAsyncCompletesTrue()
{
var model = new Mock<IScreen>();
var window = new MyWindow();
this.viewManager.Setup(x => x.CreateViewForModel(model.Object)).Returns(window);
this.windowManager.CreateWindow(model.Object, false);
var tcs = new TaskCompletionSource<bool>();
model.Setup(x => x.CanCloseAsync()).Returns(tcs.Task);
window.OnClosing(new CancelEventArgs());
model.Verify(x => x.Close(), Times.Never);
tcs.SetResult(true);
model.Verify(x => x.Close(), Times.Once);
Assert.True(window.OnClosedCalled);
// Check it didn't call WindowClosing again - just the first time
model.Verify(x => x.CanCloseAsync(), Times.Once);
}
[Test]
public void CloseItemDoesNothingIfItemIsWrong()
{
var model = new Screen();
var window = new MyWindow();
this.viewManager.Setup(x => x.CreateViewForModel(model)).Returns(window);
this.windowManager.CreateWindow(model, false);
((IChildDelegate)model.Parent).CloseItem(new object());
}
[Test]
public void CloseItemDoesNothingIfCanCloseReturnsFalse()
{
var model = new Mock<IScreen>();
var window = new MyWindow();
this.viewManager.Setup(x => x.CreateViewForModel(model.Object)).Returns(window);
object parent = null;
model.SetupSet(x => x.Parent = It.IsAny<object>()).Callback((object x) => parent = x);
this.windowManager.CreateWindow(model.Object, false);
model.Setup(x => x.CanCloseAsync()).Returns(Task.Delay(1).ContinueWith(t => false));
((IChildDelegate)parent).CloseItem(model.Object);
}
[Test]
public void CloseItemClosesAndWindowViewModelIfCanCloseReturnsTrue()
{
var model = new Mock<IScreen>();
var window = new MyWindow();
this.viewManager.Setup(x => x.CreateViewForModel(model.Object)).Returns(window);
object parent = null;
model.SetupSet(x => x.Parent = It.IsAny<object>()).Callback((object x) => parent = x);
this.windowManager.CreateWindow(model.Object, true);
model.Setup(x => x.CanCloseAsync()).ReturnsAsync(true);
((IChildDelegate)parent).CloseItem(model.Object);
model.Verify(x => x.Close());
Assert.True(window.OnClosedCalled);
}
}
}