File: commands.go

package info (click to toggle)
golang-github-leanovate-gopter 0.2.9%2Bgit20210201.bbbf00e-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 696 kB
  • sloc: makefile: 37
file content (84 lines) | stat: -rw-r--r-- 2,989 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package commands

import (
	"reflect"

	"github.com/leanovate/gopter"
	"github.com/leanovate/gopter/gen"
	"github.com/leanovate/gopter/prop"
)

// Commands provide an entry point for testing a stateful system
type Commands interface {
	// NewSystemUnderTest should create a new/isolated system under test
	NewSystemUnderTest(initialState State) SystemUnderTest
	// DestroySystemUnderTest may perform any cleanup tasks to destroy a system
	DestroySystemUnderTest(SystemUnderTest)
	// GenInitialState provides a generator for the initial State.
	// IMPORTANT: The generated state itself may be mutable, but this generator
	// is supposed to generate a clean and reproductable state every time.
	// Do not use an external random generator and be especially vary about
	// `gen.Const(<pointer to some mutable struct>)`.
	GenInitialState() gopter.Gen
	// GenCommand provides a generator for applicable commands to for a state
	GenCommand(state State) gopter.Gen
	// InitialPreCondition checks if the initial state is valid
	InitialPreCondition(state State) bool
}

// ProtoCommands is a prototype implementation of the Commands interface
type ProtoCommands struct {
	NewSystemUnderTestFunc     func(initialState State) SystemUnderTest
	DestroySystemUnderTestFunc func(SystemUnderTest)
	InitialStateGen            gopter.Gen
	GenCommandFunc             func(State) gopter.Gen
	InitialPreConditionFunc    func(State) bool
}

// NewSystemUnderTest should create a new/isolated system under test
func (p *ProtoCommands) NewSystemUnderTest(initialState State) SystemUnderTest {
	if p.NewSystemUnderTestFunc != nil {
		return p.NewSystemUnderTestFunc(initialState)
	}
	return nil
}

// DestroySystemUnderTest may perform any cleanup tasks to destroy a system
func (p *ProtoCommands) DestroySystemUnderTest(systemUnderTest SystemUnderTest) {
	if p.DestroySystemUnderTestFunc != nil {
		p.DestroySystemUnderTestFunc(systemUnderTest)
	}
}

// GenCommand provides a generator for applicable commands to for a state
func (p *ProtoCommands) GenCommand(state State) gopter.Gen {
	if p.GenCommandFunc != nil {
		return p.GenCommandFunc(state)
	}
	return gen.Fail(reflect.TypeOf((*Command)(nil)).Elem())
}

// GenInitialState provides a generator for the initial State
func (p *ProtoCommands) GenInitialState() gopter.Gen {
	return p.InitialStateGen.SuchThat(func(state State) bool {
		return p.InitialPreCondition(state)
	})
}

// InitialPreCondition checks if the initial state is valid
func (p *ProtoCommands) InitialPreCondition(state State) bool {
	if p.InitialPreConditionFunc != nil {
		return p.InitialPreConditionFunc(state)
	}
	return true
}

// Prop creates a gopter.Prop from Commands
func Prop(commands Commands) gopter.Prop {
	return prop.ForAll(func(actions *actions) *gopter.PropResult {
		systemUnderTest := commands.NewSystemUnderTest(actions.initialStateProvider())
		defer commands.DestroySystemUnderTest(systemUnderTest)

		return actions.run(systemUnderTest)
	}, genActions(commands))
}