diff --git a/src/Fallout.Cli/Program.Complete.cs b/src/Fallout.Cli/Commands/CompleteCommand.cs similarity index 81% rename from src/Fallout.Cli/Program.Complete.cs rename to src/Fallout.Cli/Commands/CompleteCommand.cs index d1af3e1fb..8c81d6890 100644 --- a/src/Fallout.Cli/Program.Complete.cs +++ b/src/Fallout.Cli/Commands/CompleteCommand.cs @@ -7,13 +7,18 @@ using Fallout.Utilities.Text.Yaml; using static Fallout.Common.Constants; -namespace Fallout.Cli; +namespace Fallout.Cli.Commands; -partial class Program +/// +/// fallout :complete: emits shell-completion candidates for the partially typed command line. +/// +public sealed class CompleteCommand : IFalloutCommand { private const string CommandName = "fallout"; - public static int Complete(string[] args, AbsolutePath rootDirectory, AbsolutePath buildScript) + public string Name => "complete"; + + public int Execute(string[] args, AbsolutePath rootDirectory, AbsolutePath buildScript) { if (rootDirectory == null) return 0; diff --git a/src/Fallout.Cli/Program.cs b/src/Fallout.Cli/Program.cs index 25c5839e1..b713e6154 100644 --- a/src/Fallout.Cli/Program.cs +++ b/src/Fallout.Cli/Program.cs @@ -54,6 +54,7 @@ private static void RegisterCommands(IServiceCollection services) // Real command types — issue #392 converts one legacy handler per PR. services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); // Legacy handlers still living on Program, adapted until they are extracted into command // types. Each conversion deletes one line here plus its Program.X.cs partial. @@ -62,7 +63,6 @@ private static void RegisterCommands(IServiceCollection services) services.AddSingleton(new DelegateCommand("add-package", AddPackage)); services.AddSingleton(new DelegateCommand("cake-convert", CakeConvert)); services.AddSingleton(new DelegateCommand("cake-clean", CakeClean)); - services.AddSingleton(new DelegateCommand("complete", Complete)); services.AddSingleton(new DelegateCommand("get-configuration", GetConfiguration)); services.AddSingleton(new DelegateCommand("secrets", Secrets)); services.AddSingleton(new DelegateCommand("GetNextDirectory", GetNextDirectory)); diff --git a/tests/Fallout.Cli.Tests/Commands/CompleteCommandTests.cs b/tests/Fallout.Cli.Tests/Commands/CompleteCommandTests.cs new file mode 100644 index 000000000..33ac3d7eb --- /dev/null +++ b/tests/Fallout.Cli.Tests/Commands/CompleteCommandTests.cs @@ -0,0 +1,35 @@ +using System; +using System.IO; +using Fallout.Cli.Commands; +using Fallout.Common.IO; +using FluentAssertions; +using Xunit; + +namespace Fallout.Cli.Tests.Commands; + +public class CompleteCommandTests +{ + [Fact] + public void Name_IsComplete() + => new CompleteCommand().Name.Should().Be("complete"); + + [Fact] + public void Execute_WithoutRootDirectory_ReturnsZero() + => new CompleteCommand().Execute(["fallout "], rootDirectory: null, buildScript: null).Should().Be(0); + + [Fact] + public void Execute_WordNotStartingWithCommandName_ReturnsZero() + { + var dir = (AbsolutePath)Path.Combine(Path.GetTempPath(), "fallout-complete-" + Guid.NewGuid().ToString("N")); + dir.CreateDirectory(); + try + { + // Completion only fires for the `fallout` command line; anything else short-circuits to 0. + new CompleteCommand().Execute(["notfallout foo"], dir, buildScript: null).Should().Be(0); + } + finally + { + Directory.Delete(dir, recursive: true); + } + } +}