tests fixes and sprints work
This commit is contained in:
@@ -0,0 +1,285 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// AnalyticsCommandTests.cs
|
||||
// Sprint: SPRINT_20260120_032_Cli_sbom_analytics_cli
|
||||
// Description: Unit tests for analytics sbom-lake CLI commands.
|
||||
// -----------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.CommandLine;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Moq;
|
||||
using StellaOps.Cli.Commands;
|
||||
using StellaOps.Cli.Services;
|
||||
using StellaOps.Cli.Services.Models;
|
||||
using StellaOps.TestKit;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Cli.Tests.Commands;
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
public sealed class AnalyticsCommandTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task SuppliersJsonOutput_IncludesItems()
|
||||
{
|
||||
var client = new Mock<IBackendOperationsClient>();
|
||||
client
|
||||
.Setup(c => c.GetAnalyticsSuppliersAsync(
|
||||
It.IsAny<int?>(),
|
||||
It.IsAny<string?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(BuildSuppliersResponse());
|
||||
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton(client.Object)
|
||||
.BuildServiceProvider();
|
||||
var root = BuildRoot(services);
|
||||
|
||||
var writer = new StringWriter(CultureInfo.InvariantCulture);
|
||||
var originalOut = Console.Out;
|
||||
int exitCode;
|
||||
try
|
||||
{
|
||||
Console.SetOut(writer);
|
||||
exitCode = await root.Parse("analytics sbom-lake suppliers --format json").InvokeAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.SetOut(originalOut);
|
||||
}
|
||||
|
||||
Assert.Equal(0, exitCode);
|
||||
|
||||
using var doc = JsonDocument.Parse(writer.ToString());
|
||||
var items = doc.RootElement.GetProperty("items");
|
||||
Assert.Equal(2, items.GetArrayLength());
|
||||
Assert.Equal("Acme Co", items[0].GetProperty("supplier").GetString());
|
||||
Assert.Equal(2, doc.RootElement.GetProperty("count").GetInt32());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SuppliersCsvOutput_MatchesFixture()
|
||||
{
|
||||
var client = new Mock<IBackendOperationsClient>();
|
||||
client
|
||||
.Setup(c => c.GetAnalyticsSuppliersAsync(
|
||||
It.IsAny<int?>(),
|
||||
It.IsAny<string?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(BuildSuppliersResponse());
|
||||
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton(client.Object)
|
||||
.BuildServiceProvider();
|
||||
var root = BuildRoot(services);
|
||||
|
||||
var writer = new StringWriter(CultureInfo.InvariantCulture);
|
||||
var originalOut = Console.Out;
|
||||
int exitCode;
|
||||
try
|
||||
{
|
||||
Console.SetOut(writer);
|
||||
exitCode = await root.Parse("analytics sbom-lake suppliers --environment prod --format csv").InvokeAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.SetOut(originalOut);
|
||||
}
|
||||
|
||||
Assert.Equal(0, exitCode);
|
||||
|
||||
var expected = await File.ReadAllTextAsync(ResolveFixturePath("suppliers.csv"), CancellationToken.None);
|
||||
Assert.Equal(expected.TrimEnd(), writer.ToString().TrimEnd());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Suppliers_InvalidLimit_ReturnsError()
|
||||
{
|
||||
var services = new ServiceCollection().BuildServiceProvider();
|
||||
var root = BuildRoot(services);
|
||||
|
||||
var writer = new StringWriter(CultureInfo.InvariantCulture);
|
||||
var originalOut = Console.Out;
|
||||
int exitCode;
|
||||
try
|
||||
{
|
||||
Console.SetOut(writer);
|
||||
exitCode = await root.Parse("analytics sbom-lake suppliers --limit 0 --format json").InvokeAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.SetOut(originalOut);
|
||||
}
|
||||
|
||||
Assert.Equal(1, exitCode);
|
||||
|
||||
using var doc = JsonDocument.Parse(writer.ToString());
|
||||
Assert.Equal("error", doc.RootElement.GetProperty("status").GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TrendsCsvOutput_MatchesFixture()
|
||||
{
|
||||
var client = new Mock<IBackendOperationsClient>();
|
||||
client
|
||||
.Setup(c => c.GetAnalyticsVulnerabilityTrendsAsync(
|
||||
It.IsAny<string?>(),
|
||||
It.IsAny<int?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(BuildVulnerabilityTrendsResponse());
|
||||
client
|
||||
.Setup(c => c.GetAnalyticsComponentTrendsAsync(
|
||||
It.IsAny<string?>(),
|
||||
It.IsAny<int?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(BuildComponentTrendsResponse());
|
||||
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton(client.Object)
|
||||
.BuildServiceProvider();
|
||||
var root = BuildRoot(services);
|
||||
|
||||
var writer = new StringWriter(CultureInfo.InvariantCulture);
|
||||
var originalOut = Console.Out;
|
||||
int exitCode;
|
||||
try
|
||||
{
|
||||
Console.SetOut(writer);
|
||||
exitCode = await root.Parse("analytics sbom-lake trends --series all --days 14 --format csv").InvokeAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Console.SetOut(originalOut);
|
||||
}
|
||||
|
||||
Assert.Equal(0, exitCode);
|
||||
|
||||
var expected = await File.ReadAllTextAsync(ResolveFixturePath("trends_all.csv"), CancellationToken.None);
|
||||
Assert.Equal(expected.TrimEnd(), writer.ToString().TrimEnd());
|
||||
}
|
||||
|
||||
private static RootCommand BuildRoot(IServiceProvider services)
|
||||
{
|
||||
var root = new RootCommand();
|
||||
root.Add(AnalyticsCommandGroup.BuildAnalyticsCommand(
|
||||
services,
|
||||
new Option<bool>("--verbose", new[] { "-v" }),
|
||||
CancellationToken.None));
|
||||
return root;
|
||||
}
|
||||
|
||||
private static AnalyticsListResponse<AnalyticsSupplierConcentration> BuildSuppliersResponse()
|
||||
{
|
||||
var items = new[]
|
||||
{
|
||||
new AnalyticsSupplierConcentration(
|
||||
"Acme Co",
|
||||
15,
|
||||
12,
|
||||
3,
|
||||
2,
|
||||
5,
|
||||
new[] { "prod", "stage" }),
|
||||
new AnalyticsSupplierConcentration(
|
||||
"Omega Labs",
|
||||
5,
|
||||
3,
|
||||
1,
|
||||
0,
|
||||
1,
|
||||
new[] { "dev" })
|
||||
};
|
||||
|
||||
return new AnalyticsListResponse<AnalyticsSupplierConcentration>(
|
||||
"tenant-001",
|
||||
"actor-001",
|
||||
new DateTimeOffset(2026, 1, 20, 0, 0, 0, TimeSpan.Zero),
|
||||
true,
|
||||
300,
|
||||
items,
|
||||
items.Length);
|
||||
}
|
||||
|
||||
private static AnalyticsListResponse<AnalyticsVulnerabilityTrendPoint> BuildVulnerabilityTrendsResponse()
|
||||
{
|
||||
var items = new[]
|
||||
{
|
||||
new AnalyticsVulnerabilityTrendPoint(
|
||||
new DateTimeOffset(2026, 1, 18, 0, 0, 0, TimeSpan.Zero),
|
||||
"prod",
|
||||
42,
|
||||
10,
|
||||
5,
|
||||
27,
|
||||
2),
|
||||
new AnalyticsVulnerabilityTrendPoint(
|
||||
new DateTimeOffset(2026, 1, 19, 0, 0, 0, TimeSpan.Zero),
|
||||
"stage",
|
||||
35,
|
||||
7,
|
||||
4,
|
||||
24,
|
||||
1)
|
||||
};
|
||||
|
||||
return new AnalyticsListResponse<AnalyticsVulnerabilityTrendPoint>(
|
||||
"tenant-001",
|
||||
"actor-001",
|
||||
new DateTimeOffset(2026, 1, 20, 0, 0, 0, TimeSpan.Zero),
|
||||
false,
|
||||
0,
|
||||
items,
|
||||
items.Length);
|
||||
}
|
||||
|
||||
private static AnalyticsListResponse<AnalyticsComponentTrendPoint> BuildComponentTrendsResponse()
|
||||
{
|
||||
var items = new[]
|
||||
{
|
||||
new AnalyticsComponentTrendPoint(
|
||||
new DateTimeOffset(2026, 1, 18, 0, 0, 0, TimeSpan.Zero),
|
||||
"prod",
|
||||
1200,
|
||||
80),
|
||||
new AnalyticsComponentTrendPoint(
|
||||
new DateTimeOffset(2026, 1, 19, 0, 0, 0, TimeSpan.Zero),
|
||||
"stage",
|
||||
950,
|
||||
65)
|
||||
};
|
||||
|
||||
return new AnalyticsListResponse<AnalyticsComponentTrendPoint>(
|
||||
"tenant-001",
|
||||
"actor-001",
|
||||
new DateTimeOffset(2026, 1, 20, 0, 0, 0, TimeSpan.Zero),
|
||||
false,
|
||||
0,
|
||||
items,
|
||||
items.Length);
|
||||
}
|
||||
|
||||
private static string ResolveFixturePath(string fileName)
|
||||
{
|
||||
var relative = Path.Combine(
|
||||
"src",
|
||||
"Cli",
|
||||
"__Tests",
|
||||
"StellaOps.Cli.Tests",
|
||||
"Fixtures",
|
||||
"Analytics",
|
||||
fileName);
|
||||
var baseDirectory = new DirectoryInfo(AppContext.BaseDirectory);
|
||||
for (var directory = baseDirectory; directory is not null; directory = directory.Parent)
|
||||
{
|
||||
var candidate = Path.Combine(directory.FullName, relative);
|
||||
if (File.Exists(candidate))
|
||||
{
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return Path.Combine("Fixtures", "Analytics", fileName);
|
||||
}
|
||||
}
|
||||
@@ -108,4 +108,16 @@ public sealed class CommandFactoryTests
|
||||
var evidence = Assert.Single(root.Subcommands, command => string.Equals(command.Name, "evidence", StringComparison.Ordinal));
|
||||
Assert.Contains(evidence.Subcommands, command => string.Equals(command.Name, "store", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Create_ExposesAnalyticsCommands()
|
||||
{
|
||||
using var loggerFactory = LoggerFactory.Create(builder => builder.SetMinimumLevel(LogLevel.None));
|
||||
var services = new ServiceCollection().BuildServiceProvider();
|
||||
var root = CommandFactory.Create(services, new StellaOpsCliOptions(), CancellationToken.None, loggerFactory);
|
||||
|
||||
var analytics = Assert.Single(root.Subcommands, command => string.Equals(command.Name, "analytics", StringComparison.Ordinal));
|
||||
var sbomLake = Assert.Single(analytics.Subcommands, command => string.Equals(command.Name, "sbom-lake", StringComparison.Ordinal));
|
||||
Assert.Contains(sbomLake.Subcommands, command => string.Equals(command.Name, "suppliers", StringComparison.Ordinal));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Collections.ObjectModel;
|
||||
@@ -4925,6 +4925,39 @@ spec:
|
||||
|
||||
public Task<string?> GetScanSarifAsync(string scanId, bool includeHardening, bool includeReachability, string? minSeverity, CancellationToken cancellationToken)
|
||||
=> Task.FromResult<string?>(null);
|
||||
|
||||
public Task<AnalyticsListResponse<AnalyticsSupplierConcentration>> GetAnalyticsSuppliersAsync(int? limit, string? environment, CancellationToken cancellationToken)
|
||||
=> Task.FromResult(new AnalyticsListResponse<AnalyticsSupplierConcentration>(Array.Empty<AnalyticsSupplierConcentration>()));
|
||||
|
||||
public Task<AnalyticsListResponse<AnalyticsLicenseDistribution>> GetAnalyticsLicensesAsync(string? environment, CancellationToken cancellationToken)
|
||||
=> Task.FromResult(new AnalyticsListResponse<AnalyticsLicenseDistribution>(Array.Empty<AnalyticsLicenseDistribution>()));
|
||||
|
||||
public Task<AnalyticsListResponse<AnalyticsVulnerabilityExposure>> GetAnalyticsVulnerabilitiesAsync(string? environment, string? minSeverity, CancellationToken cancellationToken)
|
||||
=> Task.FromResult(new AnalyticsListResponse<AnalyticsVulnerabilityExposure>(Array.Empty<AnalyticsVulnerabilityExposure>()));
|
||||
|
||||
public Task<AnalyticsListResponse<AnalyticsFixableBacklogItem>> GetAnalyticsBacklogAsync(string? environment, CancellationToken cancellationToken)
|
||||
=> Task.FromResult(new AnalyticsListResponse<AnalyticsFixableBacklogItem>(Array.Empty<AnalyticsFixableBacklogItem>()));
|
||||
|
||||
public Task<AnalyticsListResponse<AnalyticsAttestationCoverage>> GetAnalyticsAttestationCoverageAsync(string? environment, CancellationToken cancellationToken)
|
||||
=> Task.FromResult(new AnalyticsListResponse<AnalyticsAttestationCoverage>(Array.Empty<AnalyticsAttestationCoverage>()));
|
||||
|
||||
public Task<AnalyticsListResponse<AnalyticsVulnerabilityTrendPoint>> GetAnalyticsVulnerabilityTrendsAsync(string? environment, int? days, CancellationToken cancellationToken)
|
||||
=> Task.FromResult(new AnalyticsListResponse<AnalyticsVulnerabilityTrendPoint>(Array.Empty<AnalyticsVulnerabilityTrendPoint>()));
|
||||
|
||||
public Task<AnalyticsListResponse<AnalyticsComponentTrendPoint>> GetAnalyticsComponentTrendsAsync(string? environment, int? days, CancellationToken cancellationToken)
|
||||
=> Task.FromResult(new AnalyticsListResponse<AnalyticsComponentTrendPoint>(Array.Empty<AnalyticsComponentTrendPoint>()));
|
||||
|
||||
public Task<WitnessListResponse> ListWitnessesAsync(WitnessListRequest request, CancellationToken cancellationToken)
|
||||
=> Task.FromResult(new WitnessListResponse());
|
||||
|
||||
public Task<WitnessDetailResponse?> GetWitnessAsync(string witnessId, CancellationToken cancellationToken)
|
||||
=> Task.FromResult<WitnessDetailResponse?>(null);
|
||||
|
||||
public Task<WitnessVerifyResponse> VerifyWitnessAsync(string witnessId, CancellationToken cancellationToken)
|
||||
=> Task.FromResult(new WitnessVerifyResponse());
|
||||
|
||||
public Task<Stream> DownloadWitnessAsync(string witnessId, WitnessExportFormat format, CancellationToken cancellationToken)
|
||||
=> Task.FromResult<Stream>(new MemoryStream(Encoding.UTF8.GetBytes("{}")));
|
||||
}
|
||||
|
||||
private sealed class StubExecutor : IScannerExecutor
|
||||
@@ -5145,3 +5178,4 @@ spec:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,338 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// GroundTruthCommandTests.cs
|
||||
// Sprint: SPRINT_20260121_035_BinaryIndex_golden_corpus_connectors_cli
|
||||
// Task: GCC-005 - CLI commands for ground-truth corpus management
|
||||
// Description: Unit tests for groundtruth CLI command parsing
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using System.CommandLine;
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StellaOps.Cli.Commands;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Cli.Tests.Commands;
|
||||
|
||||
public sealed class GroundTruthCommandTests
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly Option<bool> _verboseOption;
|
||||
private readonly CancellationToken _cancellationToken;
|
||||
private readonly Command _groundTruthCommand;
|
||||
|
||||
public GroundTruthCommandTests()
|
||||
{
|
||||
_services = new ServiceCollection().BuildServiceProvider();
|
||||
_verboseOption = new Option<bool>("--verbose", new[] { "-v" })
|
||||
{
|
||||
Description = "Enable verbose output"
|
||||
};
|
||||
_cancellationToken = CancellationToken.None;
|
||||
_groundTruthCommand = GroundTruthCommandGroup.BuildGroundTruthCommand(
|
||||
_services,
|
||||
_verboseOption,
|
||||
_cancellationToken);
|
||||
}
|
||||
|
||||
#region Command Structure Tests
|
||||
|
||||
[Fact]
|
||||
public void BuildGroundTruthCommand_CreatesCommandWithCorrectName()
|
||||
{
|
||||
// Assert
|
||||
_groundTruthCommand.Name.Should().Be("groundtruth");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildGroundTruthCommand_HasDescription()
|
||||
{
|
||||
// Assert
|
||||
_groundTruthCommand.Description.Should().NotBeNullOrEmpty();
|
||||
_groundTruthCommand.Description.Should().Contain("corpus");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildGroundTruthCommand_HasFourSubcommands()
|
||||
{
|
||||
// Assert
|
||||
_groundTruthCommand.Subcommands.Should().HaveCount(4);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildGroundTruthCommand_HasSourcesSubcommand()
|
||||
{
|
||||
// Act
|
||||
var sourcesCommand = _groundTruthCommand.Subcommands
|
||||
.FirstOrDefault(c => c.Name == "sources");
|
||||
|
||||
// Assert
|
||||
sourcesCommand.Should().NotBeNull();
|
||||
sourcesCommand!.Description.Should().Contain("source");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildGroundTruthCommand_HasSymbolsSubcommand()
|
||||
{
|
||||
// Act
|
||||
var symbolsCommand = _groundTruthCommand.Subcommands
|
||||
.FirstOrDefault(c => c.Name == "symbols");
|
||||
|
||||
// Assert
|
||||
symbolsCommand.Should().NotBeNull();
|
||||
symbolsCommand!.Description.Should().Contain("symbol");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildGroundTruthCommand_HasPairsSubcommand()
|
||||
{
|
||||
// Act
|
||||
var pairsCommand = _groundTruthCommand.Subcommands
|
||||
.FirstOrDefault(c => c.Name == "pairs");
|
||||
|
||||
// Assert
|
||||
pairsCommand.Should().NotBeNull();
|
||||
pairsCommand!.Description.Should().Contain("pair");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildGroundTruthCommand_HasValidateSubcommand()
|
||||
{
|
||||
// Act
|
||||
var validateCommand = _groundTruthCommand.Subcommands
|
||||
.FirstOrDefault(c => c.Name == "validate");
|
||||
|
||||
// Assert
|
||||
validateCommand.Should().NotBeNull();
|
||||
validateCommand!.Description.Should().Contain("validation");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Sources Subcommand Tests
|
||||
|
||||
[Fact]
|
||||
public void Sources_HasFourSubcommands()
|
||||
{
|
||||
// Act
|
||||
var sourcesCommand = _groundTruthCommand.Subcommands.First(c => c.Name == "sources");
|
||||
|
||||
// Assert
|
||||
sourcesCommand.Subcommands.Should().HaveCount(4);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Sources_HasListCommand()
|
||||
{
|
||||
// Act
|
||||
var sourcesCommand = _groundTruthCommand.Subcommands.First(c => c.Name == "sources");
|
||||
var listCommand = sourcesCommand.Subcommands.FirstOrDefault(c => c.Name == "list");
|
||||
|
||||
// Assert
|
||||
listCommand.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Sources_HasEnableCommand()
|
||||
{
|
||||
// Act
|
||||
var sourcesCommand = _groundTruthCommand.Subcommands.First(c => c.Name == "sources");
|
||||
var enableCommand = sourcesCommand.Subcommands.FirstOrDefault(c => c.Name == "enable");
|
||||
|
||||
// Assert
|
||||
enableCommand.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Sources_HasDisableCommand()
|
||||
{
|
||||
// Act
|
||||
var sourcesCommand = _groundTruthCommand.Subcommands.First(c => c.Name == "sources");
|
||||
var disableCommand = sourcesCommand.Subcommands.FirstOrDefault(c => c.Name == "disable");
|
||||
|
||||
// Assert
|
||||
disableCommand.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Sources_HasSyncCommand()
|
||||
{
|
||||
// Act
|
||||
var sourcesCommand = _groundTruthCommand.Subcommands.First(c => c.Name == "sources");
|
||||
var syncCommand = sourcesCommand.Subcommands.FirstOrDefault(c => c.Name == "sync");
|
||||
|
||||
// Assert
|
||||
syncCommand.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Sources_Enable_HasSourceArgument()
|
||||
{
|
||||
// Arrange
|
||||
var sourcesCommand = _groundTruthCommand.Subcommands.First(c => c.Name == "sources");
|
||||
var enableCommand = sourcesCommand.Subcommands.First(c => c.Name == "enable");
|
||||
|
||||
// Assert
|
||||
enableCommand.Arguments.Should().NotBeEmpty();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Symbols Subcommand Tests
|
||||
|
||||
[Fact]
|
||||
public void Symbols_HasTwoSubcommands()
|
||||
{
|
||||
// Act
|
||||
var symbolsCommand = _groundTruthCommand.Subcommands.First(c => c.Name == "symbols");
|
||||
|
||||
// Assert
|
||||
symbolsCommand.Subcommands.Should().HaveCount(2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Symbols_HasLookupCommand()
|
||||
{
|
||||
// Act
|
||||
var symbolsCommand = _groundTruthCommand.Subcommands.First(c => c.Name == "symbols");
|
||||
var lookupCommand = symbolsCommand.Subcommands.FirstOrDefault(c => c.Name == "lookup");
|
||||
|
||||
// Assert
|
||||
lookupCommand.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Symbols_HasSearchCommand()
|
||||
{
|
||||
// Act
|
||||
var symbolsCommand = _groundTruthCommand.Subcommands.First(c => c.Name == "symbols");
|
||||
var searchCommand = symbolsCommand.Subcommands.FirstOrDefault(c => c.Name == "search");
|
||||
|
||||
// Assert
|
||||
searchCommand.Should().NotBeNull();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Pairs Subcommand Tests
|
||||
|
||||
[Fact]
|
||||
public void Pairs_HasThreeSubcommands()
|
||||
{
|
||||
// Act
|
||||
var pairsCommand = _groundTruthCommand.Subcommands.First(c => c.Name == "pairs");
|
||||
|
||||
// Assert
|
||||
pairsCommand.Subcommands.Should().HaveCount(3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Pairs_HasCreateCommand()
|
||||
{
|
||||
// Act
|
||||
var pairsCommand = _groundTruthCommand.Subcommands.First(c => c.Name == "pairs");
|
||||
var createCommand = pairsCommand.Subcommands.FirstOrDefault(c => c.Name == "create");
|
||||
|
||||
// Assert
|
||||
createCommand.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Pairs_HasListCommand()
|
||||
{
|
||||
// Act
|
||||
var pairsCommand = _groundTruthCommand.Subcommands.First(c => c.Name == "pairs");
|
||||
var listCommand = pairsCommand.Subcommands.FirstOrDefault(c => c.Name == "list");
|
||||
|
||||
// Assert
|
||||
listCommand.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Pairs_HasDeleteCommand()
|
||||
{
|
||||
// Act
|
||||
var pairsCommand = _groundTruthCommand.Subcommands.First(c => c.Name == "pairs");
|
||||
var deleteCommand = pairsCommand.Subcommands.FirstOrDefault(c => c.Name == "delete");
|
||||
|
||||
// Assert
|
||||
deleteCommand.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Pairs_Delete_HasArgument()
|
||||
{
|
||||
// Arrange
|
||||
var pairsCommand = _groundTruthCommand.Subcommands.First(c => c.Name == "pairs");
|
||||
var deleteCommand = pairsCommand.Subcommands.First(c => c.Name == "delete");
|
||||
|
||||
// Assert
|
||||
deleteCommand.Arguments.Should().NotBeEmpty();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Validate Subcommand Tests
|
||||
|
||||
[Fact]
|
||||
public void Validate_HasThreeSubcommands()
|
||||
{
|
||||
// Act
|
||||
var validateCommand = _groundTruthCommand.Subcommands.First(c => c.Name == "validate");
|
||||
|
||||
// Assert
|
||||
validateCommand.Subcommands.Should().HaveCount(3);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_HasRunCommand()
|
||||
{
|
||||
// Act
|
||||
var validateCommand = _groundTruthCommand.Subcommands.First(c => c.Name == "validate");
|
||||
var runCommand = validateCommand.Subcommands.FirstOrDefault(c => c.Name == "run");
|
||||
|
||||
// Assert
|
||||
runCommand.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_HasMetricsCommand()
|
||||
{
|
||||
// Act
|
||||
var validateCommand = _groundTruthCommand.Subcommands.First(c => c.Name == "validate");
|
||||
var metricsCommand = validateCommand.Subcommands.FirstOrDefault(c => c.Name == "metrics");
|
||||
|
||||
// Assert
|
||||
metricsCommand.Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Validate_HasExportCommand()
|
||||
{
|
||||
// Act
|
||||
var validateCommand = _groundTruthCommand.Subcommands.First(c => c.Name == "validate");
|
||||
var exportCommand = validateCommand.Subcommands.FirstOrDefault(c => c.Name == "export");
|
||||
|
||||
// Assert
|
||||
exportCommand.Should().NotBeNull();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Output Format Tests
|
||||
|
||||
[Fact]
|
||||
public void OutputFormat_Enum_HasTableValue()
|
||||
{
|
||||
// Assert
|
||||
Enum.IsDefined(typeof(GroundTruthOutputFormat), "Table").Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OutputFormat_Enum_HasJsonValue()
|
||||
{
|
||||
// Assert
|
||||
Enum.IsDefined(typeof(GroundTruthOutputFormat), "Json").Should().BeTrue();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -59,7 +59,7 @@ public sealed class ProveCommandTests : IDisposable
|
||||
command.Description.Should().Contain("replay proof");
|
||||
}
|
||||
|
||||
[Fact(Skip = "System.CommandLine 2.0 API change - options lookup behavior changed")]
|
||||
[Fact]
|
||||
public void BuildProveCommand_HasRequiredImageOption()
|
||||
{
|
||||
// Arrange
|
||||
@@ -69,13 +69,13 @@ public sealed class ProveCommandTests : IDisposable
|
||||
// Act
|
||||
var command = ProveCommandGroup.BuildProveCommand(services, verboseOption, CancellationToken.None);
|
||||
|
||||
// Assert - search by alias since Name includes the dashes
|
||||
var imageOption = command.Options.FirstOrDefault(o => o.Aliases.Contains("--image"));
|
||||
imageOption.Should().NotBeNull();
|
||||
imageOption!.Required.Should().BeTrue();
|
||||
// Assert - check that image option exists (by name containing "image")
|
||||
var imageOption = command.Options.FirstOrDefault(o => o.Name.Contains("image", StringComparison.OrdinalIgnoreCase));
|
||||
imageOption.Should().NotBeNull("prove command should have an image option");
|
||||
imageOption!.Required.Should().BeTrue("image option should be required");
|
||||
}
|
||||
|
||||
[Fact(Skip = "System.CommandLine 2.0 API change - options lookup behavior changed")]
|
||||
[Fact]
|
||||
public void BuildProveCommand_HasOptionalAtOption()
|
||||
{
|
||||
// Arrange
|
||||
@@ -86,12 +86,12 @@ public sealed class ProveCommandTests : IDisposable
|
||||
var command = ProveCommandGroup.BuildProveCommand(services, verboseOption, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var atOption = command.Options.FirstOrDefault(o => o.Aliases.Contains("--at"));
|
||||
atOption.Should().NotBeNull();
|
||||
atOption!.Required.Should().BeFalse();
|
||||
var atOption = command.Options.FirstOrDefault(o => o.Name.Contains("at", StringComparison.OrdinalIgnoreCase) && o.Name.Length <= 4);
|
||||
atOption.Should().NotBeNull("prove command should have an at option");
|
||||
atOption!.Required.Should().BeFalse("at option should be optional");
|
||||
}
|
||||
|
||||
[Fact(Skip = "System.CommandLine 2.0 API change - options lookup behavior changed")]
|
||||
[Fact]
|
||||
public void BuildProveCommand_HasOptionalSnapshotOption()
|
||||
{
|
||||
// Arrange
|
||||
@@ -102,12 +102,12 @@ public sealed class ProveCommandTests : IDisposable
|
||||
var command = ProveCommandGroup.BuildProveCommand(services, verboseOption, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var snapshotOption = command.Options.FirstOrDefault(o => o.Aliases.Contains("--snapshot"));
|
||||
snapshotOption.Should().NotBeNull();
|
||||
snapshotOption!.Required.Should().BeFalse();
|
||||
var snapshotOption = command.Options.FirstOrDefault(o => o.Name.Contains("snapshot", StringComparison.OrdinalIgnoreCase));
|
||||
snapshotOption.Should().NotBeNull("prove command should have a snapshot option");
|
||||
snapshotOption!.Required.Should().BeFalse("snapshot option should be optional");
|
||||
}
|
||||
|
||||
[Fact(Skip = "System.CommandLine 2.0 API change - options lookup behavior changed")]
|
||||
[Fact]
|
||||
public void BuildProveCommand_HasOptionalBundleOption()
|
||||
{
|
||||
// Arrange
|
||||
@@ -118,12 +118,12 @@ public sealed class ProveCommandTests : IDisposable
|
||||
var command = ProveCommandGroup.BuildProveCommand(services, verboseOption, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var bundleOption = command.Options.FirstOrDefault(o => o.Aliases.Contains("--bundle"));
|
||||
bundleOption.Should().NotBeNull();
|
||||
bundleOption!.Required.Should().BeFalse();
|
||||
var bundleOption = command.Options.FirstOrDefault(o => o.Name.Contains("bundle", StringComparison.OrdinalIgnoreCase));
|
||||
bundleOption.Should().NotBeNull("prove command should have a bundle option");
|
||||
bundleOption!.Required.Should().BeFalse("bundle option should be optional");
|
||||
}
|
||||
|
||||
[Fact(Skip = "System.CommandLine 2.0 API change - options lookup behavior changed")]
|
||||
[Fact]
|
||||
public void BuildProveCommand_HasOutputOptionWithValidValues()
|
||||
{
|
||||
// Arrange
|
||||
@@ -134,8 +134,8 @@ public sealed class ProveCommandTests : IDisposable
|
||||
var command = ProveCommandGroup.BuildProveCommand(services, verboseOption, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var outputOption = command.Options.FirstOrDefault(o => o.Aliases.Contains("--output"));
|
||||
outputOption.Should().NotBeNull();
|
||||
var outputOption = command.Options.FirstOrDefault(o => o.Name.Contains("output", StringComparison.OrdinalIgnoreCase));
|
||||
outputOption.Should().NotBeNull("prove command should have an output option");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------------
|
||||
// ScanWorkersOptionTests.cs
|
||||
// Sprint: SPRINT_20260117_005_CLI_scanning_detection (SCD-005)
|
||||
// Description: Unit tests for scan run --workers option
|
||||
@@ -33,3 +33,4 @@ public sealed class ScanWorkersOptionTests
|
||||
Assert.Equal(4, result.GetValueForOption(workersOption!));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user