Refactor code structure for improved readability and maintainability; optimize performance in key functions.
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
using FluentAssertions;
|
||||
using StellaOps.Canonicalization.Json;
|
||||
using StellaOps.Canonicalization.Ordering;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Canonicalization.Tests;
|
||||
|
||||
public class CanonicalJsonSerializerTests
|
||||
{
|
||||
[Fact]
|
||||
public void Serialize_Dictionary_OrdersKeysAlphabetically()
|
||||
{
|
||||
var dict = new Dictionary<string, int> { ["z"] = 1, ["a"] = 2, ["m"] = 3 };
|
||||
var json = CanonicalJsonSerializer.Serialize(dict);
|
||||
json.Should().Be("{\"a\":2,\"m\":3,\"z\":1}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serialize_DateTimeOffset_UsesUtcIso8601()
|
||||
{
|
||||
var dt = new DateTimeOffset(2024, 1, 15, 10, 30, 0, TimeSpan.FromHours(5));
|
||||
var obj = new { Timestamp = dt };
|
||||
var json = CanonicalJsonSerializer.Serialize(obj);
|
||||
json.Should().Contain("2024-01-15T05:30:00.000Z");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Serialize_NullValues_AreOmitted()
|
||||
{
|
||||
var obj = new { Name = "test", Value = (string?)null };
|
||||
var json = CanonicalJsonSerializer.Serialize(obj);
|
||||
json.Should().NotContain("value");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SerializeWithDigest_ProducesConsistentDigest()
|
||||
{
|
||||
var obj = new { Name = "test", Value = 123 };
|
||||
var (_, digest1) = CanonicalJsonSerializer.SerializeWithDigest(obj);
|
||||
var (_, digest2) = CanonicalJsonSerializer.SerializeWithDigest(obj);
|
||||
digest1.Should().Be(digest2);
|
||||
}
|
||||
}
|
||||
|
||||
public class PackageOrdererTests
|
||||
{
|
||||
[Fact]
|
||||
public void StableOrder_OrdersByPurlFirst()
|
||||
{
|
||||
var packages = new[]
|
||||
{
|
||||
(purl: "pkg:npm/b@1.0.0", name: "b", version: "1.0.0"),
|
||||
(purl: "pkg:npm/a@1.0.0", name: "a", version: "1.0.0")
|
||||
};
|
||||
var ordered = packages.StableOrder(p => p.purl, p => p.name, p => p.version, _ => null).ToList();
|
||||
ordered[0].purl.Should().Be("pkg:npm/a@1.0.0");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using FsCheck;
|
||||
using FsCheck.Xunit;
|
||||
using StellaOps.Canonicalization.Json;
|
||||
using StellaOps.Canonicalization.Ordering;
|
||||
|
||||
namespace StellaOps.Canonicalization.Tests.Properties;
|
||||
|
||||
public class CanonicalJsonProperties
|
||||
{
|
||||
[Property]
|
||||
public Property Serialize_IsIdempotent(Dictionary<string, int> dict)
|
||||
{
|
||||
var json1 = CanonicalJsonSerializer.Serialize(dict);
|
||||
var json2 = CanonicalJsonSerializer.Serialize(dict);
|
||||
return (json1 == json2).ToProperty();
|
||||
}
|
||||
|
||||
[Property]
|
||||
public Property Serialize_OrderIndependent(Dictionary<string, int> dict)
|
||||
{
|
||||
var reversed = dict.Reverse().ToDictionary(x => x.Key, x => x.Value);
|
||||
var json1 = CanonicalJsonSerializer.Serialize(dict);
|
||||
var json2 = CanonicalJsonSerializer.Serialize(reversed);
|
||||
return (json1 == json2).ToProperty();
|
||||
}
|
||||
|
||||
[Property]
|
||||
public Property Digest_IsDeterministic(string input)
|
||||
{
|
||||
var obj = new { Value = input ?? string.Empty };
|
||||
var (_, digest1) = CanonicalJsonSerializer.SerializeWithDigest(obj);
|
||||
var (_, digest2) = CanonicalJsonSerializer.SerializeWithDigest(obj);
|
||||
return (digest1 == digest2).ToProperty();
|
||||
}
|
||||
}
|
||||
|
||||
public class OrderingProperties
|
||||
{
|
||||
[Property]
|
||||
public Property PackageOrdering_IsStable(List<(string purl, string name, string version)> packages)
|
||||
{
|
||||
var ordered1 = packages.StableOrder(p => p.purl, p => p.name, p => p.version, _ => null).ToList();
|
||||
var ordered2 = packages.StableOrder(p => p.purl, p => p.name, p => p.version, _ => null).ToList();
|
||||
return ordered1.SequenceEqual(ordered2).ToProperty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FsCheck.Xunit" Version="2.16.6" />
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.7">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\StellaOps.Canonicalization\StellaOps.Canonicalization.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user