using Microsoft.Extensions.Logging.Abstractions; using StellaOps.Scanner.Reachability; using StellaOps.Scanner.Reachability.Gates; using GateDetectors = StellaOps.Scanner.Reachability.Gates.Detectors; using Xunit; namespace StellaOps.Scanner.Reachability.Tests; public sealed class RichGraphGateAnnotatorTests { [Fact] public async Task AnnotateAsync_AddsAuthGateAndMultiplier() { var union = new ReachabilityUnionGraph( Nodes: new[] { new ReachabilityUnionNode("sym:dotnet:A", "dotnet", "method", "A"), new ReachabilityUnionNode( "sym:dotnet:B", "dotnet", "method", "B", Attributes: new Dictionary { ["annotations"] = "[Authorize]" }) }, Edges: new[] { new ReachabilityUnionEdge("sym:dotnet:A", "sym:dotnet:B", "call", "high") }); var graph = RichGraphBuilder.FromUnion(union, "test-analyzer", "1.0.0"); var annotator = new RichGraphGateAnnotator( detectors: new GateDetectors.IGateDetector[] { new GateDetectors.AuthGateDetector() }, codeProvider: new NullCodeContentProvider(), multiplierCalculator: new GateMultiplierCalculator(), logger: NullLogger.Instance); var annotated = await annotator.AnnotateAsync(graph); Assert.Single(annotated.Edges); var edge = annotated.Edges[0]; Assert.NotNull(edge.Gates); Assert.Single(edge.Gates); Assert.Equal(GateType.AuthRequired, edge.Gates[0].Type); Assert.Equal(3000, edge.GateMultiplierBps); } private sealed class NullCodeContentProvider : GateDetectors.ICodeContentProvider { public Task GetContentAsync(string filePath, CancellationToken ct = default) => Task.FromResult(null); public Task?> GetLinesAsync(string filePath, int startLine, int endLine, CancellationToken ct = default) => Task.FromResult?>(null); } }