Stylet/StyletUnitTests/ConductorOneActiveTests.cs

463 lines
16 KiB
C#

using Moq;
using NUnit.Framework;
using Stylet;
using System;
using System.Threading.Tasks;
namespace StyletUnitTests
{
[TestFixture]
public class ConductorOneActiveTests
{
public interface IMyScreen : IScreen, IDisposable
{ }
private class MyConductor : Conductor<IScreen>.Collection.OneActive
{
public bool CanCloseValue = true;
public override async Task<bool> CanCloseAsync()
{
return this.CanCloseValue && await base.CanCloseAsync();
}
}
private MyConductor conductor;
[SetUp]
public void SetUp()
{
this.conductor = new MyConductor();
}
[Test]
public void NoActiveItemsBeforeAnyItemsActivated()
{
Assert.IsEmpty(this.conductor.Items);
}
[Test]
public void ActivatingItemActivatesAndAddsToItems()
{
var screen = new Mock<IScreen>();
((IScreenState)this.conductor).Activate();
this.conductor.ActivateItem(screen.Object);
screen.Verify(x => x.Activate());
screen.Verify(x => x.Deactivate());
Assert.AreEqual(screen.Object, this.conductor.ActiveItem);
Assert.That(this.conductor.Items, Is.EquivalentTo(new[] { screen.Object }));
}
[Test]
public void ActivatingItemDeactivatesPreviousItem()
{
var screen1 = new Mock<IScreen>();
var screen2 = new Mock<IScreen>();
((IScreenState)this.conductor).Activate();
this.conductor.ActivateItem(screen1.Object);
this.conductor.ActivateItem(screen2.Object);
screen1.Verify(x => x.Deactivate());
screen2.Verify(x => x.Activate());
Assert.AreEqual(screen2.Object, this.conductor.ActiveItem);
Assert.AreEqual(new[] { screen1.Object, screen2.Object }, this.conductor.Items);
}
[Test]
public void SettingActiveItemActivatesItem()
{
var screen = new Mock<IScreen>();
((IScreenState)this.conductor).Activate();
this.conductor.ActiveItem = screen.Object;
screen.Verify(x => x.Activate());
Assert.AreEqual(this.conductor.ActiveItem, screen.Object);
}
[Test]
public void ClosingActiveItemChoosesPreviousItemIfAvailable()
{
var screen1 = new Mock<IScreen>();
var screen2 = new Mock<IScreen>();
var screen3 = new Mock<IScreen>();
((IScreenState)this.conductor).Activate();
this.conductor.Items.AddRange(new[] { screen1.Object, screen2.Object, screen3.Object });
this.conductor.ActivateItem(screen2.Object);
screen2.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(true));
this.conductor.CloseItem(screen2.Object);
Assert.AreEqual(screen1.Object, this.conductor.ActiveItem);
Assert.AreEqual(new[] { screen1.Object, screen3.Object }, this.conductor.Items);
}
[Test]
public void ClosingActiveItemChoosesNextItemIfNoPreviousItem()
{
var screen1 = new Mock<IScreen>();
var screen2 = new Mock<IScreen>();
var screen3 = new Mock<IScreen>();
((IScreenState)this.conductor).Activate();
this.conductor.Items.AddRange(new[] { screen1.Object, screen2.Object, screen3.Object });
this.conductor.ActivateItem(screen3.Object);
screen3.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(true));
this.conductor.CloseItem(screen3.Object);
Assert.AreEqual(screen2.Object, this.conductor.ActiveItem);
Assert.AreEqual(new[] { screen1.Object, screen2.Object }, this.conductor.Items);
}
[Test]
public void ActivateItemDoesNotActivateIfConductorIsNotActive()
{
var screen = new Mock<IScreen>();
this.conductor.ActivateItem(screen.Object);
screen.Verify(x => x.Activate(), Times.Never);
}
[Test]
public void ActivateItemDoesActiveIfConductorIsActive()
{
var screen = new Mock<IScreen>();
((IScreenState)this.conductor).Activate();
this.conductor.ActivateItem(screen.Object);
screen.Verify(x => x.Activate());
}
[Test]
public void DeactiveDeactivatesItems()
{
var screen = new Mock<IScreen>();
((IScreenState)this.conductor).Activate();
this.conductor.ActivateItem(screen.Object);
((IScreenState)this.conductor).Deactivate();
screen.Verify(x => x.Deactivate());
}
[Test]
public void ClosingClosesAllItems()
{
var screen = new Mock<IMyScreen>();
screen.Setup(x => x.Close()).Callback(() => System.Diagnostics.Debug.WriteLine("FOO"));
((IScreenState)this.conductor).Activate();
this.conductor.ActivateItem(screen.Object);
((IScreenState)this.conductor).Close();
screen.Verify(x => x.Close(), Times.Once());
screen.Verify(x => x.Dispose(), Times.Once());
Assert.AreEqual(0, this.conductor.Items.Count);
}
[Test]
public void ConductorCanCloseIfAllItemsCanClose()
{
var screen1 = new Mock<IScreen>();
var screen2 = new Mock<IScreen>();
screen1.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(true));
screen2.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(true));
this.conductor.Items.AddRange(new[] { screen1.Object, screen2.Object });
Assert.IsTrue(this.conductor.CanCloseAsync().Result);
}
[Test]
public void ConductorCanNotCloseIfAnyItemCanNotClose()
{
var screen1 = new Mock<IScreen>();
var screen2 = new Mock<IScreen>();
screen1.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(true));
screen2.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(false));
this.conductor.Items.AddRange(new[] { screen1.Object, screen2.Object });
Assert.IsFalse(this.conductor.CanCloseAsync().Result);
}
[Test]
public void ConductorCanCloseAsyncCallsCanCloseOnSelfBeforeChildren()
{
var screen = new Mock<IScreen>();
this.conductor.ActivateItem(screen.Object);
this.conductor.CanCloseValue = false;
Assert.IsFalse(this.conductor.CanCloseAsync().Result);
screen.Verify(x => x.CanCloseAsync(), Times.Never());
}
[Test]
public void AddingItemSetsParent()
{
var screen = new Mock<IScreen>();
this.conductor.Items.Add(screen.Object);
screen.VerifySet(x => x.Parent = this.conductor);
}
[Test]
public void AddingItemDoesNotChangeActiveItem()
{
var screen1 = new Mock<IScreen>();
var screen2 = new Mock<IScreen>();
((IScreenState)this.conductor).Activate();
this.conductor.ActivateItem(screen1.Object);
// This is an implementation detail
screen1.Verify(x => x.Deactivate(), Times.Once);
screen1.Verify(x => x.Activate(), Times.Once);
this.conductor.Items.Add(screen2.Object);
Assert.AreEqual(this.conductor.ActiveItem, screen1.Object);
screen2.Verify(x => x.Activate(), Times.Never);
screen1.Verify(x => x.Deactivate(), Times.Once); // The one deactivate from earlier
}
[Test]
public void RemovingItemClosesAndRemovesParent()
{
var screen = new Mock<IMyScreen>();
screen.SetupGet(x => x.Parent).Returns(this.conductor);
this.conductor.Items.Add(screen.Object);
this.conductor.Items.Remove(screen.Object);
screen.VerifySet(x => x.Parent = null);
screen.Verify(x => x.Close());
}
[Test]
public void RemovingItemDisposesIfDisposeChildrenIsTrue()
{
var screen = new Mock<IMyScreen>();
this.conductor.Items.Add(screen.Object);
this.conductor.Items.Remove(screen.Object);
screen.Verify(x => x.Dispose());
}
[Test]
public void RemovingItemDoesNotDisposeIfDisposeChildrenIsFalse()
{
var screen = new Mock<IMyScreen>();
this.conductor.DisposeChildren = false;
this.conductor.Items.Add(screen.Object);
this.conductor.Items.Remove(screen.Object);
screen.Verify(x => x.Dispose(), Times.Never);
}
[Test]
public void RemovingActiveItemActivatesAnotherItem()
{
((IScreenState)this.conductor).Activate();
var screen1 = new Mock<IMyScreen>();
var screen2 = new Mock<IMyScreen>();
this.conductor.ActivateItem(screen1.Object);
this.conductor.Items.Add(screen2.Object);
this.conductor.Items.Remove(screen1.Object);
Assert.AreEqual(this.conductor.ActiveItem, screen2.Object);
screen2.Verify(x => x.Activate());
screen1.Verify(x => x.Close());
}
[Test]
public void AddingItemTwiceDoesNotResultInDuplicates()
{
var screen = new Mock<IScreen>();
this.conductor.ActivateItem(screen.Object);
this.conductor.ActivateItem(screen.Object);
Assert.AreEqual(1, this.conductor.Items.Count);
}
[Test]
public void DeactivateItemDeactivatesItemButDoesNotRemoveFromItems()
{
var screen = new Mock<IScreen>();
this.conductor.ActivateItem(screen.Object);
this.conductor.DeactivateItem(screen.Object);
screen.Verify(x => x.Deactivate());
Assert.That(this.conductor.Items, Is.EquivalentTo(new[] { screen.Object }));
}
[Test]
public void CloseItemDoesNothingIfItemCanNotClose()
{
var screen = new Mock<IMyScreen>();
this.conductor.ActivateItem(screen.Object);
this.conductor.CloseItem(screen.Object);
screen.Verify(x => x.Close(), Times.Never);
screen.Verify(x => x.Dispose(), Times.Never);
Assert.That(this.conductor.Items, Is.EquivalentTo(new[] { screen.Object }));
}
[Test]
public void CloseItemDeactivatesItemAndRemovesFromItemsIfItemCanClose()
{
var screen = new Mock<IMyScreen>();
screen.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(true));
this.conductor.ActivateItem(screen.Object);
this.conductor.CloseItem(screen.Object);
screen.Verify(x => x.Close());
Assert.AreEqual(0, this.conductor.Items.Count);
}
[Test]
public void CloseItemDisposesIfDisposeChildrenIsTrue()
{
var screen = new Mock<IMyScreen>();
screen.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(true));
this.conductor.ActivateItem(screen.Object);
this.conductor.CloseItem(screen.Object);
screen.Verify(x => x.Dispose());
}
[Test]
public void CloseItemDoesNotDisposeIfDisposeChildrenIsFalse()
{
var screen = new Mock<IMyScreen>();
this.conductor.DisposeChildren = false;
screen.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(true));
this.conductor.ActivateItem(screen.Object);
this.conductor.CloseItem(screen.Object);
screen.Verify(x => x.Dispose(), Times.Never);
}
[Test]
public void ClosingConductorClosesActiveItem()
{
var screen1 = new Mock<IMyScreen>();
screen1.SetupGet(x => x.Parent).Returns(this.conductor);
this.conductor.ActivateItem(screen1.Object);
((IScreenState)this.conductor).Close();
screen1.Verify(x => x.Close());
screen1.Verify(x => x.Dispose());
screen1.VerifySet(x => x.Parent = null);
}
[Test]
public void ClosesItemIfItemRequestsClose()
{
var screen = new Mock<IMyScreen>();
this.conductor.ActivateItem(screen.Object);
screen.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(true));
((IChildDelegate)this.conductor).CloseItem(screen.Object);
screen.Verify(x => x.Close());
screen.Verify(x => x.Dispose());
Assert.Null(this.conductor.ActiveItem);
}
[Test]
public void ClearingItemsClosesAndDisposes()
{
var screen1 = new Mock<IMyScreen>();
var screen2 = new Mock<IMyScreen>();
this.conductor.ActivateItem(screen1.Object);
this.conductor.ActivateItem(screen2.Object);
this.conductor.Items.Clear();
screen1.Verify(x => x.Deactivate());
screen1.Verify(x => x.Close());
screen1.Verify(x => x.Dispose());
screen2.Verify(x => x.Close());
screen2.Verify(x => x.Dispose());
}
[Test]
public void ClosingDoesNotCloseThenDeactivateActiveItem()
{
// If it calls Close then Deactivate, this causes OnInitialActivate to be called again (in order to
// activate the screen before deactivating it again).
var screen = new Mock<IMyScreen>();
this.conductor.ActivateItem(screen.Object);
screen.Invocations.Clear();
int sequence = 0;
screen.Setup(x => x.Deactivate()).Callback(() => Assert.AreEqual(0, sequence++));
screen.Setup(x => x.Close()).Callback(() => Assert.AreEqual(1, sequence++));
((IScreenState)this.conductor).Close();
Assert.AreEqual(2, sequence);
}
[Test]
public void ReplacingActiveItemDoesNotCloseThenDeactivate()
{
// If it calls Close then Deactivate, this causes OnInitialActivate to be called again (in order to
// activate the screen before deactivating it again).
var screen1 = new Mock<IMyScreen>();
var screen2 = new Mock<IMyScreen>();
this.conductor.ActivateItem(screen1.Object);
screen1.Invocations.Clear();
int sequence = 0;
screen1.Setup(x => x.Deactivate()).Callback(() => Assert.AreEqual(0, sequence++));
screen1.Setup(x => x.Close()).Callback(() => Assert.AreEqual(1, sequence++));
this.conductor.Items[0] = screen2.Object;
Assert.AreEqual(2, sequence);
}
[Test]
public void RemovingActiveItemDoesNotCloseThenDeactivate()
{
// If it calls Close then Deactivate, this causes OnInitialActivate to be called again (in order to
// activate the screen before deactivating it again).
var screen1 = new Mock<IMyScreen>();
var screen2 = new Mock<IMyScreen>();
this.conductor.ActivateItem(screen1.Object);
screen1.Invocations.Clear();
int sequence = 0;
screen1.Setup(x => x.Deactivate()).Callback(() => Assert.AreEqual(0, sequence++));
screen1.Setup(x => x.Close()).Callback(() => Assert.AreEqual(1, sequence++));
this.conductor.Items.RemoveAt(0);
Assert.AreEqual(2, sequence);
}
[Test]
public void ClosingTheActiveItemDoesNotDisposeItTwice()
{
var screen = new Mock<IMyScreen>();
screen.Setup(x => x.CanCloseAsync()).ReturnsAsync(true);
this.conductor.ActivateItem(screen.Object);
this.conductor.CloseItem(screen.Object);
screen.Verify(x => x.Dispose(), Times.Once());
}
[Test]
public void ClosingTheNonActiveItemDoesNotDisposeItTwice()
{
var screen1 = new Mock<IMyScreen>();
var screen2 = new Mock<IMyScreen>();
screen1.Setup(x => x.CanCloseAsync()).ReturnsAsync(true);
this.conductor.ActivateItem(screen1.Object);
this.conductor.ActivateItem(screen2.Object);
this.conductor.CloseItem(screen1.Object);
screen1.Verify(x => x.Dispose(), Times.Once());
}
}
}