using System; using System.Collections.Generic; using System.IO; using UnitTestSharp; namespace Vellum.UnitTests { public class SaveNodeTests : TestFixture { public class OfTextTests : TestFixture { public void KeepsTheTextAndComment() { SaveNode node = SaveNode.OfText("1", comment: "one"); CheckEqual(SaveNode.Kinds.Text, node.Kind); CheckEqual("1", node.Text); CheckEqual("one", node.Comment); } public void NullText_Throws() { CheckThrow(typeof(ArgumentNullException)); SaveNode.OfText(null); } } public class OfDoubleTests : TestFixture { public static readonly SaveNode OneAndAHalf = SaveNode.OfDouble(1.5); public void IsATextNode() { CheckEqual(SaveNode.Kinds.Text, OneAndAHalf.Kind); CheckNull(OneAndAHalf.Entries); CheckNull(OneAndAHalf.Items); } public void TextIsTheExactBitsAsHex() { CheckEqual("0x3FF8000000000000", OneAndAHalf.Text); CheckEqual("0x8000000000000000", SaveNode.OfDouble(-0.0).Text); CheckEqual("0x7FF0000000000000", SaveNode.OfDouble(double.PositiveInfinity).Text); CheckEqual("0xFFF0000000000000", SaveNode.OfDouble(double.NegativeInfinity).Text); } public void TextIsMadeAgainOnEachRead() { CheckEqual(OneAndAHalf.Text, OneAndAHalf.Text); CheckFalse(ReferenceEquals(OneAndAHalf.Text, OneAndAHalf.Text)); } public void RequireText_GivesTheHex() { CheckEqual("0x3FF8000000000000", OneAndAHalf.RequireText()); } public void TryGetDouble_GivesTheNumber() { double number; CheckTrue(OneAndAHalf.TryGetDouble(out number)); CheckEqual(1.5, number); } public void TryGetDouble_KeepsTheExactBits() { double number; SaveNode.OfDouble(-0.0).TryGetDouble(out number); CheckEqual(BitConverter.DoubleToInt64Bits(-0.0), BitConverter.DoubleToInt64Bits(number)); } public void TryAppendText_AppendsTheHexAndReturnsTrue() { var builder = new System.Text.StringBuilder("x "); CheckTrue(OneAndAHalf.TryAppendText(builder)); CheckEqual("x 0x3FF8000000000000", builder.ToString()); } [AllocationTest] public void TryGetDouble_AllocatesNothing() { double number; bool got = OneAndAHalf.TryGetDouble(out number); CheckNoAllocations(); CheckTrue(got); } [AllocationTest] public void Making_AllocatesOnlyTheNode() { SaveNode node = SaveNode.OfDouble(0.1 + 0.2); CheckAllocationsAtMost(maxBytesPerRun: IntPtr.Size == 4 ? 44 : 80); CheckEqual(SaveNode.Kinds.Text, node.Kind); } public void CommentIsTheDecimalValue() { CheckEqual("1.5", OneAndAHalf.Comment); CheckEqual("0.30000000000000004", SaveNode.OfDouble(0.1 + 0.2).Comment); CheckEqual("-2", SaveNode.OfDouble(-2.0).Comment); } public void CommentNamesTheValuesWithNoDigits() { CheckEqual("NaN", SaveNode.OfDouble(double.NaN).Comment); CheckEqual("Infinity", SaveNode.OfDouble(double.PositiveInfinity).Comment); CheckEqual("-Infinity", SaveNode.OfDouble(double.NegativeInfinity).Comment); } public void CommentOfNegativeZero_KeepsItsSign() { CheckEqual("-0", SaveNode.OfDouble(-0.0).Comment); CheckEqual("0", SaveNode.OfDouble(0.0).Comment); } public void CommentOfAnExtremeValue_UsesAnExponent() { CheckEqual("1.7976931348623157E+308", SaveNode.OfDouble(double.MaxValue).Comment); CheckEqual("5E-324", SaveNode.OfDouble(double.Epsilon).Comment); } public void CommentUsesAPointInAnyCulture() { SavedValueTests.InGermanCulture(() => CheckEqual("1.5", OneAndAHalf.Comment)); } public void HasAComment() { CheckTrue(OneAndAHalf.HasComment); } [AllocationTest] public void HasAComment_AllocatesNothing() { bool has = OneAndAHalf.HasComment; CheckNoAllocations(); CheckTrue(has); } } public class OfFloatTests : TestFixture { public static readonly SaveNode Tenth = SaveNode.OfFloat(0.1f); public void IsATextNode() { CheckEqual(SaveNode.Kinds.Text, Tenth.Kind); CheckNull(Tenth.Entries); } public void TextIsTheExactBitsOfTheDoubleTheFloatWidensTo() { CheckEqual("0x3FB99999A0000000", Tenth.Text); CheckEqual(SaveNode.OfDouble(0.1f).Text, Tenth.Text); } public void CommentIsTheShortestDigitsThatReadBackAsTheFloat() { CheckEqual("0.1", Tenth.Comment); CheckEqual("0.1", SaveNode.OfFloat(0.1f).Comment); CheckEqual("0.10000000149011612", SaveNode.OfDouble(0.1f).Comment); } public void TryGetDouble_GivesTheWidenedFloat() { double number; CheckTrue(Tenth.TryGetDouble(out number)); CheckEqual((double)0.1f, number); } public void TryAppendTextAndComment_AppendTheSameAsTheGetters() { var text = new System.Text.StringBuilder(); var comment = new System.Text.StringBuilder(); CheckTrue(Tenth.TryAppendText(text)); CheckTrue(Tenth.TryAppendComment(comment)); CheckEqual(Tenth.Text, text.ToString()); CheckEqual(Tenth.Comment, comment.ToString()); } public void HasAComment() { CheckTrue(Tenth.HasComment); } [AllocationTest] public void Making_AllocatesOnlyTheNode() { SaveNode node = SaveNode.OfFloat(0.1f); CheckAllocationsAtMost(maxBytesPerRun: IntPtr.Size == 4 ? 40 : 72); CheckEqual(SaveNode.Kinds.Text, node.Kind); } } public class OfIntegerTests : TestFixture { public static readonly SaveNode Seven = SaveNode.OfInteger(7); public void IsATextNodeWithNoComment() { CheckEqual(SaveNode.Kinds.Text, Seven.Kind); CheckFalse(Seven.HasComment); CheckNull(Seven.Comment); } public void TextIsTheDecimalDigits() { CheckEqual("7", Seven.Text); CheckEqual("0", SaveNode.OfInteger(0).Text); CheckEqual("-12345", SaveNode.OfInteger(-12345).Text); CheckEqual("9223372036854775807", SaveNode.OfInteger(long.MaxValue).Text); CheckEqual("-9223372036854775808", SaveNode.OfInteger(long.MinValue).Text); } public void TryGetInteger_GivesTheNumber() { long number; CheckTrue(SaveNode.OfInteger(long.MinValue).TryGetInteger(out number)); CheckEqual(long.MinValue, number); } public void TryGetUnsigned_GivesTheNumberOnlyWhenItIsNotNegative() { ulong number; CheckTrue(Seven.TryGetUnsigned(out number)); CheckEqual(7UL, number); CheckTrue(SaveNode.OfInteger(0).TryGetUnsigned(out number)); CheckFalse(SaveNode.OfInteger(-1).TryGetUnsigned(out number)); } public void OtherNodes_GiveNoInteger() { long number; ulong unsigned; CheckFalse(SaveNode.OfText("7").TryGetInteger(out number)); CheckFalse(SaveNode.OfText("7").TryGetUnsigned(out unsigned)); CheckFalse(SaveNode.OfDouble(7).TryGetInteger(out number)); } public void TryAppendText_AppendsTheDigitsAndReturnsTrue() { var builder = new System.Text.StringBuilder("x "); CheckTrue(SaveNode.OfInteger(-42).TryAppendText(builder)); CheckEqual("x -42", builder.ToString()); } [AllocationTest] public void TryGetInteger_AllocatesNothing() { long number; bool got = Seven.TryGetInteger(out number); CheckNoAllocations(); CheckTrue(got); } [AllocationTest] public void Making_AllocatesOnlyTheNode() { SaveNode node = SaveNode.OfInteger(123456789); CheckAllocationsAtMost(maxBytesPerRun: IntPtr.Size == 4 ? 44 : 80); CheckEqual(SaveNode.Kinds.Text, node.Kind); } } public class OfUnsignedTests : TestFixture { public void TextIsTheDecimalDigits() { CheckEqual("0", SaveNode.OfUnsigned(0).Text); CheckEqual("9223372036854775808", SaveNode.OfUnsigned(9223372036854775808UL).Text); CheckEqual("18446744073709551615", SaveNode.OfUnsigned(ulong.MaxValue).Text); } public void TryGetUnsigned_GivesTheNumber() { ulong number; CheckTrue(SaveNode.OfUnsigned(ulong.MaxValue).TryGetUnsigned(out number)); CheckEqual(ulong.MaxValue, number); } public void TryGetInteger_GivesTheNumberOnlyWhenALongHoldsIt() { long number; CheckTrue(SaveNode.OfUnsigned(long.MaxValue).TryGetInteger(out number)); CheckEqual(long.MaxValue, number); CheckFalse(SaveNode.OfUnsigned((ulong)long.MaxValue + 1).TryGetInteger(out number)); CheckFalse(SaveNode.OfUnsigned(ulong.MaxValue).TryGetInteger(out number)); } public void TryAppendText_AppendsTheDigitsAndReturnsTrue() { var builder = new System.Text.StringBuilder("x "); CheckTrue(SaveNode.OfUnsigned(ulong.MaxValue).TryAppendText(builder)); CheckEqual("x 18446744073709551615", builder.ToString()); } public void HasNoComment() { CheckFalse(SaveNode.OfUnsigned(5).HasComment); } } public class HasCommentTests : TestFixture { public void TextWithAComment_Has() { CheckTrue(SaveNode.OfText("1", comment: "one").HasComment); } public void TextWithoutOne_DoesNot() { CheckFalse(SaveNode.OfText("1").HasComment); } public void OtherKinds_DoNot() { CheckFalse(SaveNode.Null.HasComment); CheckFalse(SaveNode.NewTable().HasComment); CheckFalse(SaveNode.NewList().HasComment); } } public class TryAppendCommentTests : TestFixture { public void NumberNode_AppendsTheDecimalAndReturnsTrue() { var builder = new System.Text.StringBuilder("x "); CheckTrue(SaveNode.OfDouble(1.5).TryAppendComment(builder)); CheckEqual("x 1.5", builder.ToString()); } public void NodeHoldingItsCommentAsAString_AppendsNothingAndReturnsFalse() { var builder = new System.Text.StringBuilder("x"); CheckFalse(SaveNode.OfText("1", comment: "one").TryAppendComment(builder)); CheckEqual("x", builder.ToString()); } public void NodeWithNoComment_AppendsNothingAndReturnsFalse() { var builder = new System.Text.StringBuilder("x"); CheckFalse(SaveNode.OfText("1").TryAppendComment(builder)); CheckEqual("x", builder.ToString()); } } public class NewTableTests : TestFixture { public void StartsEmpty() { SaveNode node = SaveNode.NewTable(); CheckEqual(SaveNode.Kinds.Table, node.Kind); CheckEqual(0, node.Entries.Count); } } public class NewListTests : TestFixture { public void StartsEmpty() { SaveNode node = SaveNode.NewList(); CheckEqual(SaveNode.Kinds.List, node.Kind); CheckEqual(0, node.Items.Count); } public void HasNoEntriesOrText() { SaveNode node = SaveNode.NewList(); CheckNull(node.Entries); CheckNull(node.Text); } } public class NewMapTests : TestFixture { public void StartsEmpty() { SaveNode node = SaveNode.NewMap(); CheckEqual(SaveNode.Kinds.Map, node.Kind); CheckEqual(0, node.Pairs.Count); } public void HasNoEntriesItemsOrText() { SaveNode node = SaveNode.NewMap(); CheckNull(node.Entries); CheckNull(node.Items); CheckNull(node.Text); } } public class ItemsTests : TestFixture { public void OtherKinds_HaveNone() { CheckNull(SaveNode.OfText("1").Items); CheckNull(SaveNode.Null.Items); CheckNull(SaveNode.NewTable().Items); CheckNull(SaveNode.NewMap().Items); } } public class PairsTests : TestFixture { public void OtherKinds_HaveNone() { CheckNull(SaveNode.OfText("1").Pairs); CheckNull(SaveNode.Null.Pairs); CheckNull(SaveNode.NewTable().Pairs); CheckNull(SaveNode.NewList().Pairs); } } public class RequireTextTests : TestFixture { public void Text_IsReturned() { CheckEqual("1", SaveNode.OfText("1").RequireText()); } public void Null_Throws() { CheckThrow(typeof(InvalidDataException)); SaveNode.Null.RequireText(); } public void ReferenceToText_ReturnsTheText() { SaveNode reference = SaveNode.NewRef(); reference.Resolve(SaveNode.OfText("1")); CheckEqual("1", reference.RequireText()); } public void ReferenceToTable_Throws() { SaveNode reference = SaveNode.NewRef(); reference.Resolve(SaveNode.NewTable()); CheckThrow(typeof(InvalidDataException)); reference.RequireText(); } } public class TryGetEntryTests : TestFixture { public void PresentEntry_IsReturned() { SaveNode node = SaveNode.NewTable(); SaveNode entry = SaveNode.OfText("1"); node.Entries["a"] = entry; SaveNode found; CheckTrue(node.TryGetEntry("a", out found)); CheckTrue(ReferenceEquals(entry, found)); } public void MissingEntry_IsFalseWithNothing() { SaveNode found; CheckFalse(SaveNode.NewTable().TryGetEntry("a", out found)); CheckNull(found); } public void NodeThatIsNotATable_IsFalseWithNothing() { SaveNode found; CheckFalse(SaveNode.NewList().TryGetEntry("a", out found)); CheckNull(found); CheckFalse(SaveNode.OfText("1").TryGetEntry("a", out found)); CheckFalse(SaveNode.Null.TryGetEntry("a", out found)); } public void ReferenceToATable_FindsTheTablesEntry() { SaveNode table = SaveNode.NewTable(); table.Entries["a"] = SaveNode.OfText("1"); SaveNode reference = SaveNode.NewRef(); reference.Resolve(table); SaveNode found; CheckTrue(reference.TryGetEntry("a", out found)); CheckEqual("1", found.Text); } } public class RequireEntryTests : TestFixture { public void PresentEntry_IsReturned() { SaveNode node = SaveNode.NewTable(); node.Entries["a"] = SaveNode.OfText("1"); CheckEqual("1", node.RequireEntry("a").Text); } public void MissingEntry_Throws() { CheckThrow(typeof(InvalidDataException)); SaveNode.NewTable().RequireEntry("a"); } public void Text_Throws() { CheckThrow(typeof(InvalidDataException)); SaveNode.OfText("1").RequireEntry("a"); } public void ReferenceToTable_ReturnsTheTablesEntry() { SaveNode table = SaveNode.NewTable(); table.Entries["a"] = SaveNode.OfText("1"); SaveNode reference = SaveNode.NewRef(); reference.Resolve(table); CheckEqual("1", reference.RequireEntry("a").Text); } public void ReferenceToText_Throws() { SaveNode reference = SaveNode.NewRef(); reference.Resolve(SaveNode.OfText("1")); CheckThrow(typeof(InvalidDataException)); reference.RequireEntry("a"); } } public class TryGetItemsTests : TestFixture { public void List_IsTrueWithItsItems() { SaveNode node = SaveNode.NewList(); node.Items.Add(SaveNode.OfText("b")); IReadOnlyList items; CheckTrue(node.TryGetItems(out items)); CheckEqual("b", items[0].Text); } public void EmptyTable_IsTrueWithNoItems() { IReadOnlyList items; CheckTrue(SaveNode.NewTable().TryGetItems(out items)); CheckEqual(0, items.Count); } public void TableWithEntries_IsFalseWithNothing() { SaveNode node = SaveNode.NewTable(); node.Entries["a"] = SaveNode.Null; IReadOnlyList items; CheckFalse(node.TryGetItems(out items)); CheckNull(items); } public void TextAndNull_AreFalse() { IReadOnlyList items; CheckFalse(SaveNode.OfText("1").TryGetItems(out items)); CheckFalse(SaveNode.Null.TryGetItems(out items)); } public void ReferenceToAList_FindsTheListsItems() { SaveNode list = SaveNode.NewList(); list.Items.Add(SaveNode.OfText("a")); SaveNode reference = SaveNode.NewRef(); reference.Resolve(list); IReadOnlyList items; CheckTrue(reference.TryGetItems(out items)); CheckEqual("a", items[0].Text); } } public class TryGetMapTests : TestFixture { public void Map_IsTrueWithItsPairs() { SaveNode node = SaveNode.NewMap(); node.Pairs.Add(new KeyValuePair(SaveNode.OfText("b"), SaveNode.OfText("1"))); IReadOnlyList> pairs; CheckTrue(node.TryGetMap(out pairs)); CheckEqual("1", pairs[0].Value.Text); } public void Table_IsTrueWithTextKeysSortedByKey() { SaveNode node = SaveNode.NewTable(); node.Entries["b"] = SaveNode.OfText("1"); node.Entries["a"] = SaveNode.OfText("2"); IReadOnlyList> pairs; CheckTrue(node.TryGetMap(out pairs)); CheckEqual("a", pairs[0].Key.Text); CheckEqual("b", pairs[1].Key.Text); } public void EmptyTable_IsTrueWithNoPairs() { IReadOnlyList> pairs; CheckTrue(SaveNode.NewTable().TryGetMap(out pairs)); CheckEqual(0, pairs.Count); } public void ListTextAndNull_AreFalseWithNothing() { IReadOnlyList> pairs; CheckFalse(SaveNode.NewList().TryGetMap(out pairs)); CheckNull(pairs); CheckFalse(SaveNode.OfText("1").TryGetMap(out pairs)); CheckFalse(SaveNode.Null.TryGetMap(out pairs)); } public void ReferenceToAMap_FindsTheMapsPairs() { SaveNode map = SaveNode.NewMap(); map.Pairs.Add(new KeyValuePair(SaveNode.OfText("a"), SaveNode.OfText("1"))); SaveNode reference = SaveNode.NewRef(); reference.Resolve(map); IReadOnlyList> pairs; CheckTrue(reference.TryGetMap(out pairs)); CheckEqual("1", pairs[0].Value.Text); } } public class RequireItemsTests : TestFixture { public void List_ReturnsItsItemsInOrder() { SaveNode node = SaveNode.NewList(); node.Items.Add(SaveNode.OfText("b")); node.Items.Add(SaveNode.OfText("a")); CheckEqual(2, node.RequireItems().Count); CheckEqual("b", node.RequireItems()[0].Text); CheckEqual("a", node.RequireItems()[1].Text); } public void EmptyTable_IsAnEmptyList() { CheckEqual(0, SaveNode.NewTable().RequireItems().Count); } public void EmptyTable_SharesOneEmptyList() { CheckTrue(ReferenceEquals(SaveNode.NewTable().RequireItems(), SaveNode.NewTable().RequireItems())); } public void TableWithEntries_Throws() { SaveNode node = SaveNode.NewTable(); node.Entries["a"] = SaveNode.Null; CheckThrow(typeof(InvalidDataException)); node.RequireItems(); } public void Text_Throws() { CheckThrow(typeof(InvalidDataException)); SaveNode.OfText("1").RequireItems(); } public void Null_Throws() { CheckThrow(typeof(InvalidDataException)); SaveNode.Null.RequireItems(); } public void ReferenceToList_ReturnsTheListsItems() { SaveNode list = SaveNode.NewList(); list.Items.Add(SaveNode.OfText("a")); SaveNode reference = SaveNode.NewRef(); reference.Resolve(list); CheckEqual("a", reference.RequireItems()[0].Text); } public void ReferenceToEmptyTable_IsAnEmptyList() { SaveNode reference = SaveNode.NewRef(); reference.Resolve(SaveNode.NewTable()); CheckEqual(0, reference.RequireItems().Count); } public void ReferenceToText_Throws() { SaveNode reference = SaveNode.NewRef(); reference.Resolve(SaveNode.OfText("1")); CheckThrow(typeof(InvalidDataException)); reference.RequireItems(); } } public class RequireMapTests : TestFixture { public void Map_ReturnsItsPairsInOrder() { SaveNode node = SaveNode.NewMap(); node.Pairs.Add(new KeyValuePair(SaveNode.OfText("b"), SaveNode.OfText("1"))); node.Pairs.Add(new KeyValuePair(SaveNode.OfText("a"), SaveNode.OfText("2"))); CheckEqual(2, node.RequireMap().Count); CheckEqual("b", node.RequireMap()[0].Key.Text); CheckEqual("2", node.RequireMap()[1].Value.Text); } public void Table_BecomesTextKeysSortedByKey() { SaveNode node = SaveNode.NewTable(); node.Entries["b"] = SaveNode.OfText("1"); node.Entries["a"] = SaveNode.OfText("2"); IReadOnlyList> pairs = node.RequireMap(); CheckEqual(2, pairs.Count); CheckEqual(SaveNode.Kinds.Text, pairs[0].Key.Kind); CheckEqual("a", pairs[0].Key.Text); CheckEqual("2", pairs[0].Value.Text); CheckEqual("b", pairs[1].Key.Text); CheckEqual("1", pairs[1].Value.Text); } public void EmptyTable_IsAnEmptyMap() { CheckEqual(0, SaveNode.NewTable().RequireMap().Count); } public void EmptyTable_SharesOneEmptyMap() { CheckTrue(ReferenceEquals(SaveNode.NewTable().RequireMap(), SaveNode.NewTable().RequireMap())); } public void Text_Throws() { CheckThrow(typeof(InvalidDataException)); SaveNode.OfText("1").RequireMap(); } public void Null_Throws() { CheckThrow(typeof(InvalidDataException)); SaveNode.Null.RequireMap(); } public void List_Throws() { CheckThrow(typeof(InvalidDataException)); SaveNode.NewList().RequireMap(); } public void ReferenceToMap_ReturnsTheMapsPairs() { SaveNode map = SaveNode.NewMap(); map.Pairs.Add(new KeyValuePair(SaveNode.OfText("a"), SaveNode.OfText("1"))); SaveNode reference = SaveNode.NewRef(); reference.Resolve(map); CheckEqual("1", reference.RequireMap()[0].Value.Text); } public void ReferenceToTable_BecomesTextKeys() { SaveNode table = SaveNode.NewTable(); table.Entries["a"] = SaveNode.OfText("1"); SaveNode reference = SaveNode.NewRef(); reference.Resolve(table); CheckEqual("a", reference.RequireMap()[0].Key.Text); } public void ReferenceToEmptyTable_IsAnEmptyMap() { SaveNode reference = SaveNode.NewRef(); reference.Resolve(SaveNode.NewTable()); CheckEqual(0, reference.RequireMap().Count); } public void ReferenceToText_Throws() { SaveNode reference = SaveNode.NewRef(); reference.Resolve(SaveNode.OfText("1")); CheckThrow(typeof(InvalidDataException)); reference.RequireMap(); } } public class NewRefTests : TestFixture { public void IsARefWithNoTargetYet() { SaveNode reference = SaveNode.NewRef(); CheckEqual(SaveNode.Kinds.Ref, reference.Kind); CheckNull(reference.Target); CheckNull(reference.Entries); CheckNull(reference.Items); CheckNull(reference.Pairs); } } public class ResolveTests : TestFixture { public void Target_IsWhatTheRefStandsFor() { SaveNode reference = SaveNode.NewRef(); SaveNode table = SaveNode.NewTable(); reference.Resolve(table); CheckTrue(ReferenceEquals(table, reference.Target)); } public void RefAlreadyResolved_Throws() { SaveNode reference = SaveNode.NewRef(); reference.Resolve(SaveNode.NewTable()); CheckThrow(typeof(InvalidOperationException)); reference.Resolve(SaveNode.NewTable()); } public void NodeThatIsNotARef_Throws() { CheckThrow(typeof(InvalidOperationException)); SaveNode.NewTable().Resolve(SaveNode.NewTable()); } public void Itself_Throws() { SaveNode reference = SaveNode.NewRef(); CheckThrow(typeof(InvalidOperationException)); reference.Resolve(reference); } public void RefLeadingBackToIt_Throws() { SaveNode first = SaveNode.NewRef(); SaveNode second = SaveNode.NewRef(); second.Resolve(first); CheckThrow(typeof(InvalidOperationException)); first.Resolve(second); } } public class ResolvedTests : TestFixture { public void NodeThatIsNotARef_IsItself() { SaveNode table = SaveNode.NewTable(); CheckTrue(ReferenceEquals(table, table.Resolved)); } public void Ref_IsItsTarget() { SaveNode reference = SaveNode.NewRef(); SaveNode table = SaveNode.NewTable(); reference.Resolve(table); CheckTrue(ReferenceEquals(table, reference.Resolved)); } public void RefToARef_IsFollowedToTheEnd() { SaveNode first = SaveNode.NewRef(); SaveNode second = SaveNode.NewRef(); SaveNode table = SaveNode.NewTable(); first.Resolve(second); second.Resolve(table); CheckTrue(ReferenceEquals(table, first.Resolved)); } public void RefNeverResolved_Throws() { CheckThrow(typeof(InvalidOperationException)); SaveNode unused = SaveNode.NewRef().Resolved; } public void RefToAnUnresolvedRef_Throws() { SaveNode first = SaveNode.NewRef(); first.Resolve(SaveNode.NewRef()); CheckThrow(typeof(InvalidOperationException)); SaveNode unused = first.Resolved; } } public class ToStringTests : TestFixture { public void Ref_IsAReference() { CheckEqual("a reference", SaveNode.NewRef().ToString()); } public void Text_IsQuoted() { CheckEqual("\"1\"", SaveNode.OfText("1").ToString()); } public void Null_IsNull() { CheckEqual("null", SaveNode.Null.ToString()); } public void Table_ListsItsKeysInOrder() { SaveNode node = SaveNode.NewTable(); node.Entries["b"] = SaveNode.Null; node.Entries["a"] = SaveNode.Null; CheckEqual("a table of a, b", node.ToString()); } public void List_SaysHowManyItemsItHas() { SaveNode node = SaveNode.NewList(); node.Items.Add(SaveNode.Null); node.Items.Add(SaveNode.Null); CheckEqual("a list of 2", node.ToString()); } public void Map_SaysHowManyPairsItHas() { SaveNode node = SaveNode.NewMap(); node.Pairs.Add(new KeyValuePair(SaveNode.OfText("a"), SaveNode.Null)); CheckEqual("a map of 1", node.ToString()); } } } }