save progress
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
using FluentAssertions;
|
||||
using System.Collections;
|
||||
using FluentAssertions;
|
||||
using StellaOps.Canonicalization.Json;
|
||||
using StellaOps.Canonicalization.Ordering;
|
||||
using StellaOps.Canonicalization.Verification;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
@@ -9,7 +11,7 @@ namespace StellaOps.Canonicalization.Tests;
|
||||
public class CanonicalJsonSerializerTests
|
||||
{
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Serialize_Dictionary_OrdersKeysAlphabetically()
|
||||
{
|
||||
var dict = new Dictionary<string, int> { ["z"] = 1, ["a"] = 2, ["m"] = 3 };
|
||||
@@ -18,7 +20,25 @@ public class CanonicalJsonSerializerTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Serialize_Dictionary_NonStringKeys_UsesInvariantOrdering()
|
||||
{
|
||||
var dict = new Dictionary<int, string> { [2] = "a", [10] = "b" };
|
||||
var json = CanonicalJsonSerializer.Serialize(dict);
|
||||
json.Should().Be("{\"10\":\"b\",\"2\":\"a\"}");
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Serialize_Dictionary_NullKey_Throws()
|
||||
{
|
||||
var dict = new NullKeyDictionary();
|
||||
Action act = () => CanonicalJsonSerializer.Serialize(dict);
|
||||
act.Should().Throw<Exception>().WithMessage("*null*");
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Serialize_DateTimeOffset_UsesUtcIso8601()
|
||||
{
|
||||
var dt = new DateTimeOffset(2024, 1, 15, 10, 30, 0, TimeSpan.FromHours(5));
|
||||
@@ -28,7 +48,17 @@ public class CanonicalJsonSerializerTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void Deserialize_DateTimeOffset_AssumesUtcWhenOffsetMissing()
|
||||
{
|
||||
var json = "{\"timestamp\":\"2024-01-15T10:30:00\"}";
|
||||
var result = CanonicalJsonSerializer.Deserialize<TimeWrapper>(json);
|
||||
result.Timestamp.Offset.Should().Be(TimeSpan.Zero);
|
||||
result.Timestamp.UtcDateTime.Should().Be(new DateTime(2024, 1, 15, 10, 30, 0, DateTimeKind.Utc));
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Serialize_NullValues_AreOmitted()
|
||||
{
|
||||
var obj = new { Name = "test", Value = (string?)null };
|
||||
@@ -37,7 +67,7 @@ public class CanonicalJsonSerializerTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void SerializeWithDigest_ProducesConsistentDigest()
|
||||
{
|
||||
var obj = new { Name = "test", Value = 123 };
|
||||
@@ -45,12 +75,32 @@ public class CanonicalJsonSerializerTests
|
||||
var (_, digest2) = CanonicalJsonSerializer.SerializeWithDigest(obj);
|
||||
digest1.Should().Be(digest2);
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void DeterminismVerifier_Compare_ReturnsDifferences()
|
||||
{
|
||||
var verifier = new DeterminismVerifier();
|
||||
var result = verifier.Compare("{\"a\":1}", "{\"a\":2}");
|
||||
result.IsIdentical.Should().BeFalse();
|
||||
result.Differences.Should().ContainSingle(d => d.Contains("$.a", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void DeterminismVerifier_Compare_InvalidJson_ReturnsError()
|
||||
{
|
||||
var verifier = new DeterminismVerifier();
|
||||
var result = verifier.Compare("{\"a\":", "{\"a\":1}");
|
||||
result.IsIdentical.Should().BeFalse();
|
||||
result.Differences.Should().ContainSingle(d => d.StartsWith("inputA: invalid JSON", StringComparison.Ordinal));
|
||||
}
|
||||
}
|
||||
|
||||
public class PackageOrdererTests
|
||||
{
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void StableOrder_OrdersByPurlFirst()
|
||||
{
|
||||
var packages = new[]
|
||||
@@ -62,3 +112,43 @@ public class PackageOrdererTests
|
||||
ordered[0].purl.Should().Be("pkg:npm/a@1.0.0");
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TimeWrapper
|
||||
{
|
||||
public DateTimeOffset Timestamp { get; init; }
|
||||
}
|
||||
|
||||
internal sealed class NullKeyDictionary : IDictionary<string, int>
|
||||
{
|
||||
private readonly List<KeyValuePair<string, int>> _items =
|
||||
[
|
||||
new(null!, 1),
|
||||
new("b", 2)
|
||||
];
|
||||
|
||||
public IEnumerator<KeyValuePair<string, int>> GetEnumerator() => _items.GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public void Add(KeyValuePair<string, int> item) => throw new NotSupportedException();
|
||||
public void Clear() => throw new NotSupportedException();
|
||||
public bool Contains(KeyValuePair<string, int> item) => false;
|
||||
public void CopyTo(KeyValuePair<string, int>[] array, int arrayIndex) => throw new NotSupportedException();
|
||||
public bool Remove(KeyValuePair<string, int> item) => throw new NotSupportedException();
|
||||
public int Count => _items.Count;
|
||||
public bool IsReadOnly => true;
|
||||
public void Add(string key, int value) => throw new NotSupportedException();
|
||||
public bool ContainsKey(string key) => _items.Any(i => i.Key == key);
|
||||
public bool Remove(string key) => throw new NotSupportedException();
|
||||
public bool TryGetValue(string key, out int value)
|
||||
{
|
||||
var found = _items.FirstOrDefault(i => i.Key == key);
|
||||
value = found.Value;
|
||||
return found.Key is not null;
|
||||
}
|
||||
public int this[string key]
|
||||
{
|
||||
get => _items.First(i => i.Key == key).Value;
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
public ICollection<string> Keys => _items.Select(i => i.Key!).ToList();
|
||||
public ICollection<int> Values => _items.Select(i => i.Value).ToList();
|
||||
}
|
||||
|
||||
@@ -7,4 +7,4 @@ Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0133-M | DONE | Maintainability audit for StellaOps.Canonicalization.Tests. |
|
||||
| AUDIT-0133-T | DONE | Test coverage audit for StellaOps.Canonicalization.Tests. |
|
||||
| AUDIT-0133-A | TODO | Pending approval for changes. |
|
||||
| AUDIT-0133-A | DONE | Tests updated to cover canonicalization changes. |
|
||||
|
||||
12
src/__Libraries/__Tests/StellaOps.Plugin.Tests/AGENTS.md
Normal file
12
src/__Libraries/__Tests/StellaOps.Plugin.Tests/AGENTS.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# StellaOps.Plugin.Tests Agent Charter
|
||||
|
||||
## Mission
|
||||
Validate plugin platform behavior (loading, DI, security, compatibility).
|
||||
|
||||
## Required Reading
|
||||
- docs/modules/platform/architecture-overview.md
|
||||
- docs/dev/plugins/README.md
|
||||
|
||||
## Working Agreement
|
||||
- Update sprint status in docs/implplan/SPRINT_*.md and local TASKS.md.
|
||||
- Keep tests deterministic and avoid flaky filesystem or time dependencies.
|
||||
10
src/__Libraries/__Tests/StellaOps.Plugin.Tests/TASKS.md
Normal file
10
src/__Libraries/__Tests/StellaOps.Plugin.Tests/TASKS.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# StellaOps.Plugin.Tests Task Board
|
||||
|
||||
This board mirrors active sprint tasks for this module.
|
||||
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
|
||||
|
||||
| Task ID | Status | Notes |
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0437-M | DONE | Maintainability audit for StellaOps.Plugin.Tests. |
|
||||
| AUDIT-0437-T | DONE | Test coverage audit for StellaOps.Plugin.Tests. |
|
||||
| AUDIT-0437-A | DONE | APPLY waived (test project). |
|
||||
Reference in New Issue
Block a user