// ----------------------------------------------------------------------------- // 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; /// /// Unit tests for the seal command structure. /// [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(); var verboseOption = new Option("--verbose"); return SealCommandGroup.BuildSealCommand( mockServices.Object, verboseOption, CancellationToken.None); } }