Refactor code structure and optimize performance across multiple modules

This commit is contained in:
StellaOps Bot
2025-12-26 20:03:22 +02:00
parent c786faae84
commit b4fc66feb6
3353 changed files with 88254 additions and 1590657 deletions

View File

@@ -2,11 +2,13 @@ using System.Text;
using System.Text.Json;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Canonical.Json.Tests;
public class CanonJsonTests
{
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Canonicalize_SameInput_ProducesSameHash()
{
var obj = new { foo = "bar", baz = 42, nested = new { x = 1, y = 2 } };
@@ -18,7 +20,8 @@ public class CanonJsonTests
Assert.Equal(CanonJson.Sha256Hex(bytes1), CanonJson.Sha256Hex(bytes2));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Canonicalize_SortsKeysAlphabetically()
{
var obj = new { z = 3, a = 1, m = 2 };
@@ -28,7 +31,8 @@ public class CanonJsonTests
Assert.Matches(@"\{""a"":1,""m"":2,""z"":3\}", json);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Canonicalize_HandlesNestedObjects()
{
var obj = new { outer = new { z = 9, a = 1 }, inner = new { b = 2 } };
@@ -39,7 +43,8 @@ public class CanonJsonTests
Assert.Contains(@"""outer"":{""a"":1,""z"":9}", json);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Canonicalize_HandlesArrays()
{
var obj = new { items = new[] { 3, 1, 2 } };
@@ -49,7 +54,8 @@ public class CanonJsonTests
Assert.Contains(@"""items"":[3,1,2]", json);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Canonicalize_HandlesNullValues()
{
var obj = new { name = "test", value = (string?)null };
@@ -58,7 +64,8 @@ public class CanonJsonTests
Assert.Contains(@"""value"":null", json);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Canonicalize_HandlesBooleans()
{
var obj = new { enabled = true, disabled = false };
@@ -68,7 +75,8 @@ public class CanonJsonTests
Assert.Contains(@"""enabled"":true", json);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Canonicalize_HandlesDecimals()
{
var obj = new { value = 3.14159, integer = 42 };
@@ -78,7 +86,8 @@ public class CanonJsonTests
Assert.Contains(@"""value"":3.14159", json);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Canonicalize_HandlesEmptyObject()
{
var obj = new { };
@@ -87,7 +96,8 @@ public class CanonJsonTests
Assert.Equal("{}", json);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Canonicalize_HandlesEmptyArray()
{
var obj = new { items = Array.Empty<int>() };
@@ -96,7 +106,8 @@ public class CanonJsonTests
Assert.Equal(@"{""items"":[]}", json);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Canonicalize_WithCustomOptions_UsesOptions()
{
var obj = new { MyProperty = "test" };
@@ -109,7 +120,8 @@ public class CanonJsonTests
Assert.Contains(@"""my_property"":""test""", json);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Canonicalize_RawJsonBytes_SortsKeys()
{
var rawJson = Encoding.UTF8.GetBytes(@"{""z"":3,""a"":1}");
@@ -119,7 +131,8 @@ public class CanonJsonTests
Assert.Equal(@"{""a"":1,""z"":3}", json);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Sha256Hex_ProducesLowercaseHex()
{
var bytes = Encoding.UTF8.GetBytes("test");
@@ -128,7 +141,8 @@ public class CanonJsonTests
Assert.Matches(@"^[0-9a-f]{64}$", hash);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Sha256Hex_ProducesConsistentHash()
{
var bytes = Encoding.UTF8.GetBytes("deterministic input");
@@ -139,7 +153,8 @@ public class CanonJsonTests
Assert.Equal(hash1, hash2);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Sha256Prefixed_IncludesPrefix()
{
var bytes = Encoding.UTF8.GetBytes("test");
@@ -149,7 +164,8 @@ public class CanonJsonTests
Assert.Equal(71, hash.Length); // "sha256:" (7) + 64 hex chars
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Hash_CanonicalizesAndHashes()
{
var obj = new { z = 3, a = 1 };
@@ -161,7 +177,8 @@ public class CanonJsonTests
Assert.Matches(@"^[0-9a-f]{64}$", hash1);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void HashPrefixed_CanonicalizesAndHashesWithPrefix()
{
var obj = new { name = "test" };
@@ -171,7 +188,8 @@ public class CanonJsonTests
Assert.StartsWith("sha256:", hash);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void DifferentObjects_ProduceDifferentHashes()
{
var obj1 = new { value = 1 };
@@ -183,7 +201,8 @@ public class CanonJsonTests
Assert.NotEqual(hash1, hash2);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void KeyOrderDoesNotAffectHash()
{
// These should produce the same hash because keys are sorted
@@ -198,7 +217,8 @@ public class CanonJsonTests
CanonJson.Sha256Hex(canonical2));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Canonicalize_DeeplyNestedStructure()
{
var obj = new
@@ -219,7 +239,8 @@ public class CanonJsonTests
Assert.Contains(@"""a"":{""nested"":{""a"":1,""b"":2}}", json);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Canonicalize_ArrayOfObjects_SortsObjectKeys()
{
// Use raw JSON to test mixed object shapes in array
@@ -232,7 +253,8 @@ public class CanonJsonTests
Assert.Contains(@"{""a"":1,""b"":2}", json);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Canonicalize_UnicodeStrings()
{
var obj = new { greeting = "Привет мир", emoji = "🚀" };
@@ -249,7 +271,8 @@ public class CanonJsonTests
Assert.Contains("emoji", json);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Canonicalize_SpecialCharactersInStrings()
{
var obj = new { path = "C:\\Users\\test", quote = "He said \"hello\"" };

View File

@@ -3,6 +3,7 @@ using System.Text.Json;
using System.Text.RegularExpressions;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.Canonical.Json.Tests;
/// <summary>
@@ -13,20 +14,23 @@ public class CanonVersionTests
{
#region Version Constants
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void V1_HasExpectedValue()
{
Assert.Equal("stella:canon:v1", CanonVersion.V1);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void VersionFieldName_HasUnderscorePrefix()
{
Assert.Equal("_canonVersion", CanonVersion.VersionFieldName);
Assert.StartsWith("_", CanonVersion.VersionFieldName);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void Current_EqualsV1()
{
Assert.Equal(CanonVersion.V1, CanonVersion.Current);
@@ -36,35 +40,40 @@ public class CanonVersionTests
#region IsVersioned Detection
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsVersioned_VersionedJson_ReturnsTrue()
{
var json = """{"_canonVersion":"stella:canon:v1","foo":"bar"}"""u8;
Assert.True(CanonVersion.IsVersioned(json));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsVersioned_LegacyJson_ReturnsFalse()
{
var json = """{"foo":"bar"}"""u8;
Assert.False(CanonVersion.IsVersioned(json));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsVersioned_EmptyJson_ReturnsFalse()
{
var json = "{}"u8;
Assert.False(CanonVersion.IsVersioned(json));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsVersioned_TooShort_ReturnsFalse()
{
var json = """{"_ca":"v"}"""u8;
Assert.False(CanonVersion.IsVersioned(json));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void IsVersioned_WrongFieldName_ReturnsFalse()
{
var json = """{"_version":"stella:canon:v1","foo":"bar"}"""u8;
@@ -75,28 +84,32 @@ public class CanonVersionTests
#region ExtractVersion
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ExtractVersion_VersionedJson_ReturnsVersion()
{
var json = """{"_canonVersion":"stella:canon:v1","foo":"bar"}"""u8;
Assert.Equal("stella:canon:v1", CanonVersion.ExtractVersion(json));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ExtractVersion_CustomVersion_ReturnsVersion()
{
var json = """{"_canonVersion":"custom:v2","foo":"bar"}"""u8;
Assert.Equal("custom:v2", CanonVersion.ExtractVersion(json));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ExtractVersion_LegacyJson_ReturnsNull()
{
var json = """{"foo":"bar"}"""u8;
Assert.Null(CanonVersion.ExtractVersion(json));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void ExtractVersion_EmptyVersion_ReturnsNull()
{
var json = """{"_canonVersion":"","foo":"bar"}"""u8;
@@ -107,7 +120,8 @@ public class CanonVersionTests
#region CanonicalizeVersioned
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CanonicalizeVersioned_IncludesVersionMarker()
{
var obj = new { foo = "bar" };
@@ -118,7 +132,8 @@ public class CanonVersionTests
Assert.Contains("\"foo\":\"bar\"", json);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CanonicalizeVersioned_VersionMarkerIsFirst()
{
var obj = new { aaa = 1, zzz = 2 };
@@ -131,7 +146,8 @@ public class CanonVersionTests
Assert.True(versionIndex < aaaIndex);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CanonicalizeVersioned_SortsOtherKeys()
{
var obj = new { z = 3, a = 1, m = 2 };
@@ -142,7 +158,8 @@ public class CanonVersionTests
Assert.Matches(@"\{""_canonVersion"":""[^""]+"",""a"":1,""m"":2,""z"":3\}", json);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CanonicalizeVersioned_CustomVersion_UsesProvidedVersion()
{
var obj = new { foo = "bar" };
@@ -152,14 +169,16 @@ public class CanonVersionTests
Assert.Contains("\"_canonVersion\":\"custom:v99\"", json);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CanonicalizeVersioned_NullVersion_ThrowsArgumentException()
{
var obj = new { foo = "bar" };
Assert.ThrowsAny<ArgumentException>(() => CanonJson.CanonicalizeVersioned(obj, null!));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CanonicalizeVersioned_EmptyVersion_ThrowsArgumentException()
{
var obj = new { foo = "bar" };
@@ -170,7 +189,8 @@ public class CanonVersionTests
#region Hash Difference (Versioned vs Legacy)
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void HashVersioned_DiffersFromLegacyHash()
{
var obj = new { foo = "bar", count = 42 };
@@ -181,7 +201,8 @@ public class CanonVersionTests
Assert.NotEqual(legacyHash, versionedHash);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void HashVersionedPrefixed_DiffersFromLegacyHashPrefixed()
{
var obj = new { foo = "bar", count = 42 };
@@ -194,7 +215,8 @@ public class CanonVersionTests
Assert.StartsWith("sha256:", legacyHash);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void HashVersioned_SameInput_ProducesSameHash()
{
var obj = new { foo = "bar", count = 42 };
@@ -205,7 +227,8 @@ public class CanonVersionTests
Assert.Equal(hash1, hash2);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void HashVersioned_DifferentVersions_ProduceDifferentHashes()
{
var obj = new { foo = "bar" };
@@ -220,7 +243,8 @@ public class CanonVersionTests
#region Determinism
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CanonicalizeVersioned_SameInput_ProducesSameBytes()
{
var obj = new { name = "test", value = 123, nested = new { x = 1, y = 2 } };
@@ -231,7 +255,8 @@ public class CanonVersionTests
Assert.Equal(bytes1, bytes2);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CanonicalizeVersioned_DifferentPropertyOrder_ProducesSameBytes()
{
// Create two objects with same properties but defined in different order
@@ -247,7 +272,8 @@ public class CanonVersionTests
Assert.Equal(bytes1, bytes2);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CanonicalizeVersioned_StableAcrossMultipleCalls()
{
var obj = new { id = Guid.Parse("12345678-1234-1234-1234-123456789012"), name = "stable" };
@@ -264,7 +290,8 @@ public class CanonVersionTests
#region Golden File / Snapshot Tests
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CanonicalizeVersioned_KnownInput_ProducesKnownOutput()
{
// Golden test: exact output for known input to detect algorithm changes
@@ -276,7 +303,8 @@ public class CanonVersionTests
Assert.Equal("""{"_canonVersion":"stella:canon:v1","message":"hello","number":42}""", json);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void HashVersioned_KnownInput_ProducesKnownHash()
{
// Golden test: exact hash for known input to detect algorithm changes
@@ -294,7 +322,8 @@ public class CanonVersionTests
Assert.Equal(hash, hash2);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CanonicalizeVersioned_NestedObject_ProducesCorrectOutput()
{
var obj = new
@@ -313,7 +342,8 @@ public class CanonVersionTests
#region Backward Compatibility
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CanVersion_CanDistinguishLegacyFromVersioned()
{
var obj = new { foo = "bar" };
@@ -325,7 +355,8 @@ public class CanonVersionTests
Assert.True(CanonVersion.IsVersioned(versioned));
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void LegacyCanonicalize_StillWorks()
{
// Ensure we haven't broken the legacy canonicalize method
@@ -341,7 +372,8 @@ public class CanonVersionTests
#region Edge Cases
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CanonicalizeVersioned_EmptyObject_IncludesOnlyVersion()
{
var obj = new { };
@@ -351,7 +383,8 @@ public class CanonVersionTests
Assert.Equal("""{"_canonVersion":"stella:canon:v1"}""", json);
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CanonicalizeVersioned_WithSpecialCharacters_HandlesCorrectly()
{
var obj = new { message = "hello\nworld", special = "quote:\"test\"" };
@@ -365,7 +398,8 @@ public class CanonVersionTests
Assert.Equal("stella:canon:v1", parsed.GetProperty("_canonVersion").GetString());
}
[Fact]
[Trait("Category", TestCategories.Unit)]
[Fact]
public void CanonicalizeVersioned_WithUnicodeCharacters_HandlesCorrectly()
{
var obj = new { greeting = "こんにちは", emoji = "🚀" };

View File

@@ -21,5 +21,6 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\StellaOps.Canonical.Json\StellaOps.Canonical.Json.csproj" />
<ProjectReference Include="../StellaOps.TestKit/StellaOps.TestKit.csproj" />
</ItemGroup>
</Project>