using Spectre.Console.Testing; using ZB.MOM.WW.Secrets.Cli.Interactive; namespace ZB.MOM.WW.Secrets.Tests.Cli.Interactive; /// /// Pins the composition root of the interactive console: the non-TTY gate that decides whether a bare /// secret invocation launches the console, and the exact flow set (order + uniqueness) the shell /// is wired with. These are the two things Program.cs delegates to, so they are asserted here directly /// rather than by driving the whole shell. /// public sealed class InteractiveEntryTests { [Theory] // Only a bare invocation on a real TTY (neither stream redirected) enters the interactive console. [InlineData(new string[0], false, false, true)] [InlineData(new string[0], true, false, false)] [InlineData(new string[0], false, true, false)] [InlineData(new string[0], true, true, false)] [InlineData(new[] { "list" }, false, false, false)] public void ShouldEnterInteractive_true_only_for_no_args_and_real_tty( string[] args, bool inputRedirected, bool outputRedirected, bool expected) { Assert.Equal( expected, InteractiveEntry.ShouldEnterInteractive(args, inputRedirected, outputRedirected)); } [Fact] public void CreateShell_composes_all_flows_exactly_once() { // CreateShell must succeed — its InteractiveShell ctor re-validates flow-title uniqueness, so a // duplicate or reserved collision would throw here. InteractiveShell shell = InteractiveEntry.CreateShell(new TestConsole()); Assert.NotNull(shell); // The composed flow set is asserted through the same seam CreateShell uses. string[] titles = InteractiveEntry.CreateFlows().Select(f => f.Title).ToArray(); Assert.Equal( new[] { "List secrets", "Set / rotate a secret", "Get (reveal) a secret", "Delete a secret", "Reference audit & seed", "KEK doctor (lockout recovery)", "Export bundle (ciphertext-only)", "Import bundle", }, titles); // Each title appears exactly once. Assert.Equal(titles.Length, titles.Distinct(StringComparer.Ordinal).Count()); } }