using w4c_workflows.Models; using w4c_workflows.Services; using Xunit; namespace w4c_workflows.Tests; public class MermaidGeneratorServiceTests { private const string Tenant = "t1"; private const string Path = "workflows/main-task.yaml"; private static readonly string ExampleYaml = """ name: main-task mode: handler language: typescript trigger: type: queue stream: orders entry: { file: index.ts, function: handler } tasks: - id: validate parent: root next: enrich onError: compensate language: python entry: { file: validate.py } - id: enrich parent: root next: persist language: csharp entry: { file: Enrich.cs } - id: persist parent: root language: shell entry: { file: persist.sh } - id: compensate parent: root language: python entry: { file: compensate.py } """; private static CompiledWorkflow Compile() => new WorkflowCompiler(new WorkflowValidator(new LanguageRegistry())) .Compile(ExampleYaml, Path, Tenant).Workflow!; [Fact] public void Flowchart_renders_next_solid_and_onError_dashed() { var compiled = Compile(); var source = new MermaidGeneratorService().Generate("flowchart", compiled.Workflow, compiled.Tasks); Assert.Contains("flowchart TD", source); Assert.Contains("root --> validate", source); Assert.Contains("validate --> enrich", source); Assert.Contains("validate -.->|error| compensate", source); Assert.Contains("class root root", source); } [Fact] public void Sequence_renders_happy_path_and_alt_error_block() { var compiled = Compile(); var source = new MermaidGeneratorService().Generate("sequence", compiled.Workflow, compiled.Tasks); Assert.Contains("sequenceDiagram", source); Assert.Contains("root->>validate", source); Assert.Contains("validate->>enrich", source); Assert.Contains("alt on error", source); Assert.Contains("validate->>compensate", source); } [Fact] public void State_renders_entry_terminal_and_error_transitions() { var compiled = Compile(); var source = new MermaidGeneratorService().Generate("state", compiled.Workflow, compiled.Tasks); Assert.Contains("stateDiagram-v2", source); Assert.Contains("[*] --> root", source); Assert.Contains("persist --> [*]", source); Assert.Contains("validate --> compensate: error", source); } [Fact] public void Class_renders_language_not_runtime() { var compiled = Compile(); var source = new MermaidGeneratorService().Generate("class", compiled.Workflow, compiled.Tasks); Assert.Contains("classDiagram", source); Assert.Contains("<>", source); // root language Assert.Contains("<>", source); // validate language Assert.Contains("entry: index.ts", source); Assert.DoesNotContain("runtime", source); } [Fact] public void Unknown_type_throws() { var compiled = Compile(); var generator = new MermaidGeneratorService(); Assert.Throws(() => generator.Generate("pie", compiled.Workflow, compiled.Tasks)); } }