blob: 41635299ce4bb85328f0de67642f6e6eb401fc7d [file] [log] [blame]
mpagenkobb47bc22021-04-20 13:29:09 +00001package fsm
2
3import (
4 "bytes"
5 "fmt"
6)
7
8// Visualize outputs a visualization of a FSM in Graphviz format.
9func Visualize(fsm *FSM) string {
10 var buf bytes.Buffer
11
12 // we sort the key alphabetically to have a reproducible graph output
13 sortedEKeys := getSortedTransitionKeys(fsm.transitions)
14 sortedStateKeys, _ := getSortedStates(fsm.transitions)
15
16 writeHeaderLine(&buf)
17 writeTransitions(&buf, fsm.current, sortedEKeys, fsm.transitions)
18 writeStates(&buf, sortedStateKeys)
19 writeFooter(&buf)
20
21 return buf.String()
22}
23
24func writeHeaderLine(buf *bytes.Buffer) {
25 buf.WriteString(fmt.Sprintf(`digraph fsm {`))
26 buf.WriteString("\n")
27}
28
29func writeTransitions(buf *bytes.Buffer, current string, sortedEKeys []eKey, transitions map[eKey]string) {
30 // make sure the current state is at top
31 for _, k := range sortedEKeys {
32 if k.src == current {
33 v := transitions[k]
34 buf.WriteString(fmt.Sprintf(` "%s" -> "%s" [ label = "%s" ];`, k.src, v, k.event))
35 buf.WriteString("\n")
36 }
37 }
38 for _, k := range sortedEKeys {
39 if k.src != current {
40 v := transitions[k]
41 buf.WriteString(fmt.Sprintf(` "%s" -> "%s" [ label = "%s" ];`, k.src, v, k.event))
42 buf.WriteString("\n")
43 }
44 }
45
46 buf.WriteString("\n")
47}
48
49func writeStates(buf *bytes.Buffer, sortedStateKeys []string) {
50 for _, k := range sortedStateKeys {
51 buf.WriteString(fmt.Sprintf(` "%s";`, k))
52 buf.WriteString("\n")
53 }
54}
55
56func writeFooter(buf *bytes.Buffer) {
57 buf.WriteString(fmt.Sprintln("}"))
58}