Caching.Tests fixtures: element ids are 12-hex literals, the form the id rule accepts
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
f84428b9b9
commit
b86becca93
3 changed files with 51 additions and 51 deletions
|
|
@ -308,7 +308,7 @@ namespace GameCult.Caching.Tests
|
|||
{
|
||||
Id = "leaves", Flag = true, Blob = new byte[] { 1, 2, 3 }, I = -7, L = 5_000_000_000, F = 0.1f, D = 0.1, MaybeI = 9,
|
||||
Tags = new List<string> { "a", "b" }, Names = new[] { "x", "y" }, Any = "text",
|
||||
Nested = new LeafInner { N = "inner", W = 0.1f, Id = "n" }, Items = new List<LeafInner> { new() { N = "one", W = 0.1f, Id = "i1" }, new() { N = "two", W = 1.5f, Id = "i2" } },
|
||||
Nested = new LeafInner { N = "inner", W = 0.1f, Id = "000000000011" }, Items = new List<LeafInner> { new() { N = "one", W = 0.1f, Id = "000000000012" }, new() { N = "two", W = 1.5f, Id = "000000000013" } },
|
||||
Shape = new LeafCircle { R = 0.1f }, Floats = new[] { 0.1f, 1.5f }, MaybeF = 0.1f,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ namespace GameCult.Caching.Tests
|
|||
};
|
||||
|
||||
// Unit8: slots [id].
|
||||
private static Emit UnitArm(int key) => (ref MessagePackWriter w) => { w.WriteArrayHeader(2); w.Write(key); w.WriteArrayHeader(1); w.Write("u"); };
|
||||
private static Emit UnitArm(int key) => (ref MessagePackWriter w) => { w.WriteArrayHeader(2); w.Write(key); w.WriteArrayHeader(1); w.Write("000000000007"); };
|
||||
|
||||
// Branch: slots [children, next, id].
|
||||
private static Emit BranchArm(int key, Emit next, params Emit[] children) => (ref MessagePackWriter w) =>
|
||||
|
|
@ -53,7 +53,7 @@ namespace GameCult.Caching.Tests
|
|||
w.WriteArrayHeader(children.Length);
|
||||
foreach (var child in children) child(ref w);
|
||||
next(ref w);
|
||||
w.Write("b");
|
||||
w.Write("000000000008");
|
||||
};
|
||||
|
||||
private static Emit List(params Emit[] items) => (ref MessagePackWriter w) =>
|
||||
|
|
@ -123,22 +123,22 @@ namespace GameCult.Caching.Tests
|
|||
[TestCase(7)]
|
||||
[TestCase(10)]
|
||||
public void UnknownArmInFieldRefused(int key) =>
|
||||
AssertRefused(Doc(LeafArm(key, "r", Canary, 7)), NodeName, key, "3, 5, 8, 9");
|
||||
AssertRefused(Doc(LeafArm(key, "000000000005", Canary, 7)), NodeName, key, "3, 5, 8, 9");
|
||||
|
||||
[TestCase(0)]
|
||||
[TestCase(4)]
|
||||
[TestCase(10)]
|
||||
public void UnknownArmInListRefused(int key) =>
|
||||
AssertRefused(Doc(LeafArm(3, "r", "ok", 1), List(UnitArm(8), LeafArm(key, "i", Canary, 7))), NodeName, key, "3, 5, 8, 9");
|
||||
AssertRefused(Doc(LeafArm(3, "000000000005", "ok", 1), List(UnitArm(8), LeafArm(key, "000000000004", Canary, 7))), NodeName, key, "3, 5, 8, 9");
|
||||
|
||||
// Inside an arm's own list, and inside an arm's own field: the union nested under a union.
|
||||
[TestCase(4)]
|
||||
[TestCase(10)]
|
||||
public void UnknownArmNestedInArmRefused(int key)
|
||||
{
|
||||
AssertRefused(Doc(BranchArm(5, Nil, UnitArm(8), LeafArm(key, "c", Canary, 7))), NodeName, key, "3, 5, 8, 9");
|
||||
AssertRefused(Doc(BranchArm(5, LeafArm(key, "n", Canary, 7))), NodeName, key, "3, 5, 8, 9");
|
||||
AssertRefused(Doc(BranchArm(5, Nil, BranchArm(5, Nil, BranchArm(5, Nil, LeafArm(key, "deep", Canary, 7))))), NodeName, key, "3, 5, 8, 9");
|
||||
AssertRefused(Doc(BranchArm(5, Nil, UnitArm(8), LeafArm(key, "000000000006", Canary, 7))), NodeName, key, "3, 5, 8, 9");
|
||||
AssertRefused(Doc(BranchArm(5, LeafArm(key, "000000000003", Canary, 7))), NodeName, key, "3, 5, 8, 9");
|
||||
AssertRefused(Doc(BranchArm(5, Nil, BranchArm(5, Nil, BranchArm(5, Nil, LeafArm(key, "000000000002", Canary, 7))))), NodeName, key, "3, 5, 8, 9");
|
||||
}
|
||||
|
||||
// A union whose arms are also a union has its own key set: 7 is Outer's (OuterOnly) and not Inner's.
|
||||
|
|
@ -175,9 +175,9 @@ namespace GameCult.Caching.Tests
|
|||
foreach (var doc in new[]
|
||||
{
|
||||
new GuardDoc { Root = new Rogue() },
|
||||
new GuardDoc { Items = { new Unit8 { Id = "u" }, new Rogue() } },
|
||||
new GuardDoc { Root = new Branch { Id = "b", Children = { new Rogue() } } },
|
||||
new GuardDoc { Root = new Branch { Id = "b", Next = new Rogue() } },
|
||||
new GuardDoc { Items = { new Unit8 { Id = "000000000007" }, new Rogue() } },
|
||||
new GuardDoc { Root = new Branch { Id = "000000000008", Children = { new Rogue() } } },
|
||||
new GuardDoc { Root = new Branch { Id = "000000000008", Next = new Rogue() } },
|
||||
new GuardDoc { Root = new DerivedLeaf() },
|
||||
new GuardDoc { Crafted = new Unlisted() },
|
||||
})
|
||||
|
|
@ -206,26 +206,26 @@ namespace GameCult.Caching.Tests
|
|||
Id = "d1",
|
||||
Root = new Branch
|
||||
{
|
||||
Id = "b",
|
||||
Id = "000000000008",
|
||||
Children =
|
||||
{
|
||||
new Leaf { Id = "a", Content = "x", Weight = 1 },
|
||||
new Unit8 { Id = "u" },
|
||||
new Branch { Id = "b", Children = { new Branch { Id = "b", Children = { new Leaf { Id = "deep", Content = "y", Weight = 2 } } } } }
|
||||
new Leaf { Id = "000000000001", Content = "x", Weight = 1 },
|
||||
new Unit8 { Id = "000000000007" },
|
||||
new Branch { Id = "000000000008", Children = { new Branch { Id = "000000000008", Children = { new Leaf { Id = "000000000002", Content = "y", Weight = 2 } } } } }
|
||||
},
|
||||
Next = new Leaf { Id = "n", Content = "z", Weight = 3 }
|
||||
Next = new Leaf { Id = "000000000003", Content = "z", Weight = 3 }
|
||||
},
|
||||
Items = { new Unit8 { Id = "u" }, new Leaf { Id = "i", Content = "w", Weight = 4 }, null! },
|
||||
Items = { new Unit8 { Id = "000000000007" }, new Leaf { Id = "000000000004", Content = "w", Weight = 4 }, null! },
|
||||
Crafted = new InnerB { N = 9 },
|
||||
Any = new InnerA { N = 8 }
|
||||
};
|
||||
|
||||
private static byte[] KnownArmBytes() => Doc(
|
||||
BranchArm(5, LeafArm(3, "n", "z", 3),
|
||||
LeafArm(3, "a", "x", 1),
|
||||
BranchArm(5, LeafArm(3, "000000000003", "z", 3),
|
||||
LeafArm(3, "000000000001", "x", 1),
|
||||
UnitArm(8),
|
||||
BranchArm(5, Nil, BranchArm(5, Nil, LeafArm(3, "deep", "y", 2)))),
|
||||
List(UnitArm(8), LeafArm(3, "i", "w", 4), Nil),
|
||||
BranchArm(5, Nil, BranchArm(5, Nil, LeafArm(3, "000000000002", "y", 2)))),
|
||||
List(UnitArm(8), LeafArm(3, "000000000004", "w", 4), Nil),
|
||||
InnerArm(1, 9),
|
||||
InnerArm(1, 8));
|
||||
|
||||
|
|
@ -458,13 +458,13 @@ namespace GameCult.Caching.Tests
|
|||
new CultPersistedRecord
|
||||
{
|
||||
Key = "base", SchemaId = descriptor.SchemaId, StoredAt = "2026-01-01T00:00:00.0000000Z",
|
||||
Payload = Doc(LeafArm(3, "r", "ok", 1))
|
||||
Payload = Doc(LeafArm(3, "000000000005", "ok", 1))
|
||||
},
|
||||
new CultPersistedRecord
|
||||
{
|
||||
Key = "variant", SchemaId = descriptor.SchemaId, StoredAt = "2026-01-01T00:00:00.0000000Z",
|
||||
Payload = Array.Empty<byte>(),
|
||||
Variant = new CultVariantDelta("base", new[] { CultVariantOverride.Set(1, Raw(LeafArm(4, "r", Canary, 7))) })
|
||||
Variant = new CultVariantDelta("base", new[] { CultVariantOverride.Set(1, Raw(LeafArm(4, "000000000005", Canary, 7))) })
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
|
@ -498,14 +498,14 @@ namespace GameCult.Caching.Tests
|
|||
try
|
||||
{
|
||||
var path = Path.Combine(folder, "guard.cc");
|
||||
var genuine = Doc(LeafArm(3, "r", Canary, 7));
|
||||
var genuine = Doc(LeafArm(3, "000000000005", Canary, 7));
|
||||
using (var writer = CultCacheMessagePack.Create(path, new CultCacheOpenOptions { Registry = Registry, UseDirectoryStore = directory, StoreFlushOnDispose = true }))
|
||||
{
|
||||
await writer.UpsertAsync(typeof(GuardDoc), new GuardDoc { Id = "d1", Root = new Leaf { Id = "r", Content = Canary, Weight = 7 } }, new CultRecordKey("d1"));
|
||||
await writer.UpsertAsync(typeof(GuardDoc), new GuardDoc { Id = "d1", Root = new Leaf { Id = "000000000005", Content = Canary, Weight = 7 } }, new CultRecordKey("d1"));
|
||||
await writer.FlushAsync();
|
||||
}
|
||||
|
||||
var forged = Doc(LeafArm(key, "r", Canary, 7));
|
||||
var forged = Doc(LeafArm(key, "000000000005", Canary, 7));
|
||||
Assert.That(forged.Length, Is.EqualTo(genuine.Length));
|
||||
// A directory store names a page by the SHA-256 of its bytes and its manifest commits to that hash, so a forged
|
||||
// page is renamed and the manifest told its new hash: the store then holds a well-formed page the reader must refuse.
|
||||
|
|
|
|||
|
|
@ -162,24 +162,24 @@ namespace GameCult.Caching.Tests
|
|||
Version = 3,
|
||||
Root = root ?? new Box
|
||||
{
|
||||
Id = "root",
|
||||
Id = "0000000000c0",
|
||||
Children =
|
||||
{
|
||||
new Text { Id = "t1", Content = "hello" },
|
||||
new Text { Id = "0000000000c1", Content = "hello" },
|
||||
new Use
|
||||
{
|
||||
Id = "u1",
|
||||
Id = "0000000000c2",
|
||||
Composition = new Composition
|
||||
{
|
||||
Name = "comp",
|
||||
Body = new Box { Id = "inner", Children = { new Text { Id = "deep", Content = "x" }, new Image { Id = "img", Uri = "uri://a", Alt = "alt" } } }
|
||||
Body = new Box { Id = "0000000000d0", Children = { new Text { Id = "0000000000d1", Content = "x" }, new Image { Id = "0000000000d2", Uri = "uri://a", Alt = "alt" } } }
|
||||
},
|
||||
Slots = { new Text { Id = "s1", Content = "slot" }, null!, new Box { Id = "b2" } }
|
||||
Slots = { new Text { Id = "0000000000e1", Content = "slot" }, null!, new Box { Id = "0000000000e2" } }
|
||||
},
|
||||
new Image { Id = "i2", Uri = "uri://b", Alt = "" }
|
||||
new Image { Id = "0000000000c3", Uri = "uri://b", Alt = "" }
|
||||
}
|
||||
},
|
||||
Outcomes = { new Pending { Message = "wait", Id = "p" }, new Completed { SourceVersion = 7, Id = "c" }, new Denied { Id = "d" } },
|
||||
Outcomes = { new Pending { Message = "wait", Id = "0000000000a1" }, new Completed { SourceVersion = 7, Id = "0000000000a2" }, new Denied { Id = "0000000000a3" } },
|
||||
Part = new Tool { Name = "hammer", Uses = 12 },
|
||||
Crafted = new Part { Name = "gear", Count = 4 },
|
||||
Missing = null
|
||||
|
|
@ -255,13 +255,13 @@ namespace GameCult.Caching.Tests
|
|||
private static byte[] Surface(Emit? root = null, Emit? outcomes = null, Emit? crafted = null, Extra? extra = null, Emit? trailing = null)
|
||||
{
|
||||
extra ??= new Extra();
|
||||
root ??= BoxArm("root", Slots(
|
||||
TextArm("t1", "hello"),
|
||||
ArmOf(2, Str("u1"),
|
||||
Plus(extra.Composition, Str("comp"), BoxArm("inner", Slots(TextArm("deep", "x"), ImageArm("img", "uri://a", "alt")))),
|
||||
Slots(TextArm("s1", "slot", extra.ListElement), Nil, BoxArm("b2", Slots()))),
|
||||
ImageArm("i2", "uri://b", "")), extra.RootArm);
|
||||
outcomes ??= Slots(ArmOf(0, Str("wait"), Str("p")), ArmOf(1, Num(7), Str("c")), ArmOf(2, Str("d")));
|
||||
root ??= BoxArm("0000000000c0", Slots(
|
||||
TextArm("0000000000c1", "hello"),
|
||||
ArmOf(2, Str("0000000000c2"),
|
||||
Plus(extra.Composition, Str("comp"), BoxArm("0000000000d0", Slots(TextArm("0000000000d1", "x"), ImageArm("0000000000d2", "uri://a", "alt")))),
|
||||
Slots(TextArm("0000000000e1", "slot", extra.ListElement), Nil, BoxArm("0000000000e2", Slots()))),
|
||||
ImageArm("0000000000c3", "uri://b", "")), extra.RootArm);
|
||||
outcomes ??= Slots(ArmOf(0, Str("wait"), Str("0000000000a1")), ArmOf(1, Num(7), Str("0000000000a2")), ArmOf(2, Str("0000000000a3")));
|
||||
crafted ??= ArmOf(1, Str("gear"), Num(4));
|
||||
var slots = new[] { Str("surface"), Num(3), root, outcomes, ArmOf(1, Str("hammer"), Num(12)), crafted, Nil };
|
||||
return Raw(Slots(trailing != null ? slots.Append(trailing).ToArray() : extra.Record ? slots.Append(ExtraSlot).ToArray() : slots));
|
||||
|
|
@ -284,7 +284,7 @@ namespace GameCult.Caching.Tests
|
|||
new Case("unknown-arm-list.msgpack", "refused", "Outcome", 7, "unknown-arm",
|
||||
Surface(outcomes: Slots(ArmOf(0, Str("wait")), ArmOf(7, Str(Canary))))),
|
||||
new Case("unknown-arm-nested.msgpack", "refused", "Node", 9, "unknown-arm",
|
||||
Surface(root: BoxArm("root", Slots(BoxArm("l1", Slots(BoxArm("l2", Slots(ArmOf(9, Str("deep"), Str(Canary)))))))))),
|
||||
Surface(root: BoxArm("0000000000c0", Slots(BoxArm("0000000000d3", Slots(BoxArm("0000000000d4", Slots(ArmOf(9, Str("deep"), Str(Canary)))))))))),
|
||||
new Case("inner-union-outer-key.msgpack", "refused", "CraftedItem", 2, "unknown-arm",
|
||||
Surface(crafted: ArmOf(2, Str("gear"), Num(4)))),
|
||||
new Case("arm-arity.msgpack", "refused", "Node", 1, "arity",
|
||||
|
|
@ -461,30 +461,30 @@ namespace GameCult.Caching.Tests
|
|||
Slots(slots)(ref w);
|
||||
};
|
||||
|
||||
private static Emit WithOutcome(Emit element) => Slots(ArmOf(0, Str("wait"), Str("p")), ArmOf(1, Num(7), Str("c")), ArmOf(2, Str("d")), element);
|
||||
private static Emit WithOutcome(Emit element) => Slots(ArmOf(0, Str("wait"), Str("0000000000a1")), ArmOf(1, Num(7), Str("0000000000a2")), ArmOf(2, Str("0000000000a3")), element);
|
||||
|
||||
private static Emit WrapChain(int wraps, Emit leaf) => wraps == 0 ? leaf : ArmOf(6, WrapChain(wraps - 1, leaf), Str("w"));
|
||||
private static Emit WrapChain(int wraps, Emit leaf) => wraps == 0 ? leaf : ArmOf(6, WrapChain(wraps - 1, leaf), Str("0000000000b1"));
|
||||
|
||||
private static Node WrapChainValue(int wraps, Node leaf)
|
||||
{
|
||||
for (var i = 0; i < wraps; i++) leaf = new Wrap { Inner = leaf, Id = "w" };
|
||||
for (var i = 0; i < wraps; i++) leaf = new Wrap { Inner = leaf, Id = "0000000000b1" };
|
||||
return leaf;
|
||||
}
|
||||
|
||||
// n arrays nested inside one another around a single string.
|
||||
private static Emit Nested(int n) => n == 1 ? Slots(Str(Canary)) : Slots(Nested(n - 1));
|
||||
|
||||
private static Emit AtLimitLeaf => BoxArm("leaf", Slots());
|
||||
private static Emit PastLimitLeaf => TextArm("leaf", Canary);
|
||||
private static Emit AtLimitLeaf => BoxArm("0000000000f0", Slots());
|
||||
private static Emit PastLimitLeaf => TextArm("0000000000f0", Canary);
|
||||
|
||||
private static IReadOnlyList<Case> BoundsCases() => new[]
|
||||
{
|
||||
new Case("arm-key-int32-min.msgpack", "accepted", "Outcome", int.MinValue, "arm-key-int32-min.msgpack",
|
||||
Surface(outcomes: WithOutcome(ArmOf(int.MinValue, Str("f"))))),
|
||||
Surface(outcomes: WithOutcome(ArmOf(int.MinValue, Str("0000000000a4"))))),
|
||||
new Case("arm-key-int32-max.msgpack", "accepted", "Outcome", int.MaxValue, "arm-key-int32-max.msgpack",
|
||||
Surface(outcomes: WithOutcome(ArmOf(int.MaxValue, Str("x"))))),
|
||||
Surface(outcomes: WithOutcome(ArmOf(int.MaxValue, Str("0000000000a5"))))),
|
||||
new Case("arm-key-wide-coding.msgpack", "accepted", "Outcome", int.MaxValue, "arm-key-int32-max.msgpack",
|
||||
Surface(outcomes: WithOutcome(RawKey((ref MessagePackWriter w) => w.WriteUInt64(int.MaxValue), Str("x"))))),
|
||||
Surface(outcomes: WithOutcome(RawKey((ref MessagePackWriter w) => w.WriteUInt64(int.MaxValue), Str("0000000000a5"))))),
|
||||
new Case("arm-key-above-int32.msgpack", "refused", "Outcome", null, "key-out-of-range",
|
||||
Surface(outcomes: WithOutcome(RawKey((ref MessagePackWriter w) => w.Write(0x80000000u))))),
|
||||
new Case("arm-key-below-int32.msgpack", "refused", "Outcome", null, "key-out-of-range",
|
||||
|
|
@ -650,7 +650,7 @@ namespace GameCult.Caching.Tests
|
|||
var payload = Committed("depth-at-limit.msgpack");
|
||||
Assert.That(DepthOf(payload), Is.EqualTo(Limit), "the vector nests exactly the limit, counted independently");
|
||||
Assert.That(Convert.ToHexString(SerializeValue(Decode(payload))), Is.EqualTo(Convert.ToHexString(payload)), "read, then written again");
|
||||
var built = Constructed(WrapChainValue(AtLimitWraps, new Box { Id = "leaf" }));
|
||||
var built = Constructed(WrapChainValue(AtLimitWraps, new Box { Id = "0000000000f0" }));
|
||||
Assert.That(Convert.ToHexString(SerializeValue(built)), Is.EqualTo(Convert.ToHexString(payload)), "the constructed value writes the vector");
|
||||
}
|
||||
|
||||
|
|
@ -663,7 +663,7 @@ namespace GameCult.Caching.Tests
|
|||
Assert.That(read, Does.Contain(typeof(UnionSurface).FullName).And.Contain($"the limit is {Limit}").And.Contain("refused on read").And.Not.Contain(Canary));
|
||||
|
||||
byte[]? written = null;
|
||||
var write = Chain(Refusal(() => written = SerializeValue(Constructed(WrapChainValue(PastLimitWraps, new Text { Id = "leaf", Content = Canary })))));
|
||||
var write = Chain(Refusal(() => written = SerializeValue(Constructed(WrapChainValue(PastLimitWraps, new Text { Id = "0000000000f0", Content = Canary })))));
|
||||
Assert.That(written, Is.Null, "nothing is returned");
|
||||
Assert.That(write, Does.Contain(typeof(UnionSurface).FullName).And.Contain($"the limit is {Limit}").And.Contain("refused on write").And.Not.Contain(Canary));
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue