| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- package parser
- import (
- "strings"
- "testing"
- "mermaid-go/pkg/ast"
- "mermaid-go/pkg/renderer"
- )
- func TestStateParser_EnhancedFeatures(t *testing.T) {
- tests := []struct {
- name string
- input string
- expected string
- }{
- {
- name: "Basic State with Actions",
- input: `stateDiagram-v2
- [*] --> State1
- State1 : entry / initialize
- State1 : exit / cleanup
- State1 : do / process
- State1 --> State2 : transition`,
- expected: `stateDiagram-v2
- [*] --> State1
- State1 : entry / initialize
- State1 : exit / cleanup
- State1 : do / process
- State1 --> State2 : transition
- `,
- },
- {
- name: "Composite State",
- input: `stateDiagram-v2
- [*] --> CompositeState
- state CompositeState {
- [*] --> SubState1
- SubState1 --> SubState2
- SubState2 --> [*]
- }
- CompositeState --> [*]`,
- expected: `stateDiagram-v2
- [*] --> CompositeState
- state CompositeState {
- [*] --> SubState1
- SubState1 --> SubState2
- SubState2 --> [*]
- }
- CompositeState --> [*]
- `,
- },
- {
- name: "Parallel States",
- input: `stateDiagram-v2
- [*] --> ParallelState
- state ParallelState {
- [*] --> Region1
- [*] --> Region2
- state Region1 {
- [*] --> StateA
- StateA --> StateB
- }
- state Region2 {
- [*] --> StateC
- StateC --> StateD
- }
- }`,
- expected: `stateDiagram-v2
- [*] --> ParallelState
- state ParallelState {
- [*] --> Region1
- [*] --> Region2
- state Region1 {
- [*] --> StateA
- StateA --> StateB
- }
- state Region2 {
- [*] --> StateC
- StateC --> StateD
- }
- }
- `,
- },
- {
- name: "Special States",
- input: `stateDiagram-v2
- [*] --> ForkState
- ForkState : <<fork>>
- ForkState --> ChoiceState
- ChoiceState : <<choice>>
- ChoiceState --> JoinState
- JoinState : <<join>>
- JoinState --> [*]`,
- expected: `stateDiagram-v2
- state JoinState : <<join>>
- state ForkState : <<fork>>
- state ChoiceState : <<choice>>
- [*] --> ForkState
- ForkState --> ChoiceState
- ChoiceState --> JoinState
- JoinState --> [*]
- `,
- },
- {
- name: "Complex Transitions with Guards and Actions",
- input: `stateDiagram-v2
- [*] --> State1
- State1 --> State2 : normal [condition] / action
- State2 --> State3 : urgent [priority > 5] / handle
- State3 --> [*]`,
- expected: `stateDiagram-v2
- [*] --> State1
- State1 --> State2 : normal [condition] / action
- State2 --> State3 : urgent [priority > 5] / handle
- State3 --> [*]
- `,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- parser := NewStateParser()
- diagram, err := parser.Parse(tt.input)
- if err != nil {
- t.Fatalf("Failed to parse: %v", err)
- }
- // Test rendering
- renderer := renderer.NewStateRenderer()
- output, err := renderer.Render(diagram)
- if err != nil {
- t.Fatalf("Failed to render: %v", err)
- }
- // Normalize whitespace for comparison
- expected := strings.TrimSpace(tt.expected)
- actual := strings.TrimSpace(output)
- if expected != actual {
- t.Errorf("Expected:\n%s\n\nGot:\n%s", expected, actual)
- }
- })
- }
- }
- func TestStateParser_StateActions(t *testing.T) {
- input := `stateDiagram-v2
- [*] --> State1
- State1 : entry / initialize system
- State1 : exit / cleanup resources
- State1 : do / process data
- State1 --> State2`
- parser := NewStateParser()
- diagram, err := parser.Parse(input)
- if err != nil {
- t.Fatalf("Failed to parse: %v", err)
- }
- // Check state was parsed with actions
- if len(diagram.States) == 0 {
- t.Fatal("No states found")
- }
- var state1 *ast.StateNode
- for _, state := range diagram.States {
- if state.ID == "State1" {
- state1 = state
- break
- }
- }
- if state1 == nil {
- t.Fatal("State1 not found")
- }
- if state1.EntryAction == nil || *state1.EntryAction != "/ initialize system" {
- t.Errorf("Expected entry action '/ initialize system', got %v", state1.EntryAction)
- }
- if state1.ExitAction == nil || *state1.ExitAction != "/ cleanup resources" {
- t.Errorf("Expected exit action '/ cleanup resources', got %v", state1.ExitAction)
- }
- if state1.DoAction == nil || *state1.DoAction != "/ process data" {
- t.Errorf("Expected do action '/ process data', got %v", state1.DoAction)
- }
- }
- func TestStateParser_CompositeStates(t *testing.T) {
- input := `stateDiagram-v2
- [*] --> CompositeState
- state CompositeState {
- [*] --> SubState1
- SubState1 --> SubState2
- }
- CompositeState --> [*]`
- parser := NewStateParser()
- diagram, err := parser.Parse(input)
- if err != nil {
- t.Fatalf("Failed to parse: %v", err)
- }
- // Check composite state was parsed
- var compositeState *ast.StateNode
- for _, state := range diagram.States {
- if state.ID == "CompositeState" {
- compositeState = state
- break
- }
- }
- if compositeState == nil {
- t.Fatal("CompositeState not found")
- }
- if compositeState.SubStates == nil || len(compositeState.SubStates) == 0 {
- t.Fatal("No substates found in CompositeState")
- }
- // Check substates
- if _, exists := compositeState.SubStates["SubState1"]; !exists {
- t.Error("SubState1 not found in CompositeState")
- }
- if _, exists := compositeState.SubStates["SubState2"]; !exists {
- t.Error("SubState2 not found in CompositeState")
- }
- }
|