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