using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Ariadne.UnitTests;
using UnitTestSharp;
using Vellum;
namespace Ariadne.Vellum.UnitTests
{
///
/// Saves arcs paused inside passages that call themselves, directly or through others.
///
public class RecursionSaveTests : TestFixture
{
public static ScriptType Reloaded(ScriptType script)
where ScriptType : Arc
{
SaveSession session = ArcConverterTests.Session();
return (ScriptType)session.FromNode(session.ToNode(script, typeof(ScriptType)), typeof(ScriptType));
}
public static Countdown PausedAtTheThirdLevel(ArcTests.Gates gates)
{
var script = new Countdown();
script.Tick(gates, TestTicks.Fresh());
foreach (string gate in new[] { "go1", "go2" })
{
gates.Open.Add(gate);
script.Tick(gates, TestTicks.Fresh());
}
return script;
}
public class ToNodeTests : TestFixture
{
public void EachLevel_IsATableInsideTheLevelAbove()
{
SaveSession session = ArcConverterTests.Session();
Countdown paused = PausedAtTheThirdLevel(new ArcTests.Gates());
SaveNode locals = session.ToNode(paused, typeof(Countdown)).RequireEntry(ArcRecord.LocalsKey);
SaveNode first = locals.RequireEntry("Run.start/");
SaveNode second = first.RequireEntry("Descend.deeper/");
SaveNode third = second.RequireEntry("Descend.deeper/");
CheckEqual(new[] { "Descend.deeper/", "Descend.level", "Descend.mine" },
first.Entries.Keys.OrderBy(key => key, StringComparer.Ordinal).ToArray());
CheckEqual("1", first.RequireEntry("Descend.level").Text);
CheckEqual("20", second.RequireEntry("Descend.mine").Text);
CheckEqual("30", third.RequireEntry("Descend.mine").Text);
}
public void RunInACycle_KeepsItsLocalsAtTheTopAndEachLapInsideTheOneAbove()
{
SaveSession session = ArcConverterTests.Session();
var gates = new ArcTests.Gates();
var script = new Relapsing();
script.Tick(gates, TestTicks.Fresh());
gates.Open.Add("lap0");
script.Tick(gates, TestTicks.Fresh());
SaveNode locals = session.ToNode(script, typeof(Relapsing)).RequireEntry(ArcRecord.LocalsKey);
CheckEqual("0", locals.RequireEntry("Run.lap").Text);
CheckEqual("1", locals.RequireEntry("Run.start/").RequireEntry("Again.back/")
.RequireEntry("Run.lap").Text);
}
public void LuaSave_NestsTheLevels()
{
string save = ArcRecordTests.Saved(PausedAtTheThirdLevel(new ArcTests.Gates()));
CheckTrue(save.Contains("[\"Run.start/\"] = {"));
CheckEqual(2, save.Split(new[] { "[\"Descend.deeper/\"] = {" }, StringSplitOptions.None).Length - 1);
}
}
public class FromNodeTests : TestFixture
{
public void CountdownReloadedAtEachPause_RunsToTheEnd()
{
var gates = new ArcTests.Gates();
Countdown script = PausedAtTheThirdLevel(gates);
script = Reloaded(script);
gates.Open.Add("go3");
script.Tick(gates, TestTicks.Fresh());
CheckEqual("30;20;10;", script.Log);
CheckTrue(script.Finished);
}
public void CountdownReloadedFromALuaFile_RunsToTheEnd()
{
var gates = new ArcTests.Gates();
var script = ArcRecordTests.Load(ArcRecordTests.Saved(PausedAtTheThirdLevel(gates)));
gates.Open.Add("go3");
script.Tick(gates, TestTicks.Fresh());
CheckEqual("30;20;10;", script.Log);
}
public void CountdownReloadedAndSavedAgainBeforeTicking_KeepsEveryLevel()
{
var gates = new ArcTests.Gates();
Countdown script = Reloaded(Reloaded(PausedAtTheThirdLevel(gates)));
gates.Open.Add("go3");
script.Tick(gates, TestTicks.Fresh());
CheckEqual("30;20;10;", script.Log);
}
public void MutualPassages_ReloadedAtEachPause_RunToTheEnd()
{
var gates = new ArcTests.Gates();
var script = new Rally();
script.Tick(gates, TestTicks.Fresh());
foreach (string gate in new[] { "ping3", "pong2", "ping1", "pong0" })
{
script = Reloaded(script);
gates.Open.Add(gate);
script.Tick(gates, TestTicks.Fresh());
}
CheckEqual("ping3;pong2;ping1;pong0;", script.Log);
CheckTrue(script.Finished);
}
public void GenericPassageWithItsOwnTypeArguments_ReloadedAtEachPause_RunsToTheEnd()
{
var gates = new ArcTests.Gates();
var script = new Layering();
script.Tick(gates, TestTicks.Fresh());
foreach (string gate in new[] { "layer2", "layer1", "layer0" })
{
script = Reloaded(script);
gates.Open.Add(gate);
script.Tick(gates, TestTicks.Fresh());
}
CheckEqual("box@0;box@1;box@2;", script.Log);
}
public void GenericPassageWithItsTypeArgumentsSwapped_ReloadedAtEachPause_RunsToTheEnd()
{
var gates = new ArcTests.Gates();
var script = new Trading();
script.Tick(gates, TestTicks.Fresh());
foreach (string gate in new[] { "trade2", "trade1", "trade0" })
{
script = Reloaded(script);
gates.Open.Add(gate);
script.Tick(gates, TestTicks.Fresh());
}
CheckEqual("1/one;one/1;1/one;", script.Log);
}
public void GenericPassageWrappingItsTypeArgument_ReloadedAtEachPause_RunsToTheEnd()
{
var gates = new ArcTests.Gates();
var script = new Widening();
script.Tick(gates, TestTicks.Fresh());
foreach (string gate in new[] { "wrap2", "wrap1", "wrap0" })
{
script = Reloaded(script);
gates.Open.Add(gate);
script.Tick(gates, TestTicks.Fresh());
}
CheckEqual("0@2;1@1;2@0;up2;up1;up0;", script.Log);
CheckTrue(script.Finished);
}
public void GenericPassageWrappingItsTypeArgument_ReloadedFromALuaFile_RunsToTheEnd()
{
var gates = new ArcTests.Gates();
var script = new Widening();
script.Tick(gates, TestTicks.Fresh());
foreach (string gate in new[] { "wrap2", "wrap1" })
{
gates.Open.Add(gate);
script.Tick(gates, TestTicks.Fresh());
}
script = ArcRecordTests.Load(ArcRecordTests.Saved(script));
gates.Open.Add("wrap0");
script.Tick(gates, TestTicks.Fresh());
CheckEqual("0@2;1@1;2@0;up2;up1;up0;", script.Log);
}
public void SaveNamingATypeNothingRegisteredBuilds_Throws()
{
var gates = new ArcTests.Gates();
var script = new Widening();
script.Tick(gates, TestTicks.Fresh());
gates.Open.Add("wrap2");
script.Tick(gates, TestTicks.Fresh());
SaveSession session = ArcConverterTests.Session();
SaveNode node = session.ToNode(script, typeof(Widening));
node.RequireEntry(ArcRecord.LocalsKey).RequireEntry("Run.start/").RequireEntry("Wrap.deeper/")
.RequireEntry(ArcRecord.TypesKey).Items[0] = SaveNode.OfText("System.Diagnostics.Process");
CheckThrow(typeof(InvalidDataException));
ArcConverterTests.Session().FromNode(node, typeof(Widening));
}
public void DerivedClassRunInACycleOverridingABaseClassRunInACycle_ReloadedAtEachPause_RunsToTheEnd()
{
var gates = new ArcTests.Gates();
var script = new CyclingChild();
script.Tick(gates, TestTicks.Fresh());
foreach (string gate in new[] { "push0", "push1" })
{
script = Reloaded(script);
gates.Open.Add(gate);
script.Tick(gates, TestTicks.Fresh());
}
CheckEqual("push0;push1;", script.Log);
CheckTrue(script.Finished);
}
public void RunCalledFromAPassageItCalls_ReloadedAtEachPause_RunsToTheEnd()
{
var gates = new ArcTests.Gates();
var script = new Relapsing();
script.Tick(gates, TestTicks.Fresh());
foreach (string gate in new[] { "lap0", "lap1", "lap2" })
{
script = Reloaded(script);
gates.Open.Add(gate);
script.Tick(gates, TestTicks.Fresh());
}
CheckEqual("lap0;lap1;lap2;end2;end1;end0;", script.Log);
CheckTrue(script.Finished);
}
public void RunCallingItself_ReloadedFromALuaFileAtEachPause_RunsToTheEnd()
{
var gates = new ArcTests.Gates();
var script = new Repeating();
script.Tick(gates, TestTicks.Fresh());
foreach (string gate in new[] { "round0", "round1", "round2" })
{
script = ArcRecordTests.Load(ArcRecordTests.Saved(script));
gates.Open.Add(gate);
script.Tick(gates, TestTicks.Fresh());
}
CheckEqual("round0;round1;round2;done2;done1;done0;", script.Log);
CheckTrue(script.Finished);
}
public void RunCallingItself_ReloadedBeforeItsFirstTick_RunsToTheEnd()
{
var gates = new ArcTests.Gates();
Repeating script = Reloaded(new Repeating());
foreach (string gate in new[] { "round0", "round1", "round2" })
{
gates.Open.Add(gate);
script.Tick(gates, TestTicks.Fresh());
}
CheckEqual("round0;round1;round2;done2;done1;done0;", script.Log);
}
public void RecursivePassageOfAnotherArc_ReloadedAtEachPause_RunsOnThatArc()
{
var gates = new ArcTests.Gates();
var gardener = new Orchardist();
gardener.Tick(gates, TestTicks.Fresh());
foreach (string gate in new[] { "ring2", "ring1" })
{
gardener = Reloaded(gardener);
gates.Open.Add(gate);
gardener.Tick(gates, TestTicks.Fresh());
}
CheckEqual("1;2;", gardener.Trees.Log);
CheckTrue(gardener.Finished);
}
public void PassageOfABaseClassCallingItself_ReloadedAtEachPause_RunsToTheEnd()
{
var gates = new ArcTests.Gates();
var script = new Shaft();
script.Tick(gates, TestTicks.Fresh());
foreach (string gate in new[] { "dig1", "dig2" })
{
script = Reloaded(script);
gates.Open.Add(gate);
script.Tick(gates, TestTicks.Fresh());
}
CheckEqual("2;1;", script.Log);
}
public void ServesHandedBetweenTwoArcs_ReloadedAtEachPause_RunOnTheArcsReloadedWithIt()
{
var gates = new ArcTests.Gates();
var first = new Volley();
first.Partner = new Volley { Partner = first };
first.Tick(gates, TestTicks.Fresh());
foreach (string gate in new[] { "hit3", "hit2", "hit1" })
{
first = Reloaded(first);
gates.Open.Add(gate);
first.Tick(gates, TestTicks.Fresh());
}
CheckTrue(ReferenceEquals(first, first.Partner.Partner));
CheckEqual("serve3;serve1;", first.Log);
CheckEqual("serve2;", first.Partner.Log);
CheckTrue(first.Finished);
}
public void SaveNestedFarDeeperThanTheStackAllows_IsRejectedAsInvalidData()
{
SaveNode locals = SaveNode.NewTable();
SaveNode level = locals;
for (int depth = 0; depth < 50000; ++depth)
{
SaveNode next = SaveNode.NewTable();
level.Entries[depth == 0 ? "Run.start/" : "Descend.deeper/"] = next;
level = next;
}
SaveNode node = SaveNode.NewTable();
node.Entries[ArcRecord.LocalsKey] = locals;
CheckThrow(typeof(InvalidDataException));
ArcConverterTests.Session().FromNode(node, typeof(Countdown));
}
}
public class TypeArgumentTests : TestFixture
{
public void WrittenAtTheTopLevel_ReadBackAsTheSameTypes()
{
var record = new ArcRecord(ArcConverterTests.Session());
record.TypeArguments(typeof(int), typeof(List));
Type[] read;
CheckTrue(record.TryTypeArguments(out read));
CheckEqual(new[] { typeof(int), typeof(List) }, read);
}
public void NoneWritten_ReadsAsAbsent()
{
Type[] read;
CheckFalse(new ArcRecord(ArcConverterTests.Session()).TryTypeArguments(out read));
CheckNull(read);
}
public void WrittenInACall_AreNotAKeyOfThatCallsLocals()
{
var record = new ArcRecord(ArcConverterTests.Session());
record.Scope("Run.start/").TypeArguments(typeof(int));
IArcReader scope;
CheckTrue(record.TryScope("Run.start/", out scope));
CheckEqual(0, scope.LocalKeys.Count());
Type[] read;
CheckTrue(scope.TryTypeArguments(out read));
CheckEqual(new[] { typeof(int) }, read);
}
public void TypeASaveCantName_Throws()
{
var record = new ArcRecord(ArcConverterTests.Session());
CheckThrow(typeof(NotSupportedException));
record.TypeArguments(typeof(System.Diagnostics.Process));
}
}
public class PolymorphicListingTests : TestFixture
{
[IgnoreTest]
private static SaveNode SaveAtTheThirdLevel(SaveSession session)
{
var gates = new ArcTests.Gates();
var script = new Widening();
script.Tick(gates, TestTicks.Fresh());
foreach (string gate in new[] { "wrap2", "wrap1" })
{
gates.Open.Add(gate);
script.Tick(gates, TestTicks.Fresh());
}
return session.ToNode(script, typeof(Widening));
}
public void ChildrenOfASaveWithNewFrameTypesPerLevel_AreListedWithTheTypeOfEachLevel()
{
SaveConverters converters = SaveConverters.For(typeof(ArcConverterTests).Assembly);
SaveNode node = SaveAtTheThirdLevel(converters.CreateSession());
var children = new ChildList();
CheckTrue(new ArcConverter().TryListChildren(node, children, converters));
var types = new List();
for (int i = 0; i < children.Count; ++i)
{
types.Add(children.TypeAt(i));
}
CheckTrue(types.Contains(typeof(List)));
CheckTrue(types.Contains(typeof(List>)));
}
public void WithoutConverters_ReturnsFalse()
{
SaveNode node = SaveAtTheThirdLevel(ArcConverterTests.Session());
CheckFalse(new ArcConverter().TryListChildren(node, new ChildList()));
}
public void TypesThatDontFitTheFrame_ReturnFalse()
{
SaveConverters converters = SaveConverters.For(typeof(ArcConverterTests).Assembly);
SaveNode node = SaveAtTheThirdLevel(converters.CreateSession());
node.RequireEntry(ArcRecord.LocalsKey).RequireEntry("Run.start/").RequireEntry("Wrap.deeper/")
.RequireEntry(ArcRecord.TypesKey).Items.Add(SaveNode.OfText("int"));
CheckFalse(new ArcConverter().TryListChildren(node, new ChildList(),
converters));
}
public void TypesThatNothingRegisteredBuilds_ReturnFalse()
{
SaveConverters converters = SaveConverters.For(typeof(ArcConverterTests).Assembly);
SaveNode node = SaveAtTheThirdLevel(converters.CreateSession());
node.RequireEntry(ArcRecord.LocalsKey).RequireEntry("Run.start/").RequireEntry("Wrap.deeper/")
.RequireEntry(ArcRecord.TypesKey).Items[0] = SaveNode.OfText("System.Diagnostics.Process");
CheckFalse(new ArcConverter().TryListChildren(node, new ChildList(),
converters));
}
public void CallEntryThatIsNotATable_ReturnsFalse()
{
SaveConverters converters = SaveConverters.For(typeof(ArcConverterTests).Assembly);
SaveNode node = SaveAtTheThirdLevel(converters.CreateSession());
node.RequireEntry(ArcRecord.LocalsKey).RequireEntry("Run.start/").Entries["Wrap.deeper/"] =
SaveNode.OfText("not a table");
CheckFalse(new ArcConverter().TryListChildren(node, new ChildList(),
converters));
}
public void TypesEntryThatIsNotAList_ReturnsFalse()
{
SaveConverters converters = SaveConverters.For(typeof(ArcConverterTests).Assembly);
SaveNode node = SaveAtTheThirdLevel(converters.CreateSession());
node.RequireEntry(ArcRecord.LocalsKey).RequireEntry("Run.start/").RequireEntry("Wrap.deeper/")
.Entries[ArcRecord.TypesKey] = SaveNode.OfText("int");
CheckFalse(new ArcConverter().TryListChildren(node, new ChildList(),
converters));
}
}
public class ConverterTests : TestFixture
{
public void ArcsThatRunEachOthersPassages_ListTheirPartsWithoutEnd()
{
new ArcConverter();
new ArcConverter();
new ArcConverter();
}
public void ChildrenOfARecursiveSave_AreListedForEveryLevel()
{
SaveSession session = ArcConverterTests.Session();
SaveNode node = session.ToNode(PausedAtTheThirdLevel(new ArcTests.Gates()), typeof(Countdown));
var children = new ChildList();
CheckTrue(new ArcConverter().TryListChildren(node, children));
CheckEqual(7, children.Count);
}
}
}
}