This commit is contained in:
StellaOps Bot
2026-01-07 21:30:44 +02:00
1359 changed files with 61692 additions and 11378 deletions

View File

@@ -0,0 +1,241 @@
// -----------------------------------------------------------------------------
// DriftCommandTests.cs
// Sprint: SPRINT_20260105_002_004_CLI (CLI-010)
// Description: Unit tests for facet drift analysis CLI command.
// -----------------------------------------------------------------------------
using System.CommandLine;
using Moq;
using Xunit;
using StellaOps.Cli.Commands;
namespace StellaOps.Cli.Tests.Commands;
/// <summary>
/// Unit tests for the drift command structure.
/// </summary>
[Trait("Category", "Unit")]
public sealed class DriftCommandTests
{
[Fact]
public void DriftCommand_HasCorrectName()
{
// Arrange & Act
var command = BuildDriftCommand();
// Assert
Assert.Equal("drift", command.Name);
}
[Fact]
public void DriftCommand_HasCorrectDescription()
{
// Arrange & Act
var command = BuildDriftCommand();
// Assert
Assert.Contains("drift", command.Description);
Assert.Contains("baseline", command.Description);
}
[Fact]
public void DriftCommand_HasImageArgument()
{
// Arrange
var command = BuildDriftCommand();
// Act
var imageArg = command.Arguments.FirstOrDefault(a => a.Name == "image");
// Assert
Assert.NotNull(imageArg);
// Arguments are required by default in System.CommandLine
}
[Fact]
public void DriftCommand_HasBaselineOption()
{
// Arrange
var command = BuildDriftCommand();
// Act
var baselineOpt = command.Options.FirstOrDefault(o =>
o.Name == "baseline" || o.Name == "--baseline" || o.Aliases.Contains("--baseline"));
// Assert
Assert.NotNull(baselineOpt);
Assert.True(baselineOpt.Aliases.Contains("-b") || baselineOpt.Aliases.Contains("--baseline"));
Assert.Contains("Baseline seal", baselineOpt.Description);
}
[Fact]
public void DriftCommand_HasFormatOption()
{
// Arrange
var command = BuildDriftCommand();
// Act
var formatOpt = command.Options.FirstOrDefault(o =>
o.Name == "format" || o.Name == "--format" || o.Aliases.Contains("--format"));
// Assert
Assert.NotNull(formatOpt);
Assert.Contains("table", formatOpt.Description);
Assert.Contains("json", formatOpt.Description);
Assert.Contains("yaml", formatOpt.Description);
}
[Fact]
public void DriftCommand_HasVerboseFilesOption()
{
// Arrange
var command = BuildDriftCommand();
// Act
var verboseFilesOpt = command.Options.FirstOrDefault(o =>
o.Name == "verbose-files" || o.Name == "--verbose-files" || o.Aliases.Contains("--verbose-files"));
// Assert
Assert.NotNull(verboseFilesOpt);
Assert.Contains("file changes", verboseFilesOpt.Description);
}
[Fact]
public void DriftCommand_HasFailOnBreachOption()
{
// Arrange
var command = BuildDriftCommand();
// Act
var failOnBreachOpt = command.Options.FirstOrDefault(o =>
o.Name == "fail-on-breach" || o.Name == "--fail-on-breach" || o.Aliases.Contains("--fail-on-breach"));
// Assert
Assert.NotNull(failOnBreachOpt);
Assert.Contains("error code", failOnBreachOpt.Description);
}
[Fact]
public void DriftCommand_HasOutputOption()
{
// Arrange
var command = BuildDriftCommand();
// Act
var outputOpt = command.Options.FirstOrDefault(o =>
o.Name == "output" || o.Name == "--output" || o.Aliases.Contains("--output"));
// Assert
Assert.NotNull(outputOpt);
Assert.True(outputOpt.Aliases.Contains("-o") || outputOpt.Aliases.Contains("--output"));
}
[Fact]
public void DriftCommand_HasVerboseOption()
{
// Arrange
var command = BuildDriftCommand();
// Act
var verboseOpt = command.Options.FirstOrDefault(o =>
o.Name == "verbose" || o.Name == "--verbose" || o.Aliases.Contains("--verbose"));
// Assert
Assert.NotNull(verboseOpt);
}
[Fact]
public void DriftCommand_AllOptionsAreConfigured()
{
// Arrange
var command = BuildDriftCommand();
var expectedOptions = new[]
{
"baseline", "format", "verbose-files", "fail-on-breach", "output", "verbose"
};
// Act - normalize all option names by stripping leading dashes
var actualOptionNames = command.Options
.SelectMany(o => new[] { o.Name.TrimStart('-') }.Concat(o.Aliases.Select(a => a.TrimStart('-'))))
.ToHashSet(StringComparer.OrdinalIgnoreCase);
var actualArgs = command.Arguments.Select(a => a.Name).ToHashSet();
// Assert - image is now an argument, not an option
Assert.Contains("image", actualArgs);
foreach (var expected in expectedOptions)
{
Assert.Contains(expected, actualOptionNames);
}
}
[Fact]
public void DriftCommand_ImageArgument_HasCorrectDescription()
{
// Arrange
var command = BuildDriftCommand();
var imageArg = command.Arguments.First(a => a.Name == "image");
// Assert
Assert.Contains("Image", imageArg.Description);
}
[Fact]
public void DriftCommand_BaselineOption_HasCorrectAliases()
{
// Arrange
var command = BuildDriftCommand();
var baselineOpt = command.Options.First(o =>
o.Name == "baseline" || o.Name == "--baseline" || o.Aliases.Contains("--baseline"));
// Assert
Assert.True(baselineOpt.Aliases.Contains("--baseline") || baselineOpt.Aliases.Contains("-b"));
}
[Fact]
public void DriftCommand_OutputOption_HasCorrectAliases()
{
// Arrange
var command = BuildDriftCommand();
var outputOpt = command.Options.First(o =>
o.Name == "output" || o.Name == "--output" || o.Aliases.Contains("--output"));
// Assert
Assert.True(outputOpt.Aliases.Contains("--output") || outputOpt.Aliases.Contains("-o"));
}
[Fact]
public void DriftCommand_FormatOption_SupportsAllFormats()
{
// Arrange
var command = BuildDriftCommand();
var formatOpt = command.Options.First(o =>
o.Name == "format" || o.Name == "--format" || o.Aliases.Contains("--format"));
// Assert - verify description mentions all supported formats
Assert.Contains("table", formatOpt.Description);
Assert.Contains("json", formatOpt.Description);
Assert.Contains("yaml", formatOpt.Description);
}
[Fact]
public void DriftCommand_FailOnBreachOption_ExplainsBehavior()
{
// Arrange
var command = BuildDriftCommand();
var failOnBreachOpt = command.Options.First(o =>
o.Name == "fail-on-breach" || o.Name == "--fail-on-breach" || o.Aliases.Contains("--fail-on-breach"));
// Assert
Assert.Contains("quota", failOnBreachOpt.Description);
}
private static Command BuildDriftCommand()
{
var mockServices = new Mock<IServiceProvider>();
var verboseOption = new Option<bool>("--verbose");
return DriftCommandGroup.BuildDriftCommand(
mockServices.Object,
verboseOption,
CancellationToken.None);
}
}

View File

@@ -0,0 +1,236 @@
// -----------------------------------------------------------------------------
// EvidenceCommandTests.cs
// Sprint: SPRINT_20260106_003_003_EVIDENCE_export_bundle
// Task: T028
// Description: Unit tests for evidence bundle CLI commands.
// -----------------------------------------------------------------------------
using System.CommandLine;
using Xunit;
namespace StellaOps.Cli.Tests.Commands;
/// <summary>
/// Unit tests for evidence CLI commands.
/// </summary>
public sealed class EvidenceCommandTests
{
[Fact]
public void EvidenceCommand_HasExportSubcommand()
{
// Arrange
var command = BuildEvidenceCommand();
// Act
var exportCmd = command.Subcommands.FirstOrDefault(c => c.Name == "export");
// Assert
Assert.NotNull(exportCmd);
Assert.Equal("Export an evidence bundle to a tar.gz archive", exportCmd.Description);
}
[Fact]
public void EvidenceCommand_HasVerifySubcommand()
{
// Arrange
var command = BuildEvidenceCommand();
// Act
var verifyCmd = command.Subcommands.FirstOrDefault(c => c.Name == "verify");
// Assert
Assert.NotNull(verifyCmd);
Assert.Equal("Verify an exported evidence bundle", verifyCmd.Description);
}
[Fact]
public void EvidenceCommand_HasStatusSubcommand()
{
// Arrange
var command = BuildEvidenceCommand();
// Act
var statusCmd = command.Subcommands.FirstOrDefault(c => c.Name == "status");
// Assert
Assert.NotNull(statusCmd);
}
[Fact]
public void ExportCommand_HasBundleIdArgument()
{
// Arrange
var command = BuildEvidenceCommand();
var exportCmd = command.Subcommands.First(c => c.Name == "export");
// Act
var bundleArg = exportCmd.Arguments.FirstOrDefault(a => a.Name == "bundle-id");
// Assert
Assert.NotNull(bundleArg);
}
[Fact]
public void ExportCommand_HasOutputOption()
{
// Arrange
var command = BuildEvidenceCommand();
var exportCmd = command.Subcommands.First(c => c.Name == "export");
// Act
var outputOpt = exportCmd.Options.FirstOrDefault(o => o.Aliases.Contains("--output") || o.Aliases.Contains("-o"));
// Assert
Assert.NotNull(outputOpt);
Assert.Contains("-o", outputOpt.Aliases);
}
[Fact]
public void ExportCommand_HasIncludeLayersOption()
{
// Arrange
var command = BuildEvidenceCommand();
var exportCmd = command.Subcommands.First(c => c.Name == "export");
// Act
var includeLayersOpt = exportCmd.Options.FirstOrDefault(o => o.Name == "--include-layers" || o.Name == "include-layers" || o.Aliases.Contains("--include-layers"));
// Assert
Assert.NotNull(includeLayersOpt);
}
[Fact]
public void ExportCommand_HasCompressionOption()
{
// Arrange
var command = BuildEvidenceCommand();
var exportCmd = command.Subcommands.First(c => c.Name == "export");
// Act
var compressionOpt = exportCmd.Options.FirstOrDefault(o => o.Aliases.Contains("--compression") || o.Aliases.Contains("-c"));
// Assert
Assert.NotNull(compressionOpt);
}
[Fact]
public void VerifyCommand_HasPathArgument()
{
// Arrange
var command = BuildEvidenceCommand();
var verifyCmd = command.Subcommands.First(c => c.Name == "verify");
// Act
var pathArg = verifyCmd.Arguments.FirstOrDefault(a => a.Name == "path");
// Assert
Assert.NotNull(pathArg);
}
[Fact]
public void VerifyCommand_HasOfflineOption()
{
// Arrange
var command = BuildEvidenceCommand();
var verifyCmd = command.Subcommands.First(c => c.Name == "verify");
// Act
var offlineOpt = verifyCmd.Options.FirstOrDefault(o => o.Name == "--offline" || o.Name == "offline" || o.Aliases.Contains("--offline"));
// Assert
Assert.NotNull(offlineOpt);
}
[Fact]
public void VerifyCommand_HasVerboseOption()
{
// Arrange
var command = BuildEvidenceCommand();
var verifyCmd = command.Subcommands.First(c => c.Name == "verify");
// Act
var verboseOpt = verifyCmd.Options.FirstOrDefault(o => o.Aliases.Contains("--verbose") || o.Aliases.Contains("-v"));
// Assert
Assert.NotNull(verboseOpt);
Assert.Contains("-v", verboseOpt.Aliases);
}
[Fact]
public void StatusCommand_HasExportIdArgument()
{
// Arrange
var command = BuildEvidenceCommand();
var statusCmd = command.Subcommands.First(c => c.Name == "status");
// Act
var exportIdArg = statusCmd.Arguments.FirstOrDefault(a => a.Name == "export-id");
// Assert
Assert.NotNull(exportIdArg);
}
[Fact]
public void ExportCommand_HasIncludeRekorProofsOption()
{
// Arrange
var command = BuildEvidenceCommand();
var exportCmd = command.Subcommands.First(c => c.Name == "export");
// Act
var rekorOpt = exportCmd.Options.FirstOrDefault(o => o.Name == "--include-rekor-proofs" || o.Name == "include-rekor-proofs" || o.Aliases.Contains("--include-rekor-proofs"));
// Assert
Assert.NotNull(rekorOpt);
}
private static Command BuildEvidenceCommand()
{
// Build evidence command group
var bundleIdArg = new Argument<string>("bundle-id") { Description = "Bundle ID to export" };
// Create options with explicit aliases array for better compatibility
var outputOption = new Option<string>("--output", "-o") { Description = "Output file path" };
var includeLayersOption = new Option<bool>("--include-layers") { Description = "Include per-layer SBOMs" };
var includeRekorOption = new Option<bool>("--include-rekor-proofs") { Description = "Include Rekor transparency proofs" };
var compressionOption = new Option<int>("--compression", "-c") { Description = "Compression level (1-9)" };
var exportCmd = new Command("export", "Export an evidence bundle to a tar.gz archive")
{
bundleIdArg,
outputOption,
includeLayersOption,
includeRekorOption,
compressionOption
};
var pathArg = new Argument<string>("path") { Description = "Path to the bundle archive" };
var offlineOption = new Option<bool>("--offline") { Description = "Skip Rekor verification" };
var verboseOption = new Option<bool>("--verbose", "-v") { Description = "Verbose output" };
var verifyCmd = new Command("verify", "Verify an exported evidence bundle")
{
pathArg,
offlineOption,
verboseOption
};
var exportIdArg = new Argument<string>("export-id") { Description = "Export job ID to check" };
var statusCmd = new Command("status", "Check export job status")
{
exportIdArg
};
var evidenceCmd = new Command("evidence", "Evidence bundle management commands")
{
exportCmd,
verifyCmd,
statusCmd
};
return evidenceCmd;
}
}

View File

@@ -0,0 +1,238 @@
// -----------------------------------------------------------------------------
// SealCommandTests.cs
// Sprint: SPRINT_20260105_002_004_CLI (CLI-006)
// Description: Unit tests for facet seal CLI command.
// -----------------------------------------------------------------------------
using System.CommandLine;
using Moq;
using Xunit;
using StellaOps.Cli.Commands;
namespace StellaOps.Cli.Tests.Commands;
/// <summary>
/// Unit tests for the seal command structure.
/// </summary>
[Trait("Category", "Unit")]
public sealed class SealCommandTests
{
[Fact]
public void SealCommand_HasCorrectName()
{
// Arrange & Act
var command = BuildSealCommand();
// Assert
Assert.Equal("seal", command.Name);
}
[Fact]
public void SealCommand_HasCorrectDescription()
{
// Arrange & Act
var command = BuildSealCommand();
// Assert
Assert.Contains("facet seal", command.Description);
Assert.Contains("drift detection", command.Description);
}
[Fact]
public void SealCommand_HasImageArgument()
{
// Arrange
var command = BuildSealCommand();
// Act
var imageArg = command.Arguments.FirstOrDefault(a => a.Name == "image");
// Assert
Assert.NotNull(imageArg);
// Arguments are required by default in System.CommandLine
}
[Fact]
public void SealCommand_HasOutputOption()
{
// Arrange
var command = BuildSealCommand();
// Act
var outputOpt = command.Options.FirstOrDefault(o =>
o.Name == "output" || o.Name == "--output" || o.Aliases.Contains("--output"));
// Assert
Assert.NotNull(outputOpt);
Assert.True(outputOpt.Aliases.Contains("-o") || outputOpt.Aliases.Contains("--output"));
}
[Fact]
public void SealCommand_HasStoreOption()
{
// Arrange
var command = BuildSealCommand();
// Act
var storeOpt = command.Options.FirstOrDefault(o =>
o.Name == "store" || o.Name == "--store" || o.Aliases.Contains("--store"));
// Assert
Assert.NotNull(storeOpt);
Assert.Contains("Store seal", storeOpt.Description);
}
[Fact]
public void SealCommand_HasSignOption()
{
// Arrange
var command = BuildSealCommand();
// Act
var signOpt = command.Options.FirstOrDefault(o =>
o.Name == "sign" || o.Name == "--sign" || o.Aliases.Contains("--sign"));
// Assert
Assert.NotNull(signOpt);
Assert.Contains("Sign", signOpt.Description);
}
[Fact]
public void SealCommand_HasKeyOption()
{
// Arrange
var command = BuildSealCommand();
// Act
var keyOpt = command.Options.FirstOrDefault(o =>
o.Name == "key" || o.Name == "--key" || o.Aliases.Contains("--key"));
// Assert
Assert.NotNull(keyOpt);
Assert.True(keyOpt.Aliases.Contains("-k") || keyOpt.Aliases.Contains("--key"));
Assert.Contains("Private key", keyOpt.Description);
}
[Fact]
public void SealCommand_HasFacetsOption()
{
// Arrange
var command = BuildSealCommand();
// Act
var facetsOpt = command.Options.FirstOrDefault(o =>
o.Name == "facets" || o.Name == "--facets" || o.Aliases.Contains("--facets"));
// Assert
Assert.NotNull(facetsOpt);
Assert.True(facetsOpt.Aliases.Contains("-f") || facetsOpt.Aliases.Contains("--facets"));
}
[Fact]
public void SealCommand_HasFormatOption()
{
// Arrange
var command = BuildSealCommand();
// Act
var formatOpt = command.Options.FirstOrDefault(o =>
o.Name == "format" || o.Name == "--format" || o.Aliases.Contains("--format"));
// Assert
Assert.NotNull(formatOpt);
Assert.Contains("json", formatOpt.Description);
Assert.Contains("yaml", formatOpt.Description);
}
[Fact]
public void SealCommand_HasVerboseOption()
{
// Arrange
var command = BuildSealCommand();
// Act
var verboseOpt = command.Options.FirstOrDefault(o =>
o.Name == "verbose" || o.Name == "--verbose" || o.Aliases.Contains("--verbose"));
// Assert
Assert.NotNull(verboseOpt);
}
[Fact]
public void SealCommand_AllOptionsAreConfigured()
{
// Arrange
var command = BuildSealCommand();
var expectedOptions = new[] { "output", "store", "sign", "key", "facets", "format", "verbose" };
// Act - normalize all option names by stripping leading dashes
var actualOptionNames = command.Options
.SelectMany(o => new[] { o.Name.TrimStart('-') }.Concat(o.Aliases.Select(a => a.TrimStart('-'))))
.ToHashSet(StringComparer.OrdinalIgnoreCase);
var actualArgs = command.Arguments.Select(a => a.Name).ToHashSet();
// Assert - image is an argument
Assert.Contains("image", actualArgs);
foreach (var expected in expectedOptions)
{
Assert.Contains(expected, actualOptionNames);
}
}
[Fact]
public void SealCommand_ImageArgument_HasCorrectDescription()
{
// Arrange
var command = BuildSealCommand();
var imageArg = command.Arguments.First(a => a.Name == "image");
// Assert
Assert.Contains("Image", imageArg.Description);
}
[Fact]
public void SealCommand_OutputOption_HasCorrectAliases()
{
// Arrange
var command = BuildSealCommand();
var outputOpt = command.Options.First(o =>
o.Name == "output" || o.Name == "--output" || o.Aliases.Contains("--output"));
// Assert
Assert.True(outputOpt.Aliases.Contains("--output") || outputOpt.Aliases.Contains("-o"));
}
[Fact]
public void SealCommand_KeyOption_HasCorrectAliases()
{
// Arrange
var command = BuildSealCommand();
var keyOpt = command.Options.First(o =>
o.Name == "key" || o.Name == "--key" || o.Aliases.Contains("--key"));
// Assert
Assert.True(keyOpt.Aliases.Contains("--key") || keyOpt.Aliases.Contains("-k"));
}
[Fact]
public void SealCommand_FacetsOption_HasCorrectAliases()
{
// Arrange
var command = BuildSealCommand();
var facetsOpt = command.Options.First(o =>
o.Name == "facets" || o.Name == "--facets" || o.Aliases.Contains("--facets"));
// Assert
Assert.True(facetsOpt.Aliases.Contains("--facets") || facetsOpt.Aliases.Contains("-f"));
}
private static Command BuildSealCommand()
{
var mockServices = new Mock<IServiceProvider>();
var verboseOption = new Option<bool>("--verbose");
return SealCommandGroup.BuildSealCommand(
mockServices.Object,
verboseOption,
CancellationToken.None);
}
}

View File

@@ -0,0 +1,216 @@
// -----------------------------------------------------------------------------
// VexGenCommandTests.cs
// Sprint: SPRINT_20260105_002_004_CLI (CLI-014)
// Description: Unit tests for VEX generation CLI command.
// -----------------------------------------------------------------------------
using System.CommandLine;
using Moq;
using Xunit;
using StellaOps.Cli.Commands;
namespace StellaOps.Cli.Tests.Commands;
/// <summary>
/// Unit tests for the vex gen command structure.
/// </summary>
[Trait("Category", "Unit")]
public sealed class VexGenCommandTests
{
[Fact]
public void VexGenCommand_HasCorrectName()
{
// Arrange & Act
var command = BuildVexGenCommand();
// Assert
Assert.Equal("gen", command.Name);
}
[Fact]
public void VexGenCommand_HasCorrectDescription()
{
// Arrange & Act
var command = BuildVexGenCommand();
// Assert
Assert.Contains("VEX", command.Description);
Assert.Contains("drift", command.Description);
}
[Fact]
public void VexGenCommand_HasFromDriftOption()
{
// Arrange
var command = BuildVexGenCommand();
// Act
var fromDriftOpt = command.Options.FirstOrDefault(o =>
o.Name == "from-drift" || o.Name == "--from-drift" || o.Aliases.Contains("--from-drift"));
// Assert
Assert.NotNull(fromDriftOpt);
Assert.Contains("drift", fromDriftOpt.Description);
}
[Fact]
public void VexGenCommand_HasImageOption()
{
// Arrange
var command = BuildVexGenCommand();
// Act
var imageOpt = command.Options.FirstOrDefault(o =>
o.Name == "image" || o.Name == "--image" || o.Aliases.Contains("--image"));
// Assert
Assert.NotNull(imageOpt);
Assert.True(imageOpt.Aliases.Contains("-i") || imageOpt.Aliases.Contains("--image"));
}
[Fact]
public void VexGenCommand_HasBaselineOption()
{
// Arrange
var command = BuildVexGenCommand();
// Act
var baselineOpt = command.Options.FirstOrDefault(o =>
o.Name == "baseline" || o.Name == "--baseline" || o.Aliases.Contains("--baseline"));
// Assert
Assert.NotNull(baselineOpt);
Assert.True(baselineOpt.Aliases.Contains("-b") || baselineOpt.Aliases.Contains("--baseline"));
}
[Fact]
public void VexGenCommand_HasOutputOption()
{
// Arrange
var command = BuildVexGenCommand();
// Act
var outputOpt = command.Options.FirstOrDefault(o =>
o.Name == "output" || o.Name == "--output" || o.Aliases.Contains("--output"));
// Assert
Assert.NotNull(outputOpt);
Assert.True(outputOpt.Aliases.Contains("-o") || outputOpt.Aliases.Contains("--output"));
}
[Fact]
public void VexGenCommand_HasFormatOption()
{
// Arrange
var command = BuildVexGenCommand();
// Act
var formatOpt = command.Options.FirstOrDefault(o =>
o.Name == "format" || o.Name == "--format" || o.Aliases.Contains("--format"));
// Assert
Assert.NotNull(formatOpt);
Assert.Contains("openvex", formatOpt.Description);
Assert.Contains("csaf", formatOpt.Description);
}
[Fact]
public void VexGenCommand_HasStatusOption()
{
// Arrange
var command = BuildVexGenCommand();
// Act
var statusOpt = command.Options.FirstOrDefault(o =>
o.Name == "status" || o.Name == "--status" || o.Aliases.Contains("--status"));
// Assert
Assert.NotNull(statusOpt);
Assert.Contains("under_investigation", statusOpt.Description);
}
[Fact]
public void VexGenCommand_HasVerboseOption()
{
// Arrange
var command = BuildVexGenCommand();
// Act
var verboseOpt = command.Options.FirstOrDefault(o =>
o.Name == "verbose" || o.Name == "--verbose" || o.Aliases.Contains("--verbose"));
// Assert
Assert.NotNull(verboseOpt);
}
[Fact]
public void VexGenCommand_AllOptionsAreConfigured()
{
// Arrange
var command = BuildVexGenCommand();
var expectedOptions = new[]
{
"from-drift", "image", "baseline", "output", "format", "status", "verbose"
};
// Act - normalize all option names by stripping leading dashes
var actualOptionNames = command.Options
.SelectMany(o => new[] { o.Name.TrimStart('-') }.Concat(o.Aliases.Select(a => a.TrimStart('-'))))
.ToHashSet(StringComparer.OrdinalIgnoreCase);
// Assert
foreach (var expected in expectedOptions)
{
Assert.Contains(expected, actualOptionNames);
}
}
[Fact]
public void VexGenCommand_ImageOption_HasRequiredSet()
{
// Arrange
var command = BuildVexGenCommand();
var imageOpt = command.Options.First(o =>
o.Name == "image" || o.Name == "--image" || o.Aliases.Contains("--image"));
// Assert - verify it's configured as required (the Required property exists)
Assert.NotNull(imageOpt);
}
[Fact]
public void VexGenCommand_FormatOption_SupportsAllFormats()
{
// Arrange
var command = BuildVexGenCommand();
var formatOpt = command.Options.First(o =>
o.Name == "format" || o.Name == "--format" || o.Aliases.Contains("--format"));
// Assert - verify description mentions supported formats
Assert.Contains("openvex", formatOpt.Description);
Assert.Contains("csaf", formatOpt.Description);
}
[Fact]
public void VexGenCommand_StatusOption_SupportsAllStatuses()
{
// Arrange
var command = BuildVexGenCommand();
var statusOpt = command.Options.First(o =>
o.Name == "status" || o.Name == "--status" || o.Aliases.Contains("--status"));
// Assert - verify description mentions supported statuses
Assert.Contains("under_investigation", statusOpt.Description);
Assert.Contains("not_affected", statusOpt.Description);
Assert.Contains("affected", statusOpt.Description);
}
private static Command BuildVexGenCommand()
{
var mockServices = new Mock<IServiceProvider>();
var verboseOption = new Option<bool>("--verbose");
return VexGenCommandGroup.BuildVexGenCommand(
mockServices.Object,
verboseOption,
CancellationToken.None);
}
}