using System.CommandLine; using JdeScoping.ConfigManager.Cli.Commands; using JdeScoping.ConfigManager.Core.Services; using JdeScoping.DataSync.Configuration; using Microsoft.Extensions.DependencyInjection; namespace JdeScoping.ConfigManager.Cli.Tests.Commands; [Collection("Console Tests")] public class PipelineCommandsTests { private readonly IServiceProvider _serviceProvider; private readonly IConfigFileService _configFileService; private readonly IAutoDiscoveryService _autoDiscoveryService; private readonly Option _configPathOption; private readonly Option _verboseOption; private readonly Option _quietOption; public PipelineCommandsTests() { _configFileService = Substitute.For(); _autoDiscoveryService = Substitute.For(); var services = new ServiceCollection(); services.AddSingleton(_configFileService); services.AddSingleton(_autoDiscoveryService); services.AddTestLogging(); _serviceProvider = services.BuildServiceProvider(); _configPathOption = new Option(["--config-path", "-c"]); _verboseOption = new Option(["--verbose", "-v"]); _quietOption = new Option(["--quiet", "-q"]); } [Fact] public void CreateListCommand_ReturnsCommand() { // Act var command = PipelineCommands.CreateListCommand( _serviceProvider, _configPathOption, _verboseOption, _quietOption); // Assert command.ShouldNotBeNull(); command.Name.ShouldBe("list"); } [Fact] public void CreateShowCommand_ReturnsCommandWithNameArgument() { // Act var command = PipelineCommands.CreateShowCommand( _serviceProvider, _configPathOption, _verboseOption, _quietOption); // Assert command.ShouldNotBeNull(); command.Name.ShouldBe("show"); command.Arguments.ShouldContain(a => a.Name == "name"); } [Fact] public void CreateCreateCommand_ReturnsCommandWithOptions() { // Act var command = PipelineCommands.CreateCreateCommand( _serviceProvider, _configPathOption, _verboseOption, _quietOption); // Assert command.ShouldNotBeNull(); command.Name.ShouldBe("create"); command.Arguments.ShouldContain(a => a.Name == "name"); command.Options.ShouldContain(o => o.Name == "enabled"); command.Options.ShouldContain(o => o.Name == "manual-only"); } [Fact] public void CreateDeleteCommand_ReturnsCommandWithForceOption() { // Act var command = PipelineCommands.CreateDeleteCommand( _serviceProvider, _configPathOption, _verboseOption, _quietOption); // Assert command.ShouldNotBeNull(); command.Name.ShouldBe("delete"); command.Arguments.ShouldContain(a => a.Name == "name"); command.Options.ShouldContain(o => o.Name == "force"); } [Fact] public void CreateEnableCommand_ReturnsCommand() { // Act var command = PipelineCommands.CreateEnableCommand( _serviceProvider, _configPathOption, _verboseOption, _quietOption); // Assert command.ShouldNotBeNull(); command.Name.ShouldBe("enable"); command.Arguments.ShouldContain(a => a.Name == "name"); } [Fact] public void CreateDisableCommand_ReturnsCommand() { // Act var command = PipelineCommands.CreateDisableCommand( _serviceProvider, _configPathOption, _verboseOption, _quietOption); // Assert command.ShouldNotBeNull(); command.Name.ShouldBe("disable"); command.Arguments.ShouldContain(a => a.Name == "name"); } [Fact] public async Task ListCommand_WithNoConfigFolder_ReturnsError() { // Arrange _autoDiscoveryService.FindConfigFolderAsync(Arg.Any()) .Returns(Task.FromResult(null)); var command = PipelineCommands.CreateListCommand( _serviceProvider, _configPathOption, _verboseOption, _quietOption); var rootCommand = new RootCommand { command }; rootCommand.AddGlobalOption(_configPathOption); rootCommand.AddGlobalOption(_verboseOption); rootCommand.AddGlobalOption(_quietOption); // Act var exitCode = await rootCommand.InvokeAsync(["list"]); // Assert - exit code is set via Environment.ExitCode // The command should complete without throwing command.ShouldNotBeNull(); } [Fact] public async Task ListCommand_WithValidPipelines_ReturnsSuccess() { // Arrange var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); var pipelinesDir = Path.Combine(tempDir, "Pipelines"); Directory.CreateDirectory(pipelinesDir); try { _autoDiscoveryService.FindConfigFolderAsync(Arg.Any()) .Returns(Task.FromResult(tempDir)); var pipelines = new Dictionary { ["WorkOrder_Curr"] = new EtlPipelineConfig { Name = "WorkOrder_Curr", IsEnabled = true, MassSyncIntervalMinutes = 10080, DailySyncIntervalMinutes = 1440 } }; _configFileService.LoadAllPipelinesAsync(pipelinesDir, Arg.Any()) .Returns(Task.FromResult(pipelines)); var command = PipelineCommands.CreateListCommand( _serviceProvider, _configPathOption, _verboseOption, _quietOption); var rootCommand = new RootCommand { command }; rootCommand.AddGlobalOption(_configPathOption); rootCommand.AddGlobalOption(_verboseOption); rootCommand.AddGlobalOption(_quietOption); // Capture console output var originalOut = Console.Out; using var writer = new StringWriter(); Console.SetOut(writer); try { // Act await rootCommand.InvokeAsync(["list"]); // Assert var output = writer.ToString(); output.ShouldContain("WorkOrder_Curr"); } finally { Console.SetOut(originalOut); } } finally { Directory.Delete(tempDir, true); } } }