// ----------------------------------------------------------------------------- // WitnessCommandGroupTests.cs // Sprint: SPRINT_3700_0005_0001_witness_ui_cli // Tasks: TEST-002 // Description: Unit tests for witness CLI commands // ----------------------------------------------------------------------------- using System.CommandLine; using System.CommandLine.Parsing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Moq; using Xunit; using StellaOps.Cli.Commands; namespace StellaOps.Cli.Tests.Commands; /// /// Unit tests for witness CLI commands. /// public class WitnessCommandGroupTests { private readonly IServiceProvider _services; private readonly Option _verboseOption; private readonly CancellationToken _cancellationToken; public WitnessCommandGroupTests() { var serviceCollection = new ServiceCollection(); serviceCollection.AddLogging(); _services = serviceCollection.BuildServiceProvider(); _verboseOption = new Option("--verbose", "-v"); _cancellationToken = CancellationToken.None; } #region Command Structure Tests [Fact] public void BuildWitnessCommand_CreatesWitnessCommandTree() { // Act var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); // Assert Assert.Equal("witness", command.Name); Assert.Equal("Reachability witness operations.", command.Description); } [Fact] public void BuildWitnessCommand_HasShowSubcommand() { // Act var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var showCommand = command.Subcommands.FirstOrDefault(c => c.Name == "show"); // Assert Assert.NotNull(showCommand); Assert.Equal("Display a witness with call path visualization.", showCommand.Description); } [Fact] public void BuildWitnessCommand_HasVerifySubcommand() { // Act var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var verifyCommand = command.Subcommands.FirstOrDefault(c => c.Name == "verify"); // Assert Assert.NotNull(verifyCommand); } [Fact] public void BuildWitnessCommand_HasListSubcommand() { // Act var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var listCommand = command.Subcommands.FirstOrDefault(c => c.Name == "list"); // Assert Assert.NotNull(listCommand); } [Fact] public void BuildWitnessCommand_HasExportSubcommand() { // Act var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var exportCommand = command.Subcommands.FirstOrDefault(c => c.Name == "export"); // Assert Assert.NotNull(exportCommand); } #endregion #region Show Command Tests [Fact] public void ShowCommand_HasWitnessIdArgument() { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var showCommand = command.Subcommands.First(c => c.Name == "show"); // Act var witnessIdArg = showCommand.Arguments.FirstOrDefault(a => a.Name == "witness-id"); // Assert Assert.NotNull(witnessIdArg); } [Fact] public void ShowCommand_HasFormatOption() { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var showCommand = command.Subcommands.First(c => c.Name == "show"); // Act var formatOption = showCommand.Options.FirstOrDefault(o => o.Aliases.Contains("-f") || o.Aliases.Contains("--format")); // Assert Assert.NotNull(formatOption); } [Fact] public void ShowCommand_HasNoColorOption() { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var showCommand = command.Subcommands.First(c => c.Name == "show"); // Act var noColorOption = showCommand.Options.FirstOrDefault(o => o.Name == "--no-color" || o.Aliases.Contains("--no-color")); // Assert Assert.NotNull(noColorOption); } [Fact] public void ShowCommand_HasPathOnlyOption() { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var showCommand = command.Subcommands.First(c => c.Name == "show"); // Act var pathOnlyOption = showCommand.Options.FirstOrDefault(o => o.Name == "--path-only" || o.Aliases.Contains("--path-only")); // Assert Assert.NotNull(pathOnlyOption); } [Theory] [InlineData("text")] [InlineData("json")] [InlineData("yaml")] public void ShowCommand_FormatOption_AcceptsValidFormats(string format) { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var showCommand = command.Subcommands.First(c => c.Name == "show"); // Act var parseResult = showCommand.Parse($"wit:abc123 --format {format}"); // Assert Assert.Empty(parseResult.Errors); } [Fact] public void ShowCommand_FormatOption_RejectsInvalidFormat() { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var showCommand = command.Subcommands.First(c => c.Name == "show"); // Act var parseResult = showCommand.Parse("wit:abc123 --format invalid"); // Assert Assert.NotEmpty(parseResult.Errors); } #endregion #region Verify Command Tests [Fact] public void VerifyCommand_HasWitnessIdArgument() { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var verifyCommand = command.Subcommands.First(c => c.Name == "verify"); // Act var witnessIdArg = verifyCommand.Arguments.FirstOrDefault(a => a.Name == "witness-id"); // Assert Assert.NotNull(witnessIdArg); } [Fact] public void VerifyCommand_HasPublicKeyOption() { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var verifyCommand = command.Subcommands.First(c => c.Name == "verify"); // Act var publicKeyOption = verifyCommand.Options.FirstOrDefault(o => o.Aliases.Contains("-k") || o.Aliases.Contains("--public-key")); // Assert Assert.NotNull(publicKeyOption); } [Fact] public void VerifyCommand_HasOfflineOption() { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var verifyCommand = command.Subcommands.First(c => c.Name == "verify"); // Act var offlineOption = verifyCommand.Options.FirstOrDefault(o => o.Name == "--offline" || o.Aliases.Contains("--offline")); // Assert Assert.NotNull(offlineOption); } #endregion #region List Command Tests [Fact] public void ListCommand_HasScanOption() { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var listCommand = command.Subcommands.First(c => c.Name == "list"); // Act var scanOption = listCommand.Options.FirstOrDefault(o => o.Aliases.Contains("--scan") || o.Aliases.Contains("-s")); // Assert Assert.NotNull(scanOption); } [Fact] public void ListCommand_HasVulnOption() { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var listCommand = command.Subcommands.First(c => c.Name == "list"); // Act var vulnOption = listCommand.Options.FirstOrDefault(o => o.Aliases.Contains("--vuln") || o.Aliases.Contains("-v")); // Assert Assert.NotNull(vulnOption); } [Fact] public void ListCommand_HasReachableOnlyOption() { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var listCommand = command.Subcommands.First(c => c.Name == "list"); // Act var reachableOption = listCommand.Options.FirstOrDefault(o => o.Name == "--reachable-only" || o.Aliases.Contains("--reachable-only")); // Assert Assert.NotNull(reachableOption); } #endregion #region Export Command Tests [Fact] public void ExportCommand_HasWitnessIdArgument() { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var exportCommand = command.Subcommands.First(c => c.Name == "export"); // Act var witnessIdArg = exportCommand.Arguments.FirstOrDefault(a => a.Name == "witness-id"); // Assert Assert.NotNull(witnessIdArg); } [Fact] public void ExportCommand_HasFormatOption() { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var exportCommand = command.Subcommands.First(c => c.Name == "export"); // Act var formatOption = exportCommand.Options.FirstOrDefault(o => o.Aliases.Contains("-f") || o.Aliases.Contains("--format")); // Assert Assert.NotNull(formatOption); } [Fact] public void ExportCommand_HasOutputOption() { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var exportCommand = command.Subcommands.First(c => c.Name == "export"); // Act var outputOption = exportCommand.Options.FirstOrDefault(o => o.Aliases.Contains("-o") || o.Aliases.Contains("--output")); // Assert Assert.NotNull(outputOption); } [Theory] [InlineData("json")] [InlineData("sarif")] public void ExportCommand_FormatOption_AcceptsValidFormats(string format) { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); var exportCommand = command.Subcommands.First(c => c.Name == "export"); // Act var parseResult = exportCommand.Parse($"wit:abc123 --format {format}"); // Assert Assert.Empty(parseResult.Errors); } #endregion #region Integration Tests [Fact] public void WitnessCommand_CanParseShowCommand() { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); // Act var parseResult = command.Parse("show wit:sha256:abc123 --format json"); // Assert Assert.Equal("show", parseResult.CommandResult.Command.Name); Assert.Empty(parseResult.Errors); } [Fact] public void WitnessCommand_CanParseVerifyCommand() { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); // Act var parseResult = command.Parse("verify wit:sha256:abc123 --offline"); // Assert Assert.Equal("verify", parseResult.CommandResult.Command.Name); Assert.Empty(parseResult.Errors); } [Fact] public void WitnessCommand_CanParseListCommand() { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); // Act var parseResult = command.Parse("list --scan scan-12345 --reachable-only"); // Assert Assert.Equal("list", parseResult.CommandResult.Command.Name); Assert.Empty(parseResult.Errors); } [Fact] public void WitnessCommand_CanParseExportCommand() { // Arrange var command = WitnessCommandGroup.BuildWitnessCommand(_services, _verboseOption, _cancellationToken); // Act var parseResult = command.Parse("export wit:sha256:abc123 --format sarif --output report.sarif"); // Assert Assert.Equal("export", parseResult.CommandResult.Command.Name); Assert.Empty(parseResult.Errors); } #endregion }