// -----------------------------------------------------------------------------
// 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);
}
}