feat: engine-state normalizer profile + sort_array_elements rule (#10)
- Rules.SortArrayElements: sort JSON arrays lexicographically (post-mask_guids order-independence) - Normalizer output: UnsafeRelaxedJsonEscaping to preserve <GUID>/<TS>/<VOLATILE> tokens - profiles/engine-state.yaml: normalize_paths + mask_guids + sort_array_elements + round_floats(2dp) + sort_json_keys - RunnerOptions.SidecarProfile: default "engine-state", overridable via --sidecar-profile - TestRunner.CaptureAndDiffSidecar: uses SidecarProfile instead of main Profile - 4 new normalizer tests (136 total) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -208,4 +208,56 @@ public class RuleTests
|
||||
if (Directory.Exists(dir)) Directory.Delete(dir, true);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- sort_array_elements tests -----------------------------------------
|
||||
|
||||
[Fact]
|
||||
public void SortArrayElements_SortsTopLevelArray()
|
||||
{
|
||||
var node = JsonNode.Parse("[\"banana\",\"apple\",\"cherry\"]");
|
||||
var (n, c) = Rules.SortArrayElements(node);
|
||||
Assert.Equal(1, c);
|
||||
var arr = n!.AsArray();
|
||||
Assert.Equal("apple", arr[0]!.GetValue<string>());
|
||||
Assert.Equal("banana", arr[1]!.GetValue<string>());
|
||||
Assert.Equal("cherry", arr[2]!.GetValue<string>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SortArrayElements_NestedArray_SortedIndependently()
|
||||
{
|
||||
var node = JsonNode.Parse("{\"ids\":[\"c\",\"a\",\"b\"]}");
|
||||
var (n, c) = Rules.SortArrayElements(node);
|
||||
Assert.Equal(1, c);
|
||||
var ids = n!["ids"]!.AsArray();
|
||||
Assert.Equal("a", ids[0]!.GetValue<string>());
|
||||
Assert.Equal("b", ids[1]!.GetValue<string>());
|
||||
Assert.Equal("c", ids[2]!.GetValue<string>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SortArrayElements_AfterGuidMask_OrderIndependent()
|
||||
{
|
||||
// Simulate: selected_ids with two different GUIDs in different orders
|
||||
const string json1 = "{\"selection\":{\"selected_ids\":[\"aaa\",\"bbb\"]}}";
|
||||
const string json2 = "{\"selection\":{\"selected_ids\":[\"bbb\",\"aaa\"]}}";
|
||||
var (n1, _) = Rules.SortArrayElements(JsonNode.Parse(json1));
|
||||
var (n2, _) = Rules.SortArrayElements(JsonNode.Parse(json2));
|
||||
Assert.Equal(
|
||||
n1!["selection"]!["selected_ids"]!.ToJsonString(),
|
||||
n2!["selection"]!["selected_ids"]!.ToJsonString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Normalize_EngineStateProfile_AppliesAllRules()
|
||||
{
|
||||
// engine-state profile: normalize_paths, mask_guids, sort_array_elements, round_floats, sort_json_keys
|
||||
var guid = "12345678-1234-1234-1234-123456789012";
|
||||
var json = $"{{\"selection\":{{\"selected_ids\":[\"{guid}\"]}},\"camera\":{{\"fov\":45.123456789}}}}";
|
||||
var result = Normalizer.Normalize(json, "engine-state").Output;
|
||||
Assert.Contains("<GUID>", result);
|
||||
Assert.DoesNotContain(guid, result);
|
||||
// fov should be rounded to 2 decimal places
|
||||
Assert.Contains("45.12", result);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user