using Sdt.Config; using Xunit; namespace DevTool.Tests; public sealed class WorkflowModelBuilderTests { [Fact] public void TargetsOnly_Strict_ThrowsMigrationError() { var cfg = new DevToolConfig { Targets = [ new BuildTarget { Id = "build", Label = "Build", Command = "dotnet", Args = ["build"], } ] }; var ex = Assert.Throws(() => WorkflowModelBuilder.Normalize(cfg, LegacyMode.Strict)); Assert.Contains("Legacy 'targets' are not allowed in strict mode", ex.Message, StringComparison.OrdinalIgnoreCase); } [Fact] public void TargetsOnly_Compat_ProducesWarningAndConvertedWorkflow() { var cfg = new DevToolConfig { Targets = [ new BuildTarget { Id = "build", Label = "Build", Command = "dotnet", Args = ["build"], } ] }; var result = WorkflowModelBuilder.Normalize(cfg, LegacyMode.Compat); Assert.Single(result.Workflows); Assert.Contains(result.Warnings, w => w.Contains("legacy 'targets'", StringComparison.OrdinalIgnoreCase)); } [Fact] public void WorkflowsOnly_HasNoLegacyWarning() { var cfg = new DevToolConfig { Workflows = [ new WorkflowDefinition { Id = "build", Label = "Build", Steps = [ new WorkflowStep { Id = "run", Label = "Run", Command = "dotnet", Args = ["build"], } ] } ] }; var result = WorkflowModelBuilder.Normalize(cfg, LegacyMode.Strict); Assert.Single(result.Workflows); Assert.DoesNotContain(result.Warnings, w => w.Contains("legacy 'targets'", StringComparison.OrdinalIgnoreCase)); } [Fact] public void Mixed_PrefersWorkflowsDeterministically() { var cfg = new DevToolConfig { Targets = [ new BuildTarget { Id = "legacy", Label = "Legacy", Command = "dotnet", Args = ["build"], } ], Workflows = [ new WorkflowDefinition { Id = "new", Label = "New", Steps = [ new WorkflowStep { Id = "step", Label = "Step", Command = "dotnet", Args = ["build"], } ] } ] }; var result = WorkflowModelBuilder.Normalize(cfg, LegacyMode.Strict); Assert.Single(result.Workflows); Assert.Equal("new", result.Workflows[0].Id); Assert.Contains(result.Warnings, w => w.Contains("Both 'workflows' and legacy 'targets'", StringComparison.OrdinalIgnoreCase)); } [Fact] public void LegacyPwshTarget_InfersToolRequirements_FromScript() { var cfg = new DevToolConfig { Targets = [ new BuildTarget { Id = "web", Label = "Web", Command = "pwsh", Args = ["-NoProfile", "-File", "scripts/publish-app.ps1", "-Target", "web"], } ] }; var result = WorkflowModelBuilder.Normalize(cfg, LegacyMode.Compat); var step = Assert.Single(result.Workflows).Steps.Single(); Assert.Contains(step.Requires, r => r.Tool == "python"); Assert.Contains(step.Requires, r => r.Tool == "node"); Assert.Contains(step.Requires, r => r.Tool == "npm"); } }