Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9ea0a8d

Browse files
authored
feat: adds mermaid graph output (#50)
* chore: ignores .coverprofile* feat: adds mermaid visualize output* fix: sorts eKeys to have a reproducible graph output* fix: uses non current transitions with sort as well* test: adds third transition to verify sorting* fix: replaces ReplaceAll with Replace due to go1.11* fix: uses ReplaceAll in tests instead of Replace
1 parent7ee53d3 commit9ea0a8d

File tree

3 files changed

+141
-2
lines changed

3 files changed

+141
-2
lines changed

‎.gitignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,6 @@ _testmain.go
2626

2727
.DS_Store
2828
.wercker
29+
30+
# Testing
31+
.coverprofile

‎utils.go‎

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,78 @@ package fsm
33
import (
44
"bytes"
55
"fmt"
6+
"sort"
67
)
78

9+
// VisualizeType the type of the visualization
10+
typeVisualizeTypestring
11+
12+
const (
13+
// GRAPHVIZ the type for graphviz output (http://www.webgraphviz.com/)
14+
GRAPHVIZVisualizeType="graphviz"
15+
// MERMAID the type for mermaid output (https://mermaid-js.github.io/mermaid-live-editor/)
16+
MERMAIDVisualizeType="mermaid"
17+
)
18+
19+
// VisualizeWithType outputs a visualization of a FSM in the desired format.
20+
// If the type is not given it defaults to GRAPHVIZ
21+
funcVisualizeWithType(fsm*FSM,visualizeTypeVisualizeType) (string,error) {
22+
switchvisualizeType {
23+
caseGRAPHVIZ:
24+
returnVisualize(fsm),nil
25+
caseMERMAID:
26+
returnvisualizeForMermaid(fsm),nil
27+
default:
28+
return"",fmt.Errorf("unknown VisualizeType: %s",visualizeType)
29+
}
30+
}
31+
32+
// visualizeForMermaid outputs a visualization of a FSM in Mermaid format.
33+
funcvisualizeForMermaid(fsm*FSM)string {
34+
varbuf bytes.Buffer
35+
36+
// we sort the key alphabetically to have a reproducible graph output
37+
sortedEKeys:=make([]eKey,0)
38+
fork:=rangefsm.transitions {
39+
sortedEKeys=append(sortedEKeys,k)
40+
}
41+
sort.Slice(sortedEKeys,func(i,jint)bool {
42+
returnsortedEKeys[i].src<sortedEKeys[j].src
43+
})
44+
45+
buf.WriteString(fmt.Sprintf(`graph fsm`))
46+
buf.WriteString("\n")
47+
48+
for_,k:=rangesortedEKeys {
49+
v:=fsm.transitions[k]
50+
buf.WriteString(fmt.Sprintf(` %s -->|%s| %s`,k.src,k.event,v))
51+
buf.WriteString("\n")
52+
}
53+
54+
returnbuf.String()
55+
}
56+
857
// Visualize outputs a visualization of a FSM in Graphviz format.
958
funcVisualize(fsm*FSM)string {
1059
varbuf bytes.Buffer
1160

1261
states:=make(map[string]int)
1362

63+
// we sort the key alphabetically to have a reproducible graph output
64+
sortedEKeys:=make([]eKey,0)
65+
fork:=rangefsm.transitions {
66+
sortedEKeys=append(sortedEKeys,k)
67+
}
68+
sort.Slice(sortedEKeys,func(i,jint)bool {
69+
returnsortedEKeys[i].src<sortedEKeys[j].src
70+
})
71+
1472
buf.WriteString(fmt.Sprintf(`digraph fsm {`))
1573
buf.WriteString("\n")
1674

1775
// make sure the initial state is at top
18-
fork,v:=rangefsm.transitions {
76+
for_,k:=rangesortedEKeys {
77+
v:=fsm.transitions[k]
1978
ifk.src==fsm.current {
2079
states[k.src]++
2180
states[v]++
@@ -24,7 +83,8 @@ func Visualize(fsm *FSM) string {
2483
}
2584
}
2685

27-
fork,v:=rangefsm.transitions {
86+
for_,k:=rangesortedEKeys {
87+
v:=fsm.transitions[k]
2888
ifk.src!=fsm.current {
2989
states[k.src]++
3090
states[v]++
@@ -35,7 +95,15 @@ func Visualize(fsm *FSM) string {
3595

3696
buf.WriteString("\n")
3797

98+
sortedStateKeys:=make([]string,0)
3899
fork:=rangestates {
100+
sortedStateKeys=append(sortedStateKeys,k)
101+
}
102+
sort.Slice(sortedStateKeys,func(i,jint)bool {
103+
returnsortedStateKeys[i]<sortedStateKeys[j]
104+
})
105+
106+
for_,k:=rangesortedStateKeys {
39107
buf.WriteString(fmt.Sprintf(` "%s";`,k))
40108
buf.WriteString("\n")
41109
}

‎utils_test.go‎

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package fsm
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
"testing"
7+
)
8+
9+
funcTestGraphvizOutput(t*testing.T) {
10+
fsmUnderTest:=NewFSM(
11+
"closed",
12+
Events{
13+
{Name:"open",Src: []string{"closed"},Dst:"open"},
14+
{Name:"close",Src: []string{"open"},Dst:"closed"},
15+
{Name:"part-close",Src: []string{"intermediate"},Dst:"closed"},
16+
},
17+
Callbacks{},
18+
)
19+
20+
got:=Visualize(fsmUnderTest)
21+
wanted:=`
22+
digraph fsm {
23+
"closed" -> "open" [ label = "open" ];
24+
"intermediate" -> "closed" [ label = "part-close" ];
25+
"open" -> "closed" [ label = "close" ];
26+
27+
"closed";
28+
"intermediate";
29+
"open";
30+
}`
31+
normalizedGot:=strings.Replace(got,"\n","",-1)
32+
normalizedWanted:=strings.ReplaceAll(wanted,"\n","")
33+
ifnormalizedGot!=normalizedWanted {
34+
t.Errorf("build graphivz graph failed.\nwanted\n%s\nand got\n%s\n",wanted,got)
35+
fmt.Println([]byte(normalizedGot))
36+
fmt.Println([]byte(normalizedWanted))
37+
}
38+
}
39+
40+
funcTestMermaidOutput(t*testing.T) {
41+
fsmUnderTest:=NewFSM(
42+
"closed",
43+
Events{
44+
{Name:"open",Src: []string{"closed"},Dst:"open"},
45+
{Name:"close",Src: []string{"open"},Dst:"closed"},
46+
{Name:"part-close",Src: []string{"intermediate"},Dst:"closed"},
47+
},
48+
Callbacks{},
49+
)
50+
51+
got,err:=VisualizeWithType(fsmUnderTest,MERMAID)
52+
iferr!=nil {
53+
t.Errorf("got error for visualizing with type MERMAID: %s",err)
54+
}
55+
wanted:=`
56+
graph fsm
57+
closed -->|open| open
58+
intermediate -->|part-close| closed
59+
open -->|close| closed
60+
`
61+
normalizedGot:=strings.Replace(got,"\n","",-1)
62+
normalizedWanted:=strings.ReplaceAll(wanted,"\n","")
63+
ifnormalizedGot!=normalizedWanted {
64+
t.Errorf("build mermaid graph failed.\nwanted\n%s\nand got\n%s\n",wanted,got)
65+
fmt.Println([]byte(normalizedGot))
66+
fmt.Println([]byte(normalizedWanted))
67+
}
68+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp