Refactor code structure and optimize performance across multiple modules
This commit is contained in:
@@ -20,20 +20,23 @@ public class CecilMethodFingerprinterTests
|
||||
NullLogger<CecilMethodFingerprinter>.Instance);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Ecosystem_ReturnsNuget()
|
||||
{
|
||||
Assert.Equal("nuget", _fingerprinter.Ecosystem);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task FingerprintAsync_WithNullRequest_ThrowsArgumentNullException()
|
||||
{
|
||||
await Assert.ThrowsAsync<ArgumentNullException>(
|
||||
() => _fingerprinter.FingerprintAsync(null!));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task FingerprintAsync_WithNonExistentPath_ReturnsEmptyResult()
|
||||
{
|
||||
// Arrange
|
||||
@@ -53,7 +56,8 @@ public class CecilMethodFingerprinterTests
|
||||
Assert.Empty(result.Methods);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task FingerprintAsync_WithOwnAssembly_FindsMethods()
|
||||
{
|
||||
// Arrange - use the test assembly itself
|
||||
@@ -80,7 +84,8 @@ public class CecilMethodFingerprinterTests
|
||||
Assert.True(result.Methods.Count > 0, "Should find at least some methods");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task FingerprintAsync_ComputesDeterministicHashes()
|
||||
{
|
||||
// Arrange - fingerprint twice
|
||||
@@ -109,11 +114,13 @@ public class CecilMethodFingerprinterTests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task FingerprintAsync_WithCancellation_RespectsCancellation()
|
||||
{
|
||||
// Arrange
|
||||
using var cts = new CancellationTokenSource();
|
||||
using StellaOps.TestKit;
|
||||
cts.Cancel();
|
||||
|
||||
var testAssemblyPath = typeof(CecilMethodFingerprinterTests).Assembly.Location;
|
||||
@@ -142,7 +149,8 @@ public class CecilMethodFingerprinterTests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task FingerprintAsync_MethodKeyFormat_IsValid()
|
||||
{
|
||||
// Arrange
|
||||
@@ -172,7 +180,8 @@ public class CecilMethodFingerprinterTests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task FingerprintAsync_IncludesSignature()
|
||||
{
|
||||
// Arrange
|
||||
|
||||
@@ -8,11 +8,13 @@ using StellaOps.Scanner.VulnSurfaces.CallGraph;
|
||||
using StellaOps.Scanner.VulnSurfaces.Models;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Scanner.VulnSurfaces.Tests;
|
||||
|
||||
public class InternalCallGraphTests
|
||||
{
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void AddMethod_StoresMethod()
|
||||
{
|
||||
// Arrange
|
||||
@@ -38,7 +40,8 @@ public class InternalCallGraphTests
|
||||
Assert.Equal(1, graph.MethodCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void AddEdge_CreatesForwardAndReverseMapping()
|
||||
{
|
||||
// Arrange
|
||||
@@ -63,7 +66,8 @@ public class InternalCallGraphTests
|
||||
Assert.Equal(1, graph.EdgeCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void GetPublicMethods_ReturnsOnlyPublic()
|
||||
{
|
||||
// Arrange
|
||||
@@ -97,7 +101,8 @@ public class InternalCallGraphTests
|
||||
Assert.Equal("A::Public()", publicMethods[0].MethodKey);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void GetCallees_EmptyForUnknownMethod()
|
||||
{
|
||||
// Arrange
|
||||
@@ -114,7 +119,8 @@ public class InternalCallGraphTests
|
||||
Assert.Empty(callees);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void GetMethod_ReturnsNullForUnknown()
|
||||
{
|
||||
// Arrange
|
||||
|
||||
@@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging.Abstractions;
|
||||
using StellaOps.Scanner.VulnSurfaces.Fingerprint;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Scanner.VulnSurfaces.Tests;
|
||||
|
||||
public class MethodDiffEngineTests
|
||||
@@ -20,14 +21,16 @@ public class MethodDiffEngineTests
|
||||
NullLogger<MethodDiffEngine>.Instance);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task DiffAsync_WithNullRequest_ThrowsArgumentNullException()
|
||||
{
|
||||
await Assert.ThrowsAsync<ArgumentNullException>(
|
||||
() => _diffEngine.DiffAsync(null!));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task DiffAsync_WithIdenticalFingerprints_ReturnsNoChanges()
|
||||
{
|
||||
// Arrange
|
||||
@@ -68,7 +71,8 @@ public class MethodDiffEngineTests
|
||||
Assert.Equal(0, diff.TotalChanges);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task DiffAsync_WithModifiedMethod_ReturnsModified()
|
||||
{
|
||||
// Arrange
|
||||
@@ -112,7 +116,8 @@ public class MethodDiffEngineTests
|
||||
Assert.Empty(diff.Removed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task DiffAsync_WithAddedMethod_ReturnsAdded()
|
||||
{
|
||||
// Arrange
|
||||
@@ -155,7 +160,8 @@ public class MethodDiffEngineTests
|
||||
Assert.Empty(diff.Removed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task DiffAsync_WithRemovedMethod_ReturnsRemoved()
|
||||
{
|
||||
// Arrange
|
||||
@@ -198,7 +204,8 @@ public class MethodDiffEngineTests
|
||||
Assert.Equal("Test.Class::RemovedMethod", diff.Removed[0].MethodKey);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task DiffAsync_WithMultipleChanges_ReturnsAllChanges()
|
||||
{
|
||||
// Arrange - simulate a fix that modifies one method, adds one, removes one
|
||||
@@ -247,7 +254,8 @@ public class MethodDiffEngineTests
|
||||
Assert.Equal(3, diff.TotalChanges);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task DiffAsync_TriggerMethods_AreModifiedOrRemoved()
|
||||
{
|
||||
// This test validates the key insight:
|
||||
@@ -298,7 +306,8 @@ public class MethodDiffEngineTests
|
||||
Assert.Empty(diff.Removed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task DiffAsync_WithEmptyFingerprints_ReturnsNoChanges()
|
||||
{
|
||||
// Arrange
|
||||
|
||||
@@ -35,7 +35,8 @@ public class NuGetPackageDownloaderTests : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public void Ecosystem_ReturnsNuget()
|
||||
{
|
||||
// Arrange
|
||||
@@ -45,7 +46,8 @@ public class NuGetPackageDownloaderTests : IDisposable
|
||||
Assert.Equal("nuget", downloader.Ecosystem);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task DownloadAsync_WithNullRequest_ThrowsArgumentNullException()
|
||||
{
|
||||
// Arrange
|
||||
@@ -56,7 +58,8 @@ public class NuGetPackageDownloaderTests : IDisposable
|
||||
() => downloader.DownloadAsync(null!));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task DownloadAsync_WithHttpError_ReturnsFailResult()
|
||||
{
|
||||
// Arrange
|
||||
@@ -93,7 +96,8 @@ public class NuGetPackageDownloaderTests : IDisposable
|
||||
Assert.Null(result.ExtractedPath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task DownloadAsync_WithValidNupkg_ReturnsSuccessResult()
|
||||
{
|
||||
// Arrange - create a mock .nupkg (which is just a zip file)
|
||||
@@ -135,7 +139,8 @@ public class NuGetPackageDownloaderTests : IDisposable
|
||||
Assert.False(result.FromCache);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task DownloadAsync_WithCachedPackage_ReturnsCachedResult()
|
||||
{
|
||||
// Arrange - pre-create the cached directory
|
||||
@@ -162,7 +167,8 @@ public class NuGetPackageDownloaderTests : IDisposable
|
||||
Assert.Equal(packageDir, result.ExtractedPath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task DownloadAsync_WithCacheFalse_BypassesCache()
|
||||
{
|
||||
// Arrange - pre-create the cached directory
|
||||
@@ -210,7 +216,8 @@ public class NuGetPackageDownloaderTests : IDisposable
|
||||
ItExpr.IsAny<CancellationToken>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task DownloadAsync_UsesCorrectUrl()
|
||||
{
|
||||
// Arrange
|
||||
@@ -250,7 +257,8 @@ public class NuGetPackageDownloaderTests : IDisposable
|
||||
Assert.EndsWith(".nupkg", capturedRequest.RequestUri!.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task DownloadAsync_WithCustomRegistry_UsesCustomUrl()
|
||||
{
|
||||
// Arrange
|
||||
@@ -289,7 +297,8 @@ public class NuGetPackageDownloaderTests : IDisposable
|
||||
Assert.StartsWith("https://custom.nuget.feed.example.com/v3", capturedRequest.RequestUri!.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task DownloadAsync_WithCancellation_HonorsCancellation()
|
||||
{
|
||||
// Arrange
|
||||
@@ -344,6 +353,7 @@ public class NuGetPackageDownloaderTests : IDisposable
|
||||
// Add a minimal .nuspec file
|
||||
var nuspecEntry = archive.CreateEntry("test.nuspec");
|
||||
using var writer = new StreamWriter(nuspecEntry.Open());
|
||||
using StellaOps.TestKit;
|
||||
writer.Write("""
|
||||
<?xml version="1.0"?>
|
||||
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
|
||||
|
||||
@@ -10,6 +10,7 @@ using StellaOps.Scanner.VulnSurfaces.Models;
|
||||
using StellaOps.Scanner.VulnSurfaces.Triggers;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Scanner.VulnSurfaces.Tests;
|
||||
|
||||
public class TriggerMethodExtractorTests
|
||||
@@ -21,7 +22,8 @@ public class TriggerMethodExtractorTests
|
||||
_extractor = new TriggerMethodExtractor(NullLogger<TriggerMethodExtractor>.Instance);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ExtractAsync_DirectPath_FindsTrigger()
|
||||
{
|
||||
// Arrange
|
||||
@@ -85,7 +87,8 @@ public class TriggerMethodExtractorTests
|
||||
Assert.False(trigger.IsInterfaceExpansion);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ExtractAsync_NoPath_ReturnsEmpty()
|
||||
{
|
||||
// Arrange
|
||||
@@ -124,7 +127,8 @@ public class TriggerMethodExtractorTests
|
||||
Assert.Empty(result.Triggers);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ExtractAsync_MultiplePublicMethods_FindsAllTriggers()
|
||||
{
|
||||
// Arrange
|
||||
@@ -174,7 +178,8 @@ public class TriggerMethodExtractorTests
|
||||
Assert.Contains(result.Triggers, t => t.TriggerMethodKey == "Class::Api2()");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ExtractAsync_MaxDepthExceeded_DoesNotFindTrigger()
|
||||
{
|
||||
// Arrange
|
||||
@@ -231,7 +236,8 @@ public class TriggerMethodExtractorTests
|
||||
Assert.Empty(result.Triggers);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
public async Task ExtractAsync_VirtualMethod_ReducesConfidence()
|
||||
{
|
||||
// Arrange
|
||||
|
||||
@@ -4,10 +4,12 @@ using StellaOps.Scanner.VulnSurfaces.Services;
|
||||
using StellaOps.Scanner.VulnSurfaces.Storage;
|
||||
using Xunit;
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Scanner.VulnSurfaces.Tests;
|
||||
|
||||
public sealed class VulnSurfaceServiceTests
|
||||
{
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact(DisplayName = "GetAffectedSymbolsAsync returns sinks when surface exists")]
|
||||
public async Task GetAffectedSymbolsAsync_ReturnsSurfaceSinks()
|
||||
{
|
||||
@@ -50,6 +52,7 @@ public sealed class VulnSurfaceServiceTests
|
||||
Assert.Equal(surfaceGuid, repository.LastSurfaceId);
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact(DisplayName = "GetAffectedSymbolsAsync falls back to package symbol provider")]
|
||||
public async Task GetAffectedSymbolsAsync_FallsBackToPackageSymbols()
|
||||
{
|
||||
@@ -64,6 +67,7 @@ public sealed class VulnSurfaceServiceTests
|
||||
Assert.Single(result.Symbols);
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact(DisplayName = "GetAffectedSymbolsAsync returns heuristic when no data")]
|
||||
public async Task GetAffectedSymbolsAsync_ReturnsHeuristicWhenEmpty()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user