using MessagePack;
using static GameCult.Thing.Contract.Tests.Builders;
namespace GameCult.Thing.Contract.Tests;
///
/// CultLib bounds payload nesting at 256 MessagePack containers (the document array is 1). A Box chain costs 3 containers per
/// level (union array, slots array, children list), and the deepest leaf's style adds 4 beyond its slots, so a chain of
/// 84 boxes nests 3 * 84 + 4 = 256 deep and 85 nests 259. Decoding recurses per level, so the default test thread carries
/// the deepest chain the bound admits: this package sets no thread size.
///
public sealed class DeepTreeTests
{
private const int DeepestAdmitted = 84;
private static SurfaceDocument Chain(int levels)
{
var node = Boxed("leaf");
for (var level = levels - 1; level >= 1; level--) node = Boxed($"deep-{level}", node);
return new SurfaceDocument("provider.a", "deep", 1, "deep", node, new List());
}
[Test]
public void TheDeepestChainTheBoundAdmitsRoundTripsOnTheTestThread()
{
var chain = Chain(DeepestAdmitted);
var bytes = Wire.Write(chain);
var decoded = (SurfaceDocument)Wire.Read(typeof(SurfaceDocument), bytes);
Assert.That(Convert.ToHexString(Wire.Write(decoded)), Is.EqualTo(Convert.ToHexString(bytes)));
var depth = 0;
for (var node = decoded.Root; node is BoxNode box; node = box.Children.SingleOrDefault()!) depth++;
Assert.That(depth, Is.EqualTo(DeepestAdmitted));
}
[Test]
public void OneLevelDeeperIsRefusedByTheBoundOnReadAndOnWrite()
{
var chain = Chain(DeepestAdmitted + 1);
var write = Assert.Throws(() => Wire.Write(chain))!;
Assert.That(write.Message, Does.Contain("payload nests 257").And.Contain("the limit is 256"));
// The bytes a hostile sender could produce, past the writer's own check.
var bytes = MessagePackSerializer.Serialize(typeof(SurfaceDocument), chain, Wire.Options);
var read = Assert.Throws(() => Wire.Read(typeof(SurfaceDocument), bytes))!;
Assert.That(read.Message, Does.Contain("payload nests 257").And.Contain("the limit is 256"));
}
[Test]
public void AThousandNodesWideRoundTrips()
{
var children = Enumerable.Range(0, 998).Select(index => Text($"t{index}", "x")).ToList();
children.Add(Boxed("tail"));
var wide = new SurfaceDocument("provider.a", "wide", 1, "wide", Boxed("root", children.ToArray()), new List());
var bytes = Wire.Write(wide);
var decoded = (SurfaceDocument)Wire.Read(typeof(SurfaceDocument), bytes);
Assert.That(((BoxNode)decoded.Root).Children, Has.Count.EqualTo(999));
Assert.That(Convert.ToHexString(Wire.Write(decoded)), Is.EqualTo(Convert.ToHexString(bytes)));
}
}