using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using UnitTestSharp;
using Vellum;
namespace Ariadne.Vellum.UnitTests
{
public class ArcConverterTests : TestFixture
{
///
/// Returns the converters the test assembly names, which include the arc family from Ariadne.Vellum.
///
public static SaveSession Session()
{
return SaveConverters.For(typeof(ArcConverterTests).Assembly).CreateSession();
}
public static OwnedScript Owned(int progress)
{
return new OwnedScript { Progress = progress };
}
///
/// Returns a table holding , since a save is one table.
///
public static SaveNode SavedList(SaveSession session, List entities)
{
SaveNode returnMe = SaveNode.NewTable();
returnMe.Entries["entities"] = session.ToNode(entities, typeof(List));
return returnMe;
}
public class FamilyTests : TestFixture
{
public void TestAssembly_NamesTheFamilyWithoutAnyArcInIt()
{
CheckTrue(typeof(ArcConverterTests).Assembly.GetCustomAttributes()
.Any(attribute => attribute.Converter == typeof(ArcConverter<,>)));
}
public void ArcClassWithNoConverterOfItsOwn_IsSavedAndLoaded()
{
SaveSession session = Session();
SaveNode node = session.ToNode(Owned(4), typeof(OwnedScript));
CheckEqual(4, ((OwnedScript)session.FromNode(node, typeof(OwnedScript))).Progress);
}
public void ArcClassWithoutALoader_Throws()
{
SaveSession session = Session();
CheckThrow(typeof(InvalidOperationException));
session.ToNode(new ArcLoaderTests.LoaderlessArc(), typeof(ArcLoaderTests.LoaderlessArc));
}
}
public class ConstructorTests : TestFixture
{
public void ClassWithoutALoader_Throws()
{
CheckThrow(typeof(InvalidOperationException));
new ArcConverter();
}
}
public class ValueTypeTests : TestFixture
{
public void IsTheArcClass()
{
CheckEqual(typeof(CountingScript), new ArcConverter().ValueType);
}
}
public class ToNodeTests : TestFixture
{
public void WritesWhatTheArcRecordWrites()
{
SaveSession session = Session();
CountingScript script = ArcRecordTests.PausedTwice();
SaveNode node = session.ToNode(script, typeof(CountingScript));
CheckEqual(new[] { "wait" },
node.RequireEntry(ArcRecord.CursorKey).RequireItems().Select(label => label.Text).ToArray());
CheckEqual("2", node.RequireEntry(ArcRecord.FieldsKey).RequireEntry("Count").Text);
CheckEqual("2", node.RequireEntry(ArcRecord.LocalsKey).RequireEntry("Run.waits").Text);
}
}
public class TryListChildrenTests : TestFixture
{
public static Type[] TypesOf(ChildList children)
{
var returnMe = new Type[children.Count];
for (int i = 0; i < returnMe.Length; ++i)
{
returnMe[i] = children.TypeAt(i);
}
return returnMe;
}
public void ListsEachSavedFieldAndLocalWithItsType()
{
SaveSession session = Session();
SaveNode node = session.ToNode(ArcRecordTests.PausedTwice(), typeof(CountingScript));
var children = new ChildList();
CheckTrue(new ArcConverter().TryListChildren(node, children));
CheckEqual(new[] { typeof(int), typeof(string), typeof(int) }, TypesOf(children));
CheckTrue(ReferenceEquals(node.RequireEntry(ArcRecord.FieldsKey).RequireEntry("Count"),
children.NodeAt(0)));
CheckTrue(ReferenceEquals(node.RequireEntry(ArcRecord.LocalsKey).RequireEntry("Run.waits"),
children.NodeAt(2)));
}
public void DerivedClass_ListsItsBaseClassPartsFirst()
{
SaveSession session = Session();
SaveNode node = session.ToNode(new ReliefScript { Stage = 1, Crates = 2 }, typeof(ReliefScript));
var children = new ChildList();
CheckTrue(new ArcConverter().TryListChildren(node, children));
CheckEqual(2, children.Count);
CheckEqual("1", children.NodeAt(0).Text);
CheckEqual("2", children.NodeAt(1).Text);
}
public void PartTheSaveLacks_IsLeftOut()
{
SaveNode node = SaveNode.NewTable();
SaveNode fields = SaveNode.NewTable();
fields.Entries["Count"] = SaveNode.OfText("4");
node.Entries[ArcRecord.FieldsKey] = fields;
var children = new ChildList();
CheckTrue(new ArcConverter().TryListChildren(node, children));
CheckEqual(new[] { typeof(int) }, TypesOf(children));
}
public void SaveWithNoTables_ListsNothing()
{
var children = new ChildList();
CheckTrue(new ArcConverter().TryListChildren(SaveNode.NewTable(), children));
CheckEqual(0, children.Count);
}
public void ClassWritingItsOwnSaveFields_ReturnsFalse()
{
SaveNode node = Session().ToNode(new HandBuiltScript { Held = 3 }, typeof(HandBuiltScript));
CheckFalse(new ArcConverter().TryListChildren(node, new ChildList()));
}
public void NodeThatIsNotATable_ReturnsFalse()
{
CheckFalse(new ArcConverter().TryListChildren(SaveNode.OfText("x"),
new ChildList()));
}
public void FieldsThatAreNotATable_ReturnsFalse()
{
SaveNode node = SaveNode.NewTable();
node.Entries[ArcRecord.FieldsKey] = SaveNode.OfText("x");
CheckFalse(new ArcConverter().TryListChildren(node, new ChildList()));
}
public void LocalsThatAreNotATable_ReturnsFalse()
{
SaveNode node = SaveNode.NewTable();
node.Entries[ArcRecord.LocalsKey] = SaveNode.OfText("x");
CheckFalse(new ArcConverter().TryListChildren(node, new ChildList()));
}
public void LocalsOfACall_AreListedFromTheCallsTableWithTheirTypes()
{
SaveNode node = Session().ToNode(ForeignCallSaveTests.PausedInside(new Gates(), ticks: 2),
typeof(OperatorScript));
SaveNode call = node.RequireEntry(ArcRecord.LocalsKey).RequireEntry("Run.update/");
var children = new ChildList();
CheckTrue(new ArcConverter().TryListChildren(node, children));
int waited = IndexOfNode(children, call.RequireEntry("Update.waited"));
int receiver = IndexOfNode(children, call.RequireEntry("receiver"));
CheckTrue(waited >= 0);
CheckTrue(receiver >= 0);
CheckEqual(typeof(int), children.TypeAt(waited));
CheckEqual(typeof(PlantScript), children.TypeAt(receiver));
}
public void CallTheSaveLacks_IsLeftOut()
{
SaveNode node = SaveNode.NewTable();
node.Entries[ArcRecord.LocalsKey] = SaveNode.NewTable();
var children = new ChildList();
CheckTrue(new ArcConverter().TryListChildren(node, children));
CheckEqual(0, children.Count);
}
public void CallThatIsNotATable_ReturnsFalse()
{
SaveNode locals = SaveNode.NewTable();
locals.Entries["Run.update/"] = SaveNode.OfText("x");
SaveNode node = SaveNode.NewTable();
node.Entries[ArcRecord.LocalsKey] = locals;
CheckFalse(new ArcConverter().TryListChildren(node, new ChildList()));
}
}
public class DeepChainTests : TestFixture
{
public static ChainScript Chain(int length)
{
var head = new ChainScript { Depth = length };
ChainScript tail = head;
for (int i = length - 1; i > 0; --i)
{
tail.Next = new ChainScript { Depth = i };
tail = tail.Next;
}
return head;
}
public void ArcsHoldingArcs_LoadPastTheNestingLimit()
{
SaveSession session = Session();
SaveNode node = LuaSaveFormat.Parse(LuaSaveFormat.Format(
session.ToNode(Chain(200), typeof(ChainScript))));
var loaded = (ChainScript)Session().FromNode(node, typeof(ChainScript));
int length = 0;
for (ChainScript link = loaded; link != null; link = link.Next)
{
CheckEqual(200 - length, link.Depth);
length++;
}
CheckEqual(200, length);
}
public void ClassWritingItsOwnSaveFields_StillLoads()
{
SaveSession session = Session();
SaveNode node = session.ToNode(new HandBuiltScript { Held = 7 }, typeof(HandBuiltScript));
CheckEqual(7, ((HandBuiltScript)session.FromNode(node, typeof(HandBuiltScript))).Held);
}
}
public static int IndexOfNode(ChildList children, SaveNode node)
{
for (int i = 0; i < children.Count; ++i)
{
if (ReferenceEquals(children.NodeAt(i), node))
{
return i;
}
}
return -1;
}
public class FromNodeTests : TestFixture
{
public void BuildsAnArcAtWhereTheSaveLeftOff()
{
SaveSession session = Session();
SaveNode node = session.ToNode(ArcRecordTests.PausedTwice(), typeof(CountingScript));
var resumed = (CountingScript)session.FromNode(node, typeof(CountingScript));
var gates = new Gates();
gates.Open.Add("go");
resumed.Tick(gates, TestTicks.Fresh());
CheckEqual(2, resumed.Count);
CheckEqual("waited 2", resumed.Note);
CheckTrue(resumed.Finished);
}
public void PausedScript_ReportsNoUnreadKeys()
{
SaveSession session = Session();
session.ReportsUnreadKeys = true;
SaveNode node = session.ToNode(ArcRecordTests.PausedTwice(), typeof(CountingScript));
session.FromNode(node, typeof(CountingScript));
CheckEqual(0, session.Sandbox.Issues.Count);
}
public void FieldTheScriptLacks_IsReportedAsUnread()
{
SaveSession session = Session();
session.ReportsUnreadKeys = true;
SaveNode node = session.ToNode(ArcRecordTests.PausedTwice(), typeof(CountingScript));
node.Entries[ArcRecord.FieldsKey].Entries["Removed"] = SaveNode.OfText("1");
session.FromNode(node, typeof(CountingScript));
CheckEqual(new[] { "fields: Removed" },
session.Sandbox.Issues.Select(issue => issue.Path).ToArray());
}
public void LocalTheScriptLacks_Throws()
{
SaveNode node = SaveNode.NewTable();
SaveNode locals = SaveNode.NewTable();
locals.Entries["Run.removed"] = SaveNode.OfText("1");
node.Entries[ArcRecord.LocalsKey] = locals;
CheckThrow(typeof(NotImplementedException));
Session().FromNode(node, typeof(CountingScript));
}
public void ValueOfTheWrongShape_KeepsTheFieldsInitialValueAndRecordsIt()
{
SaveNode node = SaveNode.NewTable();
SaveNode fields = SaveNode.NewTable();
fields.Entries["Count"] = SaveNode.OfText("many");
node.Entries[ArcRecord.FieldsKey] = fields;
SaveSession session = Session();
var loaded = (CountingScript)session.FromNode(node, typeof(CountingScript));
CheckEqual(0, loaded.Count);
CheckEqual(1, session.Sandbox.Issues.Count);
}
}
public class FieldOfAnotherObjectTests : TestFixture
{
public void ArcHeldByAnEntity_SurvivesALuaRoundTrip()
{
SaveSession session = Session();
var original = new Entity { Name = "Ada", Mission = Owned(5) };
SaveNode node = LuaSaveFormat.Parse(LuaSaveFormat.Format(session.ToNode(original, typeof(Entity))));
var loaded = (Entity)session.FromNode(node, typeof(Entity));
CheckEqual("Ada", loaded.Name);
CheckEqual(5, loaded.Mission.Progress);
}
public void EntityWithNoArc_LoadsWithNone()
{
SaveSession session = Session();
SaveNode node = session.ToNode(new Entity { Name = "Ada" }, typeof(Entity));
var loaded = (Entity)session.FromNode(node, typeof(Entity));
CheckNull(loaded.Mission);
}
public void ArcSharedByTwoEntities_IsOneArcAgain()
{
SaveSession session = Session();
OwnedScript shared = Owned(3);
var entities = new List
{
new Entity { Name = "Ada", Mission = shared },
new Entity { Name = "Bob", Mission = shared },
};
SaveNode node = LuaSaveFormat.Parse(LuaSaveFormat.Format(SavedList(session, entities)));
var loaded = (List)session.FromNode(node.RequireEntry("entities"), typeof(List));
CheckTrue(ReferenceEquals(loaded[0].Mission, loaded[1].Mission));
CheckEqual(3, loaded[0].Mission.Progress);
}
public void ArcSharedByTwoEntities_IsWrittenOnce()
{
SaveSession session = Session();
OwnedScript shared = Owned(3);
var entities = new List
{
new Entity { Name = "Ada", Mission = shared },
new Entity { Name = "Bob", Mission = shared },
};
string text = LuaSaveFormat.Format(SavedList(session, entities));
CheckEqual(1, text.Split(new[] { "Progress" }, StringSplitOptions.None).Length - 1);
}
public void EntityAndArcHoldingEachOther_AreEachOtherAgain()
{
SaveSession session = Session();
var original = new Entity { Name = "Ada", Mission = Owned(1) };
original.Mission.Owner = original;
SaveNode node = LuaSaveFormat.Parse(LuaSaveFormat.Format(session.ToNode(original, typeof(Entity))));
var loaded = (Entity)session.FromNode(node, typeof(Entity));
CheckTrue(ReferenceEquals(loaded, loaded.Mission.Owner));
CheckEqual("Ada", loaded.Mission.Owner.Name);
}
public void ArcLoadedFirst_StillFindsItsEntity()
{
SaveSession session = Session();
var original = new Entity { Name = "Ada", Mission = Owned(1) };
original.Mission.Owner = original;
SaveNode node = LuaSaveFormat.Parse(LuaSaveFormat.Format(session.ToNode(original.Mission,
typeof(OwnedScript))));
var loaded = (OwnedScript)session.FromNode(node, typeof(OwnedScript));
CheckTrue(ReferenceEquals(loaded, loaded.Owner.Mission));
}
}
public class OneSaveFileTests : TestFixture
{
public void ArcsAndTheWorld_ShareTheirObjectsAfterOneSaveAndOneLoad()
{
var ada = new Entity { Name = "Ada", Mission = Owned(1) };
ada.Mission.Owner = ada;
OwnedScript helper = Owned(2);
helper.Owner = ada;
var arcs = new List> { ada.Mission, helper, ArcRecordTests.PausedTwice() };
SaveNode save = SaveNode.NewTable();
SaveSession saving = Session();
save.Entries["world"] = saving.ToNode(new List { ada }, typeof(List));
save.Entries["arcs"] = saving.ToNode(arcs, typeof(List>));
SaveNode parsed = LuaSaveFormat.Parse(LuaSaveFormat.Format(save));
SaveSession loading = Session();
var loadedWorld = (List)loading.FromNode(parsed.RequireEntry("world"), typeof(List));
var loadedArcs = (List>)loading.FromNode(parsed.RequireEntry("arcs"),
typeof(List>));
CheckTrue(ReferenceEquals(loadedWorld[0].Mission, loadedArcs[0]));
CheckTrue(ReferenceEquals(loadedWorld[0], ((OwnedScript)loadedArcs[1]).Owner));
CheckEqual(2, ((CountingScript)loadedArcs[2]).Count);
}
}
public class SeparateSaveTests : TestFixture
{
public void ArcSavedAlone_CarriesEverythingItReaches()
{
var cy = new Entity { Name = "Cy", Mission = Owned(3) };
var bob = new Entity { Name = "Bob", Mission = Owned(2) };
var ada = new Entity { Name = "Ada", Mission = Owned(1) };
ada.Mission.Owner = bob;
bob.Mission.Owner = cy;
string text = LuaSaveFormat.Format(Session().ToNode(ada.Mission, typeof(OwnedScript)));
CheckTrue(text.Contains("\"Bob\""));
CheckTrue(text.Contains("\"Cy\""));
CheckFalse(text.Contains("\"Ada\""));
}
public void EntitySavedInTwoSessions_LoadsAsTwoCopies()
{
var ada = new Entity { Name = "Ada", Mission = Owned(1) };
ada.Mission.Owner = ada;
SaveNode worldSave = Session().ToNode(ada, typeof(Entity));
SaveNode arcSave = Session().ToNode(ada.Mission, typeof(OwnedScript));
var loadedWorld = (Entity)Session().FromNode(worldSave, typeof(Entity));
var loadedArc = (OwnedScript)Session().FromNode(arcSave, typeof(OwnedScript));
CheckFalse(ReferenceEquals(loadedWorld, loadedArc.Owner));
CheckFalse(ReferenceEquals(loadedWorld.Mission, loadedArc));
CheckEqual("Ada", loadedArc.Owner.Name);
}
}
public class DeclaredAsItsBaseClassTests : TestFixture
{
public void ArcHeldAsItsBaseClass_IsLoadedAsItsOwnClass()
{
SaveSession session = Session();
CountingScript original = ArcRecordTests.PausedTwice();
SaveNode node = session.ToNode(original, typeof(Arc));
var loaded = session.FromNode(node, typeof(Arc));
CheckEqual(typeof(CountingScript), loaded.GetType());
CheckEqual(2, ((CountingScript)loaded).Count);
}
public void NullHeldAsItsBaseClass_StaysNull()
{
SaveSession session = Session();
SaveNode node = session.ToNode(null, typeof(Arc));
CheckNull(session.FromNode(node, typeof(Arc)));
}
public void ArcClassNoConverterNamesInASave_CantBeLoaded()
{
SaveSession session = Session();
SaveNode node = session.ToNode(ArcRecordTests.PausedTwice(), typeof(Arc));
node.Entries[SaveConverters.TypeKey] = SaveNode.OfText("Ariadne.Vellum.UnitTests.NoSuchScript");
CheckThrow(typeof(InvalidDataException));
session.FromNode(node, typeof(Arc));
}
}
}
}