using System.IO; using UnitTestSharp; using Vellum; namespace Ariadne.Vellum.UnitTests { public class TriggerWaitConverterTests : TestFixture { public class FromNodeTests : TestFixture { [IgnoreTest] public TriggerWait Reload(TriggerWait wait) { SaveSession session = ArcConverterTests.Session(); return (TriggerWait)session.FromNode(session.ToNode(wait, typeof(TriggerWait)), typeof(TriggerWait)); } [IgnoreTest] public SaveNode Saved(TriggerWait wait, SaveSession session) { return session.ToNode(wait, typeof(TriggerWait)).Resolved; } public void WaitInProgress_LoadsWithItsProgress() { var door = new Trigger(); TriggerWait wait = TriggerConverterTests.WaitOn(capacity: 3, requiresAll: true, door, new Trigger()); door.Raise(); TriggerWait loaded = Reload(wait); CheckEqual(3, loaded.Triggers.Length); CheckEqual(2, loaded.Count); CheckEqual(wait.Wait, loaded.Wait); CheckTrue(loaded.RequiresAll); CheckEqual(1, loaded.Seen); CheckEqual(-1, loaded.Fired); CheckFalse(loaded.Complete); } public void WaitThatIsOver_LoadsWithTheTriggerThatEndedIt() { var door = new Trigger(); TriggerWait wait = TriggerConverterTests.WaitOn(capacity: 2, requiresAll: false, new Trigger(), door); door.Raise(); TriggerWait loaded = Reload(wait); CheckTrue(loaded.Complete); CheckEqual(1, loaded.Fired); CheckTrue(ReferenceEquals(loaded.Triggers[1], loaded.Result)); } public void WaitThatNeverBegan_LoadsEmpty() { TriggerWait loaded = Reload(new TriggerWait(capacity: 4)); CheckEqual(4, loaded.Triggers.Length); CheckEqual(0, loaded.Count); CheckEqual(0, loaded.Wait); CheckFalse(loaded.Complete); } public void WaitThatExpired_LoadsOverWithNothingWaitedOn() { TriggerWait wait = TriggerConverterTests.WaitOn(capacity: 2, requiresAll: false, new Trigger(), new Trigger()); wait.Expire(); TriggerWait loaded = Reload(wait); CheckEqual(2, loaded.Triggers.Length); CheckEqual(0, loaded.Count); CheckEqual(wait.Wait, loaded.Wait); CheckTrue(loaded.Complete); CheckNull(loaded.Result); } public void WaitOfTheMostTriggers_Loads() { TriggerWait loaded = Reload(new TriggerWait(TriggerWait.MaximumTriggers)); CheckEqual(TriggerWait.MaximumTriggers, loaded.Triggers.Length); } public void WaitOfTheMostTriggersAllRaised_LoadsComplete() { var triggers = new Trigger[TriggerWait.MaximumTriggers]; for (int i = 0; i < triggers.Length; ++i) { triggers[i] = new Trigger(); } TriggerWait wait = TriggerConverterTests.WaitOn(TriggerWait.MaximumTriggers, requiresAll: true, triggers); foreach (Trigger trigger in triggers) { trigger.Raise(); } TriggerWait loaded = Reload(wait); CheckTrue(loaded.Complete); CheckEqual(TriggerWait.MaximumTriggers - 1, loaded.Fired); } public void LoadedTriggers_AreSubscribedToTheLoadedWait() { var door = new Trigger(); TriggerWait wait = TriggerConverterTests.WaitOn(capacity: 1, requiresAll: false, door); TriggerWait loaded = Reload(wait); CheckEqual(1, loaded.Triggers[0].SubscriptionCount); CheckTrue(ReferenceEquals(loaded.Subscriptions[0], loaded.Triggers[0].SubscriptionAt(0))); } public void NodeWithNoTriggers_Throws() { SaveSession session = ArcConverterTests.Session(); SaveNode node = Saved(new TriggerWait(capacity: 1), session); node.Entries.Remove("triggers"); CheckThrow(typeof(InvalidDataException)); session.FromNode(node, typeof(TriggerWait)); } public void CapacityOfZero_Throws() { SaveSession session = ArcConverterTests.Session(); SaveNode node = Saved(new TriggerWait(capacity: 1), session); node.Entries["capacity"] = session.ToNode(0); CheckThrow(typeof(InvalidDataException)); session.FromNode(node, typeof(TriggerWait)); } public void CapacityPastTheMaximum_Throws() { SaveSession session = ArcConverterTests.Session(); SaveNode node = Saved(new TriggerWait(capacity: 1), session); node.Entries["capacity"] = session.ToNode(TriggerWait.MaximumTriggers + 1); CheckThrow(typeof(InvalidDataException)); session.FromNode(node, typeof(TriggerWait)); } public void MoreTriggersThanTheCapacity_Throws() { SaveSession session = ArcConverterTests.Session(); TriggerWait wait = TriggerConverterTests.WaitOn(capacity: 2, requiresAll: false, new Trigger(), new Trigger()); SaveNode node = Saved(wait, session); node.Entries["capacity"] = session.ToNode(1); CheckThrow(typeof(InvalidDataException)); session.FromNode(node, typeof(TriggerWait)); } public void TriggerThatEndedItPastTheOnesListed_Throws() { SaveSession session = ArcConverterTests.Session(); var door = new Trigger(); SaveNode node = Saved(TriggerConverterTests.WaitOn(capacity: 1, requiresAll: false, door), session); node.Entries["fired"] = session.ToNode(1); CheckThrow(typeof(InvalidDataException)); session.FromNode(node, typeof(TriggerWait)); } public void TriggerThatEndedItBelowNone_Throws() { SaveSession session = ArcConverterTests.Session(); SaveNode node = Saved(new TriggerWait(capacity: 1), session); node.Entries["fired"] = session.ToNode(-2); CheckThrow(typeof(InvalidDataException)); session.FromNode(node, typeof(TriggerWait)); } public void RaisedBitsPastTheTriggersListed_Throw() { SaveSession session = ArcConverterTests.Session(); TriggerWait wait = TriggerConverterTests.WaitOn(capacity: 2, requiresAll: true, new Trigger(), new Trigger()); SaveNode node = Saved(wait, session); node.Entries["seen"] = session.ToNode(4); CheckThrow(typeof(InvalidDataException)); session.FromNode(node, typeof(TriggerWait)); } public void WaitThatIsOverButSaysNoTriggerEndedIt_Throws() { SaveSession session = ArcConverterTests.Session(); SaveNode node = Saved( TriggerConverterTests.WaitOn(capacity: 1, requiresAll: false, new Trigger()), session); node.Entries["seen"] = session.ToNode(1); CheckThrow(typeof(InvalidDataException)); session.FromNode(node, typeof(TriggerWait)); } public void WaitThatGoesOnButSaysATriggerEndedIt_Throws() { SaveSession session = ArcConverterTests.Session(); SaveNode node = Saved( TriggerConverterTests.WaitOn(capacity: 1, requiresAll: false, new Trigger()), session); node.Entries["fired"] = session.ToNode(0); CheckThrow(typeof(InvalidDataException)); session.FromNode(node, typeof(TriggerWait)); } } /// /// A condition no wait could be paused in, since only latches and their inverses are saved. /// public class OddCondition : Condition { public override bool IsSet => true; } /// /// A slot that counts the times it is woken. /// public class CountingSlot : WakeSlot { public int Wakes; public override void Wake() { ++Wakes; } } public class FromNodeOnConditionsTests : TestFixture { [IgnoreTest] public TriggerWait Reload(TriggerWait wait) { SaveSession session = ArcConverterTests.Session(); return (TriggerWait)session.FromNode(session.ToNode(wait, typeof(TriggerWait)), typeof(TriggerWait)); } [IgnoreTest] public SaveNode Saved(TriggerWait wait, SaveSession session) { return session.ToNode(wait, typeof(TriggerWait)).Resolved; } public void WaitInProgress_LoadsOnConditionsWithItsProgress() { TriggerWait wait = LatchConverterTests.WaitOn(capacity: 3, requiresAll: true, new Latch(initiallySet: true), new Latch()); TriggerWait loaded = Reload(wait); CheckTrue(loaded.OnConditions); CheckEqual(3, loaded.Conditions.Length); CheckEqual(0, loaded.Triggers.Length); CheckEqual(3, loaded.Subscriptions.Length); CheckEqual(2, loaded.Count); CheckEqual(wait.Wait, loaded.Wait); CheckTrue(loaded.RequiresAll); CheckTrue(loaded.Conditions[0].IsSet); CheckFalse(loaded.Conditions[1].IsSet); CheckFalse(loaded.Complete); } public void WaitOnAnInverse_LoadsTheInverseOfTheLoadedLatch() { var door = new Latch(initiallySet: true); TriggerWait wait = LatchConverterTests.WaitOn(capacity: 1, requiresAll: false, door.Inverse); TriggerWait loaded = Reload(wait); var inverse = (InvertedLatch)loaded.Conditions[0]; CheckTrue(inverse.Original.IsSet); CheckTrue(ReferenceEquals(inverse.Original.Inverse, inverse)); CheckFalse(loaded.Complete); } public void WaitOnALatchAndItsInverse_LoadsOneLatch() { var door = new Latch(); TriggerWait wait = LatchConverterTests.WaitOn(capacity: 2, requiresAll: false, door, door.Inverse); TriggerWait loaded = Reload(wait); var latch = (Latch)loaded.Conditions[0]; CheckTrue(ReferenceEquals(latch.Inverse, loaded.Conditions[1])); } public void WaitThatIsSatisfiedButNotFinished_LoadsOverWithTheConditionThatAnswersIt() { var door = new Latch(initiallySet: true); TriggerWait wait = LatchConverterTests.WaitOn(capacity: 2, requiresAll: false, new Latch(), door); TriggerWait loaded = Reload(wait); CheckTrue(loaded.Complete); CheckTrue(ReferenceEquals(loaded.Conditions[1], loaded.ConditionResult)); } public void WaitThatWasFinished_LoadsOverWithNothingWaitedOn() { TriggerWait wait = LatchConverterTests.WaitOn(capacity: 2, requiresAll: false, new Latch(), new Latch()); wait.Finish(); TriggerWait loaded = Reload(wait); CheckTrue(loaded.OnConditions); CheckEqual(0, loaded.Count); CheckEqual(wait.Wait, loaded.Wait); CheckTrue(loaded.Complete); CheckNull(loaded.ConditionResult); } public void WaitThatNeverBegan_LoadsEmptyOnConditions() { TriggerWait loaded = Reload(new TriggerWait(capacity: 4, onConditions: true)); CheckEqual(4, loaded.Conditions.Length); CheckEqual(0, loaded.Count); CheckFalse(loaded.Complete); } public void LoadedConditions_AreSubscribedToTheLoadedWait() { TriggerWait wait = LatchConverterTests.WaitOn(capacity: 1, requiresAll: false, new Latch()); TriggerWait loaded = Reload(wait); CheckEqual(1, loaded.Conditions[0].SubscriptionCount); CheckTrue(ReferenceEquals(loaded.Subscriptions[0], loaded.Conditions[0].SubscriptionAt(0))); } public void LoadedWait_WakesItsArcWhenItsLatchIsSet() { var door = new Latch(); TriggerWait wait = LatchConverterTests.WaitOn(capacity: 1, requiresAll: false, door); TriggerWait loaded = Reload(wait); var slot = new CountingSlot(); loaded.Attach(slot); ((Latch)loaded.Conditions[0]).Set(); CheckEqual(1, slot.Wakes); } public void ConditionThatIsNotALatch_CannotBeSaved() { SaveSession session = ArcConverterTests.Session(); TriggerWait wait = LatchConverterTests.WaitOn(capacity: 1, requiresAll: false, new OddCondition()); CheckThrow(typeof(System.InvalidOperationException)); session.ToNode(wait, typeof(TriggerWait)); } public void MoreConditionsThanTheCapacity_Throws() { SaveSession session = ArcConverterTests.Session(); TriggerWait wait = LatchConverterTests.WaitOn(capacity: 2, requiresAll: false, new Latch(), new Latch()); SaveNode node = Saved(wait, session); node.Entries["capacity"] = session.ToNode(1); CheckThrow(typeof(InvalidDataException)); session.FromNode(node, typeof(TriggerWait)); } public void ConditionsThatAreNotAList_Throw() { SaveSession session = ArcConverterTests.Session(); SaveNode node = Saved(new TriggerWait(capacity: 1, onConditions: true), session); node.Entries["conditions"] = session.ToNode(5); CheckThrow(typeof(InvalidDataException)); session.FromNode(node, typeof(TriggerWait)); } public void ConditionWithNoLatch_Throws() { SaveSession session = ArcConverterTests.Session(); TriggerWait wait = LatchConverterTests.WaitOn(capacity: 1, requiresAll: false, new Latch()); SaveNode node = Saved(wait, session); node.Entries["conditions"].Items[0].Entries.Remove("latch"); CheckThrow(typeof(InvalidDataException)); session.FromNode(node, typeof(TriggerWait)); } public void ConditionWithNoInvertedFlag_Throws() { SaveSession session = ArcConverterTests.Session(); TriggerWait wait = LatchConverterTests.WaitOn(capacity: 1, requiresAll: false, new Latch()); SaveNode node = Saved(wait, session); node.Entries["conditions"].Items[0].Entries.Remove("inverted"); CheckThrow(typeof(InvalidDataException)); session.FromNode(node, typeof(TriggerWait)); } } } }