Add the canonical MessagePack encoding for every public CultMath value type
CultMathResolver formats float2/3/4, double2/3, int2/3/4, bool2/3/4,
quaternion, Color32, Random, float2x2, float3x3, rect and CultCellular as
component arrays, and sits in the default CultCache resolver chain so no
consumer registers anything. It lives in GameCult.Caching.MessagePack, which
already owns that chain; CultMath core stays dependency-free.
Vector, rect and Aetheria-formatter byte shapes are pinned by golden tests, a
reflection test fails when a public CultMath value type has no formatter, and
decode skips extra elements and refuses nil.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:13:22 +02:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using FluentAssertions;
|
|
|
|
|
using GameCult.Caching.MessagePack;
|
|
|
|
|
using CultMath;
|
|
|
|
|
using MessagePack;
|
Pin every CultMath MessagePack shape and decode a missing Color32 alpha as opaque
Golden bytes now cover double2, double3, int3, int4, bool3, bool4, quaternion,
Color32, Random, float3x3 and CultCellular. A missing Color32 alpha decodes as
255, the constructor default. A test proves a consumer resolver registered for
the assembly wins over CultMathResolver. The redundant nil check is deleted;
ReadArrayHeader already refuses nil.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:57:31 +02:00
|
|
|
using MessagePack.Formatters;
|
Add the canonical MessagePack encoding for every public CultMath value type
CultMathResolver formats float2/3/4, double2/3, int2/3/4, bool2/3/4,
quaternion, Color32, Random, float2x2, float3x3, rect and CultCellular as
component arrays, and sits in the default CultCache resolver chain so no
consumer registers anything. It lives in GameCult.Caching.MessagePack, which
already owns that chain; CultMath core stays dependency-free.
Vector, rect and Aetheria-formatter byte shapes are pinned by golden tests, a
reflection test fails when a public CultMath value type has no formatter, and
decode skips extra elements and refuses nil.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:13:22 +02:00
|
|
|
using NUnit.Framework;
|
|
|
|
|
|
Pin every CultMath MessagePack shape and decode a missing Color32 alpha as opaque
Golden bytes now cover double2, double3, int3, int4, bool3, bool4, quaternion,
Color32, Random, float3x3 and CultCellular. A missing Color32 alpha decodes as
255, the constructor default. A test proves a consumer resolver registered for
the assembly wins over CultMathResolver. The redundant nil check is deleted;
ReadArrayHeader already refuses nil.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:57:31 +02:00
|
|
|
[assembly: CultCacheFormatterResolver(typeof(GameCult.Caching.Tests.CultMathSerializationTests.Float2Override))]
|
|
|
|
|
|
Add the canonical MessagePack encoding for every public CultMath value type
CultMathResolver formats float2/3/4, double2/3, int2/3/4, bool2/3/4,
quaternion, Color32, Random, float2x2, float3x3, rect and CultCellular as
component arrays, and sits in the default CultCache resolver chain so no
consumer registers anything. It lives in GameCult.Caching.MessagePack, which
already owns that chain; CultMath core stays dependency-free.
Vector, rect and Aetheria-formatter byte shapes are pinned by golden tests, a
reflection test fails when a public CultMath value type has no formatter, and
decode skips extra elements and refuses nil.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:13:22 +02:00
|
|
|
namespace GameCult.Caching.Tests
|
|
|
|
|
{
|
|
|
|
|
public sealed class CultMathSerializationTests
|
|
|
|
|
{
|
|
|
|
|
private static readonly MessagePackSerializerOptions Options = CultDocumentMessagePackSerialization.Options;
|
|
|
|
|
|
|
|
|
|
private static string Hex<T>(T value) => Convert.ToHexString(MessagePackSerializer.Serialize(value, Options));
|
|
|
|
|
|
|
|
|
|
private static T Decode<T>(string hex) => MessagePackSerializer.Deserialize<T>(Convert.FromHexString(hex), Options);
|
|
|
|
|
|
|
|
|
|
[MessagePackObject]
|
|
|
|
|
public sealed class Carrier
|
|
|
|
|
{
|
|
|
|
|
[Key(0)] public float2 Position;
|
|
|
|
|
[Key(1)] public float3? Velocity;
|
|
|
|
|
[Key(2)] public float2[] Path = Array.Empty<float2>();
|
|
|
|
|
[Key(3)] public List<int2> Cells = new();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Bytes the pre-collapse CultVec2/CultVec3/CultRect encodings and Aetheria's Float2/Int2/Bool2/Float3/Float4
|
|
|
|
|
// formatters produce: an array of components in declaration order, float32 as 0xCA.
|
2026-09-29 16:15:29 +02:00
|
|
|
[Test]
|
|
|
|
|
public void Float2_MatchesTheLegacyVectorBytes()
|
Add the canonical MessagePack encoding for every public CultMath value type
CultMathResolver formats float2/3/4, double2/3, int2/3/4, bool2/3/4,
quaternion, Color32, Random, float2x2, float3x3, rect and CultCellular as
component arrays, and sits in the default CultCache resolver chain so no
consumer registers anything. It lives in GameCult.Caching.MessagePack, which
already owns that chain; CultMath core stays dependency-free.
Vector, rect and Aetheria-formatter byte shapes are pinned by golden tests, a
reflection test fails when a public CultMath value type has no formatter, and
decode skips extra elements and refuses nil.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:13:22 +02:00
|
|
|
{
|
2026-09-29 16:15:29 +02:00
|
|
|
const string hex = "92CA3F800000CA40000000";
|
Add the canonical MessagePack encoding for every public CultMath value type
CultMathResolver formats float2/3/4, double2/3, int2/3/4, bool2/3/4,
quaternion, Color32, Random, float2x2, float3x3, rect and CultCellular as
component arrays, and sits in the default CultCache resolver chain so no
consumer registers anything. It lives in GameCult.Caching.MessagePack, which
already owns that chain; CultMath core stays dependency-free.
Vector, rect and Aetheria-formatter byte shapes are pinned by golden tests, a
reflection test fails when a public CultMath value type has no formatter, and
decode skips extra elements and refuses nil.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:13:22 +02:00
|
|
|
Hex(new float2(1f, 2f)).Should().Be(hex);
|
|
|
|
|
Decode<float2>(hex).Should().Be(new float2(1f, 2f));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void Float3_MatchesTheLegacyVectorBytes()
|
|
|
|
|
{
|
|
|
|
|
const string hex = "93CA3F800000CA40000000CA40400000";
|
|
|
|
|
Hex(new float3(1f, 2f, 3f)).Should().Be(hex);
|
|
|
|
|
Decode<float3>(hex).Should().Be(new float3(1f, 2f, 3f));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void Rect_MatchesTheLegacyCultRectBytes()
|
|
|
|
|
{
|
|
|
|
|
const string hex = "9292CABF800000CAC000000092CA40A00000CA40E00000";
|
|
|
|
|
Hex(new rect(5f, 7f, -1f, -2f)).Should().Be(hex);
|
|
|
|
|
Decode<rect>(hex).Should().Be(new rect(-1f, -2f, 5f, 7f));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void ConsumerFormatterShapes_MatchByteForByte()
|
|
|
|
|
{
|
|
|
|
|
Hex(new float4(1f, 2f, 3f, 4f)).Should().Be("94CA3F800000CA40000000CA40400000CA40800000");
|
|
|
|
|
Hex(new int2(3, -4)).Should().Be("9203FC");
|
|
|
|
|
Hex(new bool2(true, false)).Should().Be("92C3C2");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void Decode_SkipsExtraElements_AndLeavesMissingOnesZero()
|
|
|
|
|
{
|
|
|
|
|
Decode<float2>("93CA3F800000CA40000000CA40400000").Should().Be(new float2(1f, 2f));
|
|
|
|
|
Decode<float3>("92CA3F800000CA40000000").Should().Be(new float3(1f, 2f, 0f));
|
|
|
|
|
Decode<rect>("9392CABF800000CAC000000092CA40A00000CA40E0000001").Should().Be(new rect(-1f, -2f, 5f, 7f));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void Decode_RefusesNilAndNonArrays()
|
|
|
|
|
{
|
|
|
|
|
Action nil = () => Decode<float2>("C0");
|
|
|
|
|
nil.Should().Throw<MessagePackSerializationException>();
|
|
|
|
|
Action notArray = () => Decode<float3>("01");
|
|
|
|
|
notArray.Should().Throw<MessagePackSerializationException>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void EveryFormattedType_RoundTrips()
|
|
|
|
|
{
|
|
|
|
|
RoundTrip(new float2(1.5f, -2f));
|
|
|
|
|
RoundTrip(new float3(1f, 2f, 3f));
|
|
|
|
|
RoundTrip(new float4(1f, 2f, 3f, 4f));
|
|
|
|
|
RoundTrip(new double2(1e300, -2.5));
|
|
|
|
|
RoundTrip(new double3(1, 2, 3));
|
|
|
|
|
RoundTrip(new int2(-7, 900000));
|
|
|
|
|
RoundTrip(new int3(1, -2, 3));
|
|
|
|
|
RoundTrip(new int4(1, 2, 3, int.MinValue));
|
|
|
|
|
RoundTrip(new bool2(true, false));
|
|
|
|
|
RoundTrip(new bool3(false, true, true));
|
|
|
|
|
RoundTrip(new bool4(true, false, false, true));
|
|
|
|
|
RoundTrip(new quaternion(0.1f, 0.2f, 0.3f, 0.9f));
|
|
|
|
|
RoundTrip(new Color32(255, 128, 0, 7));
|
|
|
|
|
RoundTrip(new CultMath.Random(12345u));
|
|
|
|
|
RoundTrip(new float2x2(1f, 2f, 3f, 4f));
|
|
|
|
|
RoundTrip(new float3x3(1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f));
|
|
|
|
|
RoundTrip(new rect(-1f, -2f, 5f, 7f));
|
|
|
|
|
RoundTrip(new CultCellular(new float4(1, 2, 3, 4), new float4(5, 6, 7, 8), 0.25f));
|
2026-09-30 02:46:29 +02:00
|
|
|
RoundTrip(new CultPhasor(new float4(1, 2, 3, 4), new float4(5, 6, 7, 8)));
|
2026-10-14 20:48:44 +02:00
|
|
|
RoundTrip(new SpanNoise(new float4(1, 2, 3, 4), 0.25f, 0.5f));
|
2026-10-15 20:49:31 +02:00
|
|
|
RoundTrip(new SpanPath { midpoint = new float3(1f, 2f, 3f), velocity = new float3(4f, 5f, 6f), speed = 7f, acceleration = 8f, halfLength = 9f });
|
|
|
|
|
RoundTrip(new SpanStage { frequency = 1f, stretch = 2f, axis = new float3(3f, 4f, 5f), shift = new float3(6f, 7f, 8f), offset = new float3(9f, 10f, 11f), octaveStep = new float3(12f, 13f, 14f) });
|
2026-10-16 18:16:37 +02:00
|
|
|
RoundTrip(new CultSiteCells(new float4(1, 2, 3, 4), new float4(5, 6, 7, 8), 9f, 10f));
|
|
|
|
|
RoundTrip(new CultSiteCells(new float4(0, 0, 0, 1.0e30f), new float4(0, 0, 0, 1.0e30f), -1f, -1f));
|
Add the canonical MessagePack encoding for every public CultMath value type
CultMathResolver formats float2/3/4, double2/3, int2/3/4, bool2/3/4,
quaternion, Color32, Random, float2x2, float3x3, rect and CultCellular as
component arrays, and sits in the default CultCache resolver chain so no
consumer registers anything. It lives in GameCult.Caching.MessagePack, which
already owns that chain; CultMath core stays dependency-free.
Vector, rect and Aetheria-formatter byte shapes are pinned by golden tests, a
reflection test fails when a public CultMath value type has no formatter, and
decode skips extra elements and refuses nil.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:13:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void Matrices_AreArraysOfRows()
|
|
|
|
|
{
|
2026-09-29 16:15:29 +02:00
|
|
|
Hex(new float2x2(1f, 2f, 3f, 4f)).Should().Be("9292CA3F800000CA4000000092CA40400000CA40800000");
|
Add the canonical MessagePack encoding for every public CultMath value type
CultMathResolver formats float2/3/4, double2/3, int2/3/4, bool2/3/4,
quaternion, Color32, Random, float2x2, float3x3, rect and CultCellular as
component arrays, and sits in the default CultCache resolver chain so no
consumer registers anything. It lives in GameCult.Caching.MessagePack, which
already owns that chain; CultMath core stays dependency-free.
Vector, rect and Aetheria-formatter byte shapes are pinned by golden tests, a
reflection test fails when a public CultMath value type has no formatter, and
decode skips extra elements and refuses nil.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:13:22 +02:00
|
|
|
}
|
|
|
|
|
|
Pin every CultMath MessagePack shape and decode a missing Color32 alpha as opaque
Golden bytes now cover double2, double3, int3, int4, bool3, bool4, quaternion,
Color32, Random, float3x3 and CultCellular. A missing Color32 alpha decodes as
255, the constructor default. A test proves a consumer resolver registered for
the assembly wins over CultMathResolver. The redundant nil check is deleted;
ReadArrayHeader already refuses nil.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:57:31 +02:00
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void EveryShape_IsPinnedByteForByte()
|
|
|
|
|
{
|
|
|
|
|
Hex(new double2(1d, 2d)).Should().Be("92CB3FF0000000000000CB4000000000000000");
|
|
|
|
|
Hex(new double3(1d, 2d, 3d)).Should().Be("93CB3FF0000000000000CB4000000000000000CB4008000000000000");
|
|
|
|
|
Hex(new int3(1, -2, 3)).Should().Be("9301FE03");
|
|
|
|
|
Hex(new int4(1, 2, 3, -1)).Should().Be("94010203FF");
|
|
|
|
|
Hex(new bool3(true, false, true)).Should().Be("93C3C2C3");
|
|
|
|
|
Hex(new bool4(false, true, true, false)).Should().Be("94C2C3C3C2");
|
|
|
|
|
Hex(new quaternion(1f, 2f, 3f, 4f)).Should().Be("94CA3F800000CA40000000CA40400000CA40800000");
|
|
|
|
|
Hex(new Color32(255, 128, 0, 7)).Should().Be("94CCFFCC800007");
|
|
|
|
|
Hex(new CultMath.Random(12345u)).Should().Be("91CD3039");
|
|
|
|
|
Hex(new float3x3(1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f, 9f)).Should().Be(
|
|
|
|
|
"93" +
|
|
|
|
|
"93CA3F800000CA40000000CA40400000" +
|
|
|
|
|
"93CA40800000CA40A00000CA40C00000" +
|
|
|
|
|
"93CA40E00000CA41000000CA41100000");
|
|
|
|
|
Hex(new CultCellular(new float4(1f, 2f, 3f, 4f), new float4(5f, 6f, 7f, 8f), 0.25f)).Should().Be(
|
|
|
|
|
"93" +
|
|
|
|
|
"94CA3F800000CA40000000CA40400000CA40800000" +
|
|
|
|
|
"94CA40A00000CA40C00000CA40E00000CA41000000" +
|
|
|
|
|
"CA3E800000");
|
2026-09-30 02:46:29 +02:00
|
|
|
Hex(new CultPhasor(new float4(1f, 2f, 3f, 4f), new float4(5f, 6f, 7f, 8f))).Should().Be(
|
|
|
|
|
"92" +
|
|
|
|
|
"94CA3F800000CA40000000CA40400000CA40800000" +
|
|
|
|
|
"94CA40A00000CA40C00000CA40E00000CA41000000");
|
2026-10-14 20:48:44 +02:00
|
|
|
Hex(new SpanNoise(new float4(1f, 2f, 3f, 4f), 0.25f, 0.5f)).Should().Be(
|
|
|
|
|
"93" +
|
|
|
|
|
"94CA3F800000CA40000000CA40400000CA40800000" +
|
|
|
|
|
"CA3E800000" +
|
|
|
|
|
"CA3F000000");
|
2026-10-15 20:49:31 +02:00
|
|
|
Hex(new SpanPath { midpoint = new float3(1f, 2f, 3f), velocity = new float3(4f, 5f, 6f), speed = 7f, acceleration = 8f, halfLength = 9f }).Should().Be(
|
|
|
|
|
"95" +
|
|
|
|
|
"93CA3F800000CA40000000CA40400000" +
|
|
|
|
|
"93CA40800000CA40A00000CA40C00000" +
|
|
|
|
|
"CA40E00000CA41000000CA41100000");
|
|
|
|
|
Hex(new SpanStage { frequency = 1f, stretch = 2f, axis = new float3(3f, 4f, 5f), shift = new float3(6f, 7f, 8f), offset = new float3(9f, 10f, 11f), octaveStep = new float3(12f, 13f, 14f) }).Should().Be(
|
|
|
|
|
"96" +
|
|
|
|
|
"CA3F800000" +
|
|
|
|
|
"CA40000000" +
|
|
|
|
|
"93CA40400000CA40800000CA40A00000" +
|
|
|
|
|
"93CA40C00000CA40E00000CA41000000" +
|
|
|
|
|
"93CA41100000CA41200000CA41300000" +
|
|
|
|
|
"93CA41400000CA41500000CA41600000");
|
2026-10-16 18:16:37 +02:00
|
|
|
Hex(new CultSiteCells(new float4(1, 2, 3, 4), new float4(5, 6, 7, 8), 9f, 10f)).Should().Be(
|
|
|
|
|
"94" +
|
|
|
|
|
"94CA3F800000CA40000000CA40400000CA40800000" +
|
|
|
|
|
"94CA40A00000CA40C00000CA40E00000CA41000000" +
|
|
|
|
|
"CA41100000" +
|
|
|
|
|
"CA41200000");
|
Pin every CultMath MessagePack shape and decode a missing Color32 alpha as opaque
Golden bytes now cover double2, double3, int3, int4, bool3, bool4, quaternion,
Color32, Random, float3x3 and CultCellular. A missing Color32 alpha decodes as
255, the constructor default. A test proves a consumer resolver registered for
the assembly wins over CultMathResolver. The redundant nil check is deleted;
ReadArrayHeader already refuses nil.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:57:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void Color32_MissingAlphaDecodesAsOpaque()
|
|
|
|
|
{
|
|
|
|
|
Decode<Color32>("93CCFFCC8000").Should().Be(new Color32(255, 128, 0, 255));
|
|
|
|
|
Decode<Color32>("94CCFFCC800007").Should().Be(new Color32(255, 128, 0, 7));
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-29 17:29:02 +02:00
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void Random_StateZero_IsTheGeneratorDefaultSeed()
|
|
|
|
|
{
|
|
|
|
|
// CultMath's generator maps state 0 to its default seed, so a zero or missing state is not degenerate.
|
|
|
|
|
var reference = new CultMath.Random(0u);
|
|
|
|
|
var expected = new[] { reference.NextUInt(), reference.NextUInt(), reference.NextUInt() };
|
|
|
|
|
|
|
|
|
|
foreach (var hex in new[] { "9100", "90" })
|
|
|
|
|
{
|
|
|
|
|
var decoded = Decode<CultMath.Random>(hex);
|
|
|
|
|
new[] { decoded.NextUInt(), decoded.NextUInt(), decoded.NextUInt() }.Should().Equal(expected);
|
|
|
|
|
}
|
|
|
|
|
}
|
Pin every CultMath MessagePack shape and decode a missing Color32 alpha as opaque
Golden bytes now cover double2, double3, int3, int4, bool3, bool4, quaternion,
Color32, Random, float3x3 and CultCellular. A missing Color32 alpha decodes as
255, the constructor default. A test proves a consumer resolver registered for
the assembly wins over CultMathResolver. The redundant nil check is deleted;
ReadArrayHeader already refuses nil.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:57:31 +02:00
|
|
|
[Test]
|
|
|
|
|
public void ConsumerResolvers_WinOverCultMathResolver()
|
|
|
|
|
{
|
|
|
|
|
var overridden = CultDocumentMessagePackSerialization.OptionsFor(typeof(Float2Override).Assembly);
|
|
|
|
|
|
|
|
|
|
MessagePackSerializer.Serialize(new float2(1f, 2f), overridden).Should().Equal(0xC3);
|
|
|
|
|
Hex(new float2(1f, 2f)).Should().Be("92CA3F800000CA40000000");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public sealed class Float2Override : IFormatterResolver
|
|
|
|
|
{
|
|
|
|
|
public static readonly Float2Override Instance = new();
|
|
|
|
|
|
|
|
|
|
public IMessagePackFormatter<T>? GetFormatter<T>() =>
|
|
|
|
|
typeof(T) == typeof(float2) ? (IMessagePackFormatter<T>)(object)Formatter.Instance : null;
|
|
|
|
|
|
|
|
|
|
private sealed class Formatter : IMessagePackFormatter<float2>
|
|
|
|
|
{
|
|
|
|
|
public static readonly Formatter Instance = new();
|
|
|
|
|
public void Serialize(ref MessagePackWriter writer, float2 value, MessagePackSerializerOptions options) => writer.Write(true);
|
|
|
|
|
public float2 Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) => throw new NotSupportedException();
|
|
|
|
|
}
|
|
|
|
|
}
|
Add the canonical MessagePack encoding for every public CultMath value type
CultMathResolver formats float2/3/4, double2/3, int2/3/4, bool2/3/4,
quaternion, Color32, Random, float2x2, float3x3, rect and CultCellular as
component arrays, and sits in the default CultCache resolver chain so no
consumer registers anything. It lives in GameCult.Caching.MessagePack, which
already owns that chain; CultMath core stays dependency-free.
Vector, rect and Aetheria-formatter byte shapes are pinned by golden tests, a
reflection test fails when a public CultMath value type has no formatter, and
decode skips extra elements and refuses nil.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-29 16:13:22 +02:00
|
|
|
[Test]
|
|
|
|
|
public void EveryPublicCultMathValueType_HasAFormatter()
|
|
|
|
|
{
|
|
|
|
|
var valueTypes = typeof(float2).Assembly.GetExportedTypes()
|
|
|
|
|
.Where(t => t.IsValueType && !t.IsEnum)
|
|
|
|
|
.ToHashSet();
|
|
|
|
|
|
|
|
|
|
valueTypes.Except(CultMathResolver.FormattedTypes).Should().BeEmpty(
|
|
|
|
|
"every public CultMath value type serializes through CultMathResolver");
|
|
|
|
|
CultMathResolver.FormattedTypes.Except(valueTypes).Should().BeEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
|
public void TheDefaultChain_ComposesMathIntoNullablesCollectionsAndDocuments()
|
|
|
|
|
{
|
|
|
|
|
var value = new Carrier
|
|
|
|
|
{
|
|
|
|
|
Position = new float2(1f, 2f),
|
|
|
|
|
Velocity = new float3(3f, 4f, 5f),
|
|
|
|
|
Path = new[] { new float2(0f, 1f), new float2(2f, 3f) },
|
|
|
|
|
Cells = new List<int2> { new int2(1, 2) },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var decoded = MessagePackSerializer.Deserialize<Carrier>(MessagePackSerializer.Serialize(value, Options), Options);
|
|
|
|
|
|
|
|
|
|
decoded.Position.Should().Be(value.Position);
|
|
|
|
|
decoded.Velocity.Should().Be(value.Velocity);
|
|
|
|
|
decoded.Path.Should().Equal(value.Path);
|
|
|
|
|
decoded.Cells.Should().Equal(value.Cells);
|
|
|
|
|
MessagePackSerializer.Serialize(new Carrier(), Options).Should().NotBeEmpty();
|
|
|
|
|
|
|
|
|
|
var absent = MessagePackSerializer.Deserialize<Carrier>(MessagePackSerializer.Serialize(new Carrier(), Options), Options);
|
|
|
|
|
absent.Velocity.Should().BeNull();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void RoundTrip<T>(T value)
|
|
|
|
|
{
|
|
|
|
|
var bytes = MessagePackSerializer.Serialize(value, Options);
|
|
|
|
|
MessagePackSerializer.Deserialize<T>(bytes, Options).Should().Be(value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|