Guides
Document a state machine
Add a state table, a transition table and an SVG diagram of a state machine. They come from the calls that your tests make.
v2/machine/machine.go
type LampState uint8const (
// LampOff gives no light.
LampOff LampState = iota
// LampOn gives light.
LampOn
// LampBroken never gives light again.
LampBroken
)func (l *Lamp) State() LampState { return l.state }func (l *Lamp) Start(now time.Duration) error {
if l.state == LampOn {
return ErrBusy
}
if l.state == LampOff {
l.state, l.until = LampOn, now+l.wait
}
return nil
}func (l *Lamp) Stop() error {
if l.state != LampOn {
return ErrOff
}
l.off()
return nil
}func (l *Lamp) Tick(now time.Duration) {
if l.state == LampOn && now >= l.until {
l.off()
}
}func (l *Lamp) Break() { l.state = LampBroken }func (l *Lamp) off() { l.state = LampOff }v2/machine/machine_test.go
func TestLamp(t *testing.T) {
l, err := NewLamp(Config{})
if err != nil {
t.Fatal(err)
}
_ = l.Start(0)
l.Tick(DefaultWait)
_ = l.Start(0)
_ = l.Stop()
l.Break()
}docs/machines/guide-states.md
Before
# The lamp
<!-- docgen:states pkg=machine type=Lamp -->
<!-- /docgen:states -->
After
# The lamp
<!-- docgen:states pkg=machine type=Lamp -->
States of [`Lamp`](https://pkg.go.dev/github.com/USA-RedDragon/docgen/v2/machine#Lamp), from [`Lamp.State`](https://pkg.go.dev/github.com/USA-RedDragon/docgen/v2/machine#Lamp.State):
| State | Meaning | Seen in tests |
|---|---|---|
| [`LampOff`](https://pkg.go.dev/github.com/USA-RedDragon/docgen/v2/machine#LampOff) | LampOff gives no light. | yes, first state |
| [`LampOn`](https://pkg.go.dev/github.com/USA-RedDragon/docgen/v2/machine#LampOn) | LampOn gives light. | yes |
| [`LampBroken`](https://pkg.go.dev/github.com/USA-RedDragon/docgen/v2/machine#LampBroken) | LampBroken never gives light again. | yes |
Transitions seen in tests:
| From | Method call | To |
|---|---|---|
| LampOff | `Start` | LampOn |
| LampOff | `Break` | LampBroken |
| LampOn | `Stop`, `Tick` | LampOff |

<!-- /docgen:states -->
Preview
The lamp
States of Lamp, from Lamp.State:
| State | Meaning | Seen in tests |
|---|---|---|
LampOff |
LampOff gives no light. | yes, first state |
LampOn |
LampOn gives light. | yes |
LampBroken |
LampBroken never gives light again. | yes |
Transitions seen in tests:
| From | Method call | To |
|---|---|---|
| LampOff | Start |
LampOn |
| LampOff | Break |
LampBroken |
| LampOn | Stop, Tick |
LampOff |
For all options, see docgen:states.
Commit the diagram with the page. It goes in states/<pkg>-<type>.svg next to the page. For another place, add diagram=<path>, relative to the page.
Requirements§
- A type with exported methods that have pointer receivers. Generic types are not supported.
- A way to read the state: a
Statemethod, or methods that return aboolor a(value, bool). - Tests that drive the machine.
When a transition is missing§
A transition that no test makes is not in the table. Add a test. The state table lists each state that no test reached, so a gap is easy to see.
Slow tests§
Add run=<regexp> to limit the tests, as go test -run does. It applies only when each docgen:states marker of the package has one.
v2/door/door.go
// Package door is a state machine with its own tests, for the run= argument.
package door
// State is the state of a Door.
type State uint8
// The State values.
const (
// StateClosed is shut.
StateClosed State = iota
// StateOpen is open.
StateOpen
)
// Door opens and closes.
type Door struct{ state State }
// State returns the state of the Door.
func (d *Door) State() State { return d.state }
// Open opens the Door.
func (d *Door) Open() { d.state = StateOpen }
// Close closes the Door.
func (d *Door) Close() { d.state = StateClosed }v2/door/door_test.go
func TestOpen(t *testing.T) {
var d Door
d.Open()
}docs/machines/guide-states-run.md
Before
<!-- docgen:states pkg=door type=Door run=TestOpen diagram=states/door-open.svg -->
<!-- /docgen:states -->
After
<!-- docgen:states pkg=door type=Door run=TestOpen diagram=states/door-open.svg -->
States of [`Door`](https://pkg.go.dev/github.com/USA-RedDragon/docgen/v2/door#Door), from [`Door.State`](https://pkg.go.dev/github.com/USA-RedDragon/docgen/v2/door#Door.State):
| State | Meaning | Seen in tests |
|---|---|---|
| [`StateClosed`](https://pkg.go.dev/github.com/USA-RedDragon/docgen/v2/door#StateClosed) | StateClosed is shut. | yes, first state |
| [`StateOpen`](https://pkg.go.dev/github.com/USA-RedDragon/docgen/v2/door#StateOpen) | StateOpen is open. | yes |
Transitions seen in tests:
| From | Method call | To |
|---|---|---|
| StateClosed | `Open` | StateOpen |

<!-- /docgen:states -->
Preview
States of Door, from Door.State:
| State | Meaning | Seen in tests |
|---|---|---|
StateClosed |
StateClosed is shut. | yes, first state |
StateOpen |
StateOpen is open. | yes |
Transitions seen in tests:
| From | Method call | To |
|---|---|---|
| StateClosed | Open |
StateOpen |
For the exact rules, see How docgen works.
Source: docs/guides/state-machines.md