Files
recordingtest/tests/Recordingtest.Normalizer.Tests/CoverageTests.cs
minsung 05c7a3f388 Fix normalizer sidecar log and coverage test (#4)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 14:17:22 +09:00

102 lines
3.9 KiB
C#

using System.Text.Json;
using Xunit;
using Recordingtest.Normalizer;
namespace Recordingtest.Normalizer.Tests;
/// <summary>
/// Verifies that every "SuspectedNondeterministicFields" entry in
/// docs/sut-catalog/json-configs.json is covered by a semantically appropriate
/// rule that is actually present in the default profile.
/// </summary>
public class CoverageTests
{
// Explicit field -> rule mapping. Each entry must be a rule that semantically
// covers the kind of value the field holds.
// *Path / *FileName / *RecentFile* -> normalize_paths
// Known volatile boolean / color / scalar settings -> mask_volatile_settings
// No catch-all to sort_json_keys for arbitrary scalars.
private static readonly Dictionary<string, string> FieldRuleMap = new(StringComparer.Ordinal)
{
// path-bearing
["AutoSaveFilePath"] = "normalize_paths",
["AutoSave_RecentFileName"] = "normalize_paths",
// volatile boolean / scalar UI settings
["CanOverrideWireColorWithFace"] = "mask_volatile_settings",
["IsSidePanelVisible"] = "mask_volatile_settings",
["OverrideFaceColor"] = "mask_volatile_settings",
["Solar_IsLocalTime"] = "mask_volatile_settings",
["VisibleGrid"] = "mask_volatile_settings",
["GridSnap"] = "mask_volatile_settings",
["MidpointOsnap"] = "mask_volatile_settings",
["GridSpacing"] = "mask_volatile_settings",
// volatile color channels
["GridColor.ALPHA"] = "mask_volatile_settings",
["GridColor.BLUE"] = "mask_volatile_settings",
["GridColor.GREEN"] = "mask_volatile_settings",
["GridColor.RED"] = "mask_volatile_settings",
["MajorGridColor.ALPHA"] = "mask_volatile_settings",
["MajorGridColor.BLUE"] = "mask_volatile_settings",
["MajorGridColor.GREEN"] = "mask_volatile_settings",
["MajorGridColor.RED"] = "mask_volatile_settings",
};
private static string FindCatalog()
{
var dir = AppContext.BaseDirectory;
for (int i = 0; i < 10 && dir is not null; i++)
{
var candidate = Path.Combine(dir, "docs", "sut-catalog", "json-configs.json");
if (File.Exists(candidate)) return candidate;
dir = Directory.GetParent(dir)?.FullName;
}
throw new FileNotFoundException("json-configs.json not found by walking up from " + AppContext.BaseDirectory);
}
[Fact]
public void DefaultProfile_CoversAllSuspectedFields()
{
var path = FindCatalog();
using var doc = JsonDocument.Parse(File.ReadAllText(path));
var allFields = new HashSet<string>(StringComparer.Ordinal);
foreach (var entry in doc.RootElement.EnumerateArray())
{
if (entry.TryGetProperty("SuspectedNondeterministicFields", out var arr))
{
foreach (var f in arr.EnumerateArray())
{
var s = f.GetString();
if (!string.IsNullOrEmpty(s)) allFields.Add(s);
}
}
}
Assert.NotEmpty(allFields);
var profile = Profile.Load("default");
var profileRules = new HashSet<string>(profile.Rules, StringComparer.Ordinal);
var unmapped = new List<string>();
var notInProfile = new List<string>();
foreach (var field in allFields)
{
if (!FieldRuleMap.TryGetValue(field, out var rule))
{
unmapped.Add(field);
continue;
}
if (!profileRules.Contains(rule))
{
notInProfile.Add($"{field} -> {rule}");
}
}
Assert.True(unmapped.Count == 0,
"Suspected fields without an explicit semantic rule mapping: " + string.Join(", ", unmapped));
Assert.True(notInProfile.Count == 0,
"Mapped rules missing from default profile: " + string.Join(", ", notInProfile));
}
}