in internal/testutil/statespace/statespace.go [55:98]
func (m *Model[T, TT]) evaluate(fail func(msg string, args ...any)) {
var testCases [][]bool
for i := range 1 << len(m.transitions) {
stack := make([]bool, len(m.transitions))
for j := range m.transitions {
stack[j] = (i>>j)&1 == 1
}
testCases = append(testCases, stack)
}
rand.Shuffle(len(testCases), func(i, j int) { testCases[i], testCases[j] = testCases[j], testCases[i] })
for _, bitmap := range testCases {
var state T
if m.initial != nil {
state = m.initial()
}
// Build the state by applying mutations
for _, i := range rand.Perm(len(bitmap)) {
if bitmap[i] {
state = m.transitions[i].Func(state)
}
}
var stack []string
rand.Shuffle(len(m.invariants), func(i, j int) { m.invariants[i], m.invariants[j] = m.invariants[j], m.invariants[i] })
for _, inv := range m.invariants {
if inv.Assert(state, m.subject(state)) {
continue
}
// Defer building the stack strings to avoid allocating the memory for passing tests
if stack == nil {
for i, enabled := range bitmap {
if enabled {
stack = append(stack, m.transitions[i].Name)
}
}
}
fail("invariant '%s' failed with mutation stack: [%s]", inv.Name, strings.Join(stack, ", "))
}
}
}