save progress
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
using Xunit;
|
||||
|
||||
@@ -8,7 +9,7 @@ namespace StellaOps.Canonical.Json.Tests;
|
||||
public class CanonJsonTests
|
||||
{
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Canonicalize_SameInput_ProducesSameHash()
|
||||
{
|
||||
var obj = new { foo = "bar", baz = 42, nested = new { x = 1, y = 2 } };
|
||||
@@ -21,7 +22,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Canonicalize_SortsKeysAlphabetically()
|
||||
{
|
||||
var obj = new { z = 3, a = 1, m = 2 };
|
||||
@@ -32,7 +33,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Canonicalize_HandlesNestedObjects()
|
||||
{
|
||||
var obj = new { outer = new { z = 9, a = 1 }, inner = new { b = 2 } };
|
||||
@@ -44,7 +45,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Canonicalize_HandlesArrays()
|
||||
{
|
||||
var obj = new { items = new[] { 3, 1, 2 } };
|
||||
@@ -55,7 +56,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Canonicalize_HandlesNullValues()
|
||||
{
|
||||
var obj = new { name = "test", value = (string?)null };
|
||||
@@ -65,7 +66,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Canonicalize_HandlesBooleans()
|
||||
{
|
||||
var obj = new { enabled = true, disabled = false };
|
||||
@@ -76,7 +77,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Canonicalize_HandlesDecimals()
|
||||
{
|
||||
var obj = new { value = 3.14159, integer = 42 };
|
||||
@@ -87,7 +88,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Canonicalize_HandlesEmptyObject()
|
||||
{
|
||||
var obj = new { };
|
||||
@@ -97,7 +98,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Canonicalize_HandlesEmptyArray()
|
||||
{
|
||||
var obj = new { items = Array.Empty<int>() };
|
||||
@@ -107,7 +108,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Canonicalize_WithCustomOptions_UsesOptions()
|
||||
{
|
||||
var obj = new { MyProperty = "test" };
|
||||
@@ -121,7 +122,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Canonicalize_RawJsonBytes_SortsKeys()
|
||||
{
|
||||
var rawJson = Encoding.UTF8.GetBytes(@"{""z"":3,""a"":1}");
|
||||
@@ -132,7 +133,40 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Canonicalize_RawJsonBytes_InvalidJson_Throws()
|
||||
{
|
||||
var rawJson = Encoding.UTF8.GetBytes(@"{""a"":");
|
||||
|
||||
Assert.ThrowsAny<JsonException>(() => CanonJson.CanonicalizeParsedJson(rawJson));
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Canonicalize_RawJsonBytes_CustomEncoder_EscapesUnsafeChars()
|
||||
{
|
||||
var rawJson = Encoding.UTF8.GetBytes(@"{""value"":""<tag>""}");
|
||||
var canonical = CanonJson.CanonicalizeParsedJson(rawJson, JavaScriptEncoder.Default);
|
||||
var json = Encoding.UTF8.GetString(canonical);
|
||||
|
||||
Assert.DoesNotContain("<", json);
|
||||
Assert.DoesNotContain(">", json);
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Canonicalize_RawJsonBytes_HandlesScientificNotation()
|
||||
{
|
||||
var rawJson = Encoding.UTF8.GetBytes(@"{""value"":1e2,""small"":1e-6}");
|
||||
var canonical = CanonJson.CanonicalizeParsedJson(rawJson);
|
||||
|
||||
using var doc = JsonDocument.Parse(canonical);
|
||||
Assert.Equal(100d, doc.RootElement.GetProperty("value").GetDouble());
|
||||
Assert.Equal(0.000001d, doc.RootElement.GetProperty("small").GetDouble());
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Sha256Hex_ProducesLowercaseHex()
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes("test");
|
||||
@@ -142,7 +176,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Sha256Hex_ProducesConsistentHash()
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes("deterministic input");
|
||||
@@ -154,7 +188,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Sha256Prefixed_IncludesPrefix()
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes("test");
|
||||
@@ -165,7 +199,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Hash_CanonicalizesAndHashes()
|
||||
{
|
||||
var obj = new { z = 3, a = 1 };
|
||||
@@ -178,7 +212,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void HashPrefixed_CanonicalizesAndHashesWithPrefix()
|
||||
{
|
||||
var obj = new { name = "test" };
|
||||
@@ -189,7 +223,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void DifferentObjects_ProduceDifferentHashes()
|
||||
{
|
||||
var obj1 = new { value = 1 };
|
||||
@@ -202,7 +236,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void KeyOrderDoesNotAffectHash()
|
||||
{
|
||||
// These should produce the same hash because keys are sorted
|
||||
@@ -218,7 +252,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Canonicalize_DeeplyNestedStructure()
|
||||
{
|
||||
var obj = new
|
||||
@@ -240,7 +274,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Canonicalize_ArrayOfObjects_SortsObjectKeys()
|
||||
{
|
||||
// Use raw JSON to test mixed object shapes in array
|
||||
@@ -254,10 +288,10 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Canonicalize_UnicodeStrings()
|
||||
{
|
||||
var obj = new { greeting = "Привет мир", emoji = "🚀" };
|
||||
var obj = new { greeting = "\u041f\u0440\u0438\u0432\u0435\u0442 \u043c\u0438\u0440", emoji = "\U0001F680" };
|
||||
var bytes = CanonJson.Canonicalize(obj);
|
||||
|
||||
// Verify deterministic hashing regardless of Unicode escaping
|
||||
@@ -272,7 +306,7 @@ public class CanonJsonTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Canonicalize_SpecialCharactersInStrings()
|
||||
{
|
||||
var obj = new { path = "C:\\Users\\test", quote = "He said \"hello\"" };
|
||||
|
||||
@@ -15,14 +15,14 @@ public class CanonVersionTests
|
||||
#region Version Constants
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void V1_HasExpectedValue()
|
||||
{
|
||||
Assert.Equal("stella:canon:v1", CanonVersion.V1);
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void VersionFieldName_HasUnderscorePrefix()
|
||||
{
|
||||
Assert.Equal("_canonVersion", CanonVersion.VersionFieldName);
|
||||
@@ -30,7 +30,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Current_EqualsV1()
|
||||
{
|
||||
Assert.Equal(CanonVersion.V1, CanonVersion.Current);
|
||||
@@ -41,7 +41,7 @@ public class CanonVersionTests
|
||||
#region IsVersioned Detection
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void IsVersioned_VersionedJson_ReturnsTrue()
|
||||
{
|
||||
var json = """{"_canonVersion":"stella:canon:v1","foo":"bar"}"""u8;
|
||||
@@ -49,7 +49,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void IsVersioned_LegacyJson_ReturnsFalse()
|
||||
{
|
||||
var json = """{"foo":"bar"}"""u8;
|
||||
@@ -57,7 +57,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void IsVersioned_EmptyJson_ReturnsFalse()
|
||||
{
|
||||
var json = "{}"u8;
|
||||
@@ -65,7 +65,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void IsVersioned_TooShort_ReturnsFalse()
|
||||
{
|
||||
var json = """{"_ca":"v"}"""u8;
|
||||
@@ -73,7 +73,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void IsVersioned_WrongFieldName_ReturnsFalse()
|
||||
{
|
||||
var json = """{"_version":"stella:canon:v1","foo":"bar"}"""u8;
|
||||
@@ -85,7 +85,7 @@ public class CanonVersionTests
|
||||
#region ExtractVersion
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void ExtractVersion_VersionedJson_ReturnsVersion()
|
||||
{
|
||||
var json = """{"_canonVersion":"stella:canon:v1","foo":"bar"}"""u8;
|
||||
@@ -93,7 +93,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void ExtractVersion_CustomVersion_ReturnsVersion()
|
||||
{
|
||||
var json = """{"_canonVersion":"custom:v2","foo":"bar"}"""u8;
|
||||
@@ -101,7 +101,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void ExtractVersion_LegacyJson_ReturnsNull()
|
||||
{
|
||||
var json = """{"foo":"bar"}"""u8;
|
||||
@@ -109,7 +109,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void ExtractVersion_EmptyVersion_ReturnsNull()
|
||||
{
|
||||
var json = """{"_canonVersion":"","foo":"bar"}"""u8;
|
||||
@@ -121,7 +121,7 @@ public class CanonVersionTests
|
||||
#region CanonicalizeVersioned
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void CanonicalizeVersioned_IncludesVersionMarker()
|
||||
{
|
||||
var obj = new { foo = "bar" };
|
||||
@@ -133,7 +133,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void CanonicalizeVersioned_VersionMarkerIsFirst()
|
||||
{
|
||||
var obj = new { aaa = 1, zzz = 2 };
|
||||
@@ -147,7 +147,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void CanonicalizeVersioned_SortsOtherKeys()
|
||||
{
|
||||
var obj = new { z = 3, a = 1, m = 2 };
|
||||
@@ -159,7 +159,38 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void CanonicalizeVersioned_WithCustomOptions_UsesOptions()
|
||||
{
|
||||
var obj = new { MyProperty = "test" };
|
||||
var options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
|
||||
};
|
||||
|
||||
var canonical = CanonJson.CanonicalizeVersioned(obj, options);
|
||||
var json = Encoding.UTF8.GetString(canonical);
|
||||
|
||||
Assert.Contains(@"""my_property"":""test""", json);
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void CanonicalizeVersioned_SkipsExistingVersionField()
|
||||
{
|
||||
var jsonInput = """{"_canonVersion":"legacy","foo":"bar"}""";
|
||||
var element = JsonSerializer.Deserialize<JsonElement>(jsonInput);
|
||||
|
||||
var canonical = CanonJson.CanonicalizeVersioned(element, "stella:canon:v1");
|
||||
var json = Encoding.UTF8.GetString(canonical);
|
||||
|
||||
var matches = Regex.Matches(json, "_canonVersion");
|
||||
Assert.Single(matches);
|
||||
Assert.Contains(@"""_canonVersion"":""stella:canon:v1""", json);
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void CanonicalizeVersioned_CustomVersion_UsesProvidedVersion()
|
||||
{
|
||||
var obj = new { foo = "bar" };
|
||||
@@ -170,7 +201,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void CanonicalizeVersioned_NullVersion_ThrowsArgumentException()
|
||||
{
|
||||
var obj = new { foo = "bar" };
|
||||
@@ -178,7 +209,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void CanonicalizeVersioned_EmptyVersion_ThrowsArgumentException()
|
||||
{
|
||||
var obj = new { foo = "bar" };
|
||||
@@ -190,7 +221,7 @@ public class CanonVersionTests
|
||||
#region Hash Difference (Versioned vs Legacy)
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void HashVersioned_DiffersFromLegacyHash()
|
||||
{
|
||||
var obj = new { foo = "bar", count = 42 };
|
||||
@@ -202,7 +233,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void HashVersionedPrefixed_DiffersFromLegacyHashPrefixed()
|
||||
{
|
||||
var obj = new { foo = "bar", count = 42 };
|
||||
@@ -216,7 +247,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void HashVersioned_SameInput_ProducesSameHash()
|
||||
{
|
||||
var obj = new { foo = "bar", count = 42 };
|
||||
@@ -228,7 +259,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void HashVersioned_DifferentVersions_ProduceDifferentHashes()
|
||||
{
|
||||
var obj = new { foo = "bar" };
|
||||
@@ -244,7 +275,7 @@ public class CanonVersionTests
|
||||
#region Determinism
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void CanonicalizeVersioned_SameInput_ProducesSameBytes()
|
||||
{
|
||||
var obj = new { name = "test", value = 123, nested = new { x = 1, y = 2 } };
|
||||
@@ -256,7 +287,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void CanonicalizeVersioned_DifferentPropertyOrder_ProducesSameBytes()
|
||||
{
|
||||
// Create two objects with same properties but defined in different order
|
||||
@@ -273,7 +304,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void CanonicalizeVersioned_StableAcrossMultipleCalls()
|
||||
{
|
||||
var obj = new { id = Guid.Parse("12345678-1234-1234-1234-123456789012"), name = "stable" };
|
||||
@@ -291,7 +322,7 @@ public class CanonVersionTests
|
||||
#region Golden File / Snapshot Tests
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void CanonicalizeVersioned_KnownInput_ProducesKnownOutput()
|
||||
{
|
||||
// Golden test: exact output for known input to detect algorithm changes
|
||||
@@ -304,7 +335,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void HashVersioned_KnownInput_ProducesKnownHash()
|
||||
{
|
||||
// Golden test: exact hash for known input to detect algorithm changes
|
||||
@@ -323,7 +354,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void CanonicalizeVersioned_NestedObject_ProducesCorrectOutput()
|
||||
{
|
||||
var obj = new
|
||||
@@ -343,7 +374,7 @@ public class CanonVersionTests
|
||||
#region Backward Compatibility
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void CanVersion_CanDistinguishLegacyFromVersioned()
|
||||
{
|
||||
var obj = new { foo = "bar" };
|
||||
@@ -356,7 +387,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void LegacyCanonicalize_StillWorks()
|
||||
{
|
||||
// Ensure we haven't broken the legacy canonicalize method
|
||||
@@ -373,7 +404,7 @@ public class CanonVersionTests
|
||||
#region Edge Cases
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void CanonicalizeVersioned_EmptyObject_IncludesOnlyVersion()
|
||||
{
|
||||
var obj = new { };
|
||||
@@ -384,7 +415,7 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void CanonicalizeVersioned_WithSpecialCharacters_HandlesCorrectly()
|
||||
{
|
||||
var obj = new { message = "hello\nworld", special = "quote:\"test\"" };
|
||||
@@ -399,17 +430,16 @@ public class CanonVersionTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void CanonicalizeVersioned_WithUnicodeCharacters_HandlesCorrectly()
|
||||
{
|
||||
var obj = new { greeting = "こんにちは", emoji = "🚀" };
|
||||
var obj = new { greeting = "\u3053\u3093\u306b\u3061\u306f", emoji = "\U0001F680" };
|
||||
var canonical = CanonJson.CanonicalizeVersioned(obj);
|
||||
var json = Encoding.UTF8.GetString(canonical);
|
||||
|
||||
var parsed = JsonSerializer.Deserialize<JsonElement>(json);
|
||||
Assert.Equal("こんにちは", parsed.GetProperty("greeting").GetString());
|
||||
Assert.Equal("🚀", parsed.GetProperty("emoji").GetString());
|
||||
Assert.Equal("\u3053\u3093\u306b\u3061\u306f", parsed.GetProperty("greeting").GetString());
|
||||
Assert.Equal("\U0001F680", parsed.GetProperty("emoji").GetString());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -7,4 +7,4 @@ Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0131-M | DONE | Maintainability audit for StellaOps.Canonical.Json.Tests. |
|
||||
| AUDIT-0131-T | DONE | Test coverage audit for StellaOps.Canonical.Json.Tests. |
|
||||
| AUDIT-0131-A | TODO | Pending approval for changes. |
|
||||
| AUDIT-0131-A | DONE | Tests updated to cover CanonJson fixes for AUDIT-0130-A. |
|
||||
|
||||
Reference in New Issue
Block a user