w4c-workflows-api/w4c-workflows-api.Tests/MermaidGeneratorServiceTests.cs

105 lines
3.4 KiB
C#

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("<<typescript>>", source); // root language
Assert.Contains("<<python>>", 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<ArgumentException>(() => generator.Generate("pie", compiled.Workflow, compiled.Tasks));
}
}