using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.Json; using System.Text.Json.Nodes; using FluentAssertions; using StellaOps.Graph.Indexer.Ingestion.Policy; using Xunit; using Xunit.Abstractions; namespace StellaOps.Graph.Indexer.Tests; public sealed class PolicyOverlayTransformerTests { private readonly ITestOutputHelper _output; public PolicyOverlayTransformerTests(ITestOutputHelper output) { _output = output; } private static readonly string FixturesRoot = Path.Combine(AppContext.BaseDirectory, "Fixtures", "v1"); private static readonly HashSet ExpectedNodeKinds = new(StringComparer.Ordinal) { "policy_version" }; private static readonly HashSet ExpectedEdgeKinds = new(StringComparer.Ordinal) { "GOVERNS_WITH" }; [Fact] public void Transform_projects_policy_nodes_and_governs_with_edges() { var snapshot = LoadSnapshot("policy-overlay.json"); var transformer = new PolicyOverlayTransformer(); var batch = transformer.Transform(snapshot); var expectedNodes = LoadArray("nodes.json") .Cast() .Where(node => ExpectedNodeKinds.Contains(node["kind"]!.GetValue())) .OrderBy(node => node["id"]!.GetValue(), StringComparer.Ordinal) .ToArray(); var expectedEdges = LoadArray("edges.json") .Cast() .Where(edge => ExpectedEdgeKinds.Contains(edge["kind"]!.GetValue())) .OrderBy(edge => edge["id"]!.GetValue(), StringComparer.Ordinal) .ToArray(); var actualNodes = batch.Nodes .Where(node => ExpectedNodeKinds.Contains(node["kind"]!.GetValue())) .OrderBy(node => node["id"]!.GetValue(), StringComparer.Ordinal) .ToArray(); var actualEdges = batch.Edges .Where(edge => ExpectedEdgeKinds.Contains(edge["kind"]!.GetValue())) .OrderBy(edge => edge["id"]!.GetValue(), StringComparer.Ordinal) .ToArray(); actualNodes.Length.Should().Be(expectedNodes.Length); actualEdges.Length.Should().Be(expectedEdges.Length); for (var i = 0; i < expectedNodes.Length; i++) { if (!JsonNode.DeepEquals(expectedNodes[i], actualNodes[i])) { _output.WriteLine($"Expected Node: {expectedNodes[i]}"); _output.WriteLine($"Actual Node: {actualNodes[i]}"); } JsonNode.DeepEquals(expectedNodes[i], actualNodes[i]).Should().BeTrue(); } for (var i = 0; i < expectedEdges.Length; i++) { if (!JsonNode.DeepEquals(expectedEdges[i], actualEdges[i])) { _output.WriteLine($"Expected Edge: {expectedEdges[i]}"); _output.WriteLine($"Actual Edge: {actualEdges[i]}"); } JsonNode.DeepEquals(expectedEdges[i], actualEdges[i]).Should().BeTrue(); } } private static PolicyOverlaySnapshot LoadSnapshot(string fileName) { var path = Path.Combine(FixturesRoot, fileName); var json = File.ReadAllText(path); return JsonSerializer.Deserialize(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true })!; } private static JsonArray LoadArray(string fileName) { var path = Path.Combine(FixturesRoot, fileName); return (JsonArray)JsonNode.Parse(File.ReadAllText(path))!; } }