github.com/leanovate/gopter@v0.2.9/commands/example_commands_test.go (about)

     1  package commands_test
     2  
     3  import (
     4  	"github.com/leanovate/gopter"
     5  	"github.com/leanovate/gopter/commands"
     6  	"github.com/leanovate/gopter/gen"
     7  )
     8  
     9  type BuggyCounter struct {
    10  	n int
    11  }
    12  
    13  func (c *BuggyCounter) Inc() {
    14  	c.n++
    15  }
    16  
    17  func (c *BuggyCounter) Dec() {
    18  	if c.n > 3 {
    19  		// Intentional error
    20  		c.n -= 2
    21  	} else {
    22  		c.n--
    23  	}
    24  }
    25  
    26  func (c *BuggyCounter) Get() int {
    27  	return c.n
    28  }
    29  
    30  func (c *BuggyCounter) Reset() {
    31  	c.n = 0
    32  }
    33  
    34  var GetBuggyCommand = &commands.ProtoCommand{
    35  	Name: "GET",
    36  	RunFunc: func(systemUnderTest commands.SystemUnderTest) commands.Result {
    37  		return systemUnderTest.(*BuggyCounter).Get()
    38  	},
    39  	PostConditionFunc: func(state commands.State, result commands.Result) *gopter.PropResult {
    40  		if state.(int) != result.(int) {
    41  			return &gopter.PropResult{Status: gopter.PropFalse}
    42  		}
    43  		return &gopter.PropResult{Status: gopter.PropTrue}
    44  	},
    45  }
    46  
    47  var IncBuggyCommand = &commands.ProtoCommand{
    48  	Name: "INC",
    49  	RunFunc: func(systemUnderTest commands.SystemUnderTest) commands.Result {
    50  		systemUnderTest.(*BuggyCounter).Inc()
    51  		return nil
    52  	},
    53  	NextStateFunc: func(state commands.State) commands.State {
    54  		return state.(int) + 1
    55  	},
    56  }
    57  
    58  var DecBuggyCommand = &commands.ProtoCommand{
    59  	Name: "DEC",
    60  	RunFunc: func(systemUnderTest commands.SystemUnderTest) commands.Result {
    61  		systemUnderTest.(*BuggyCounter).Dec()
    62  		return nil
    63  	},
    64  	NextStateFunc: func(state commands.State) commands.State {
    65  		return state.(int) - 1
    66  	},
    67  }
    68  
    69  var ResetBuggyCommand = &commands.ProtoCommand{
    70  	Name: "RESET",
    71  	RunFunc: func(systemUnderTest commands.SystemUnderTest) commands.Result {
    72  		systemUnderTest.(*BuggyCounter).Reset()
    73  		return nil
    74  	},
    75  	NextStateFunc: func(state commands.State) commands.State {
    76  		return 0
    77  	},
    78  }
    79  
    80  var buggyCounterCommands = &commands.ProtoCommands{
    81  	NewSystemUnderTestFunc: func(initialState commands.State) commands.SystemUnderTest {
    82  		return &BuggyCounter{}
    83  	},
    84  	InitialStateGen: gen.Const(0),
    85  	InitialPreConditionFunc: func(state commands.State) bool {
    86  		return state.(int) == 0
    87  	},
    88  	GenCommandFunc: func(state commands.State) gopter.Gen {
    89  		return gen.OneConstOf(GetBuggyCommand, IncBuggyCommand, DecBuggyCommand, ResetBuggyCommand)
    90  	},
    91  }
    92  
    93  // Demonstrates the usage of the commands package to find a bug in a counter
    94  // implementation that only occurs if the counter is above 3.
    95  //
    96  // The output of this example will be
    97  //  ! buggy counter: Falsified after 45 passed tests.
    98  //  ARG_0: initial=0 sequential=[INC INC INC INC DEC GET]
    99  //  ARG_0_ORIGINAL (9 shrinks): initial=0 sequential=[DEC RESET GET GET GET
   100  //     RESET DEC DEC INC INC RESET RESET DEC INC RESET INC INC GET INC INC DEC
   101  //     DEC GET RESET INC INC DEC INC INC INC RESET RESET INC INC GET INC DEC GET
   102  //     DEC GET INC RESET INC INC RESET]
   103  // I.e. gopter found an invalid state with a rather long sequence of arbitrary
   104  // commands/function calls, and then shrank that sequence down to
   105  //  INC INC INC INC DEC GET
   106  // which is indeed the minimal set of commands one has to perform to find the
   107  // bug.
   108  func Example_buggyCounter() {
   109  	parameters := gopter.DefaultTestParameters()
   110  	parameters.Rng.Seed(1234) // Just for this example to generate reproducible results
   111  
   112  	properties := gopter.NewProperties(parameters)
   113  
   114  	properties.Property("buggy counter", commands.Prop(buggyCounterCommands))
   115  
   116  	// When using testing.T you might just use: properties.TestingRun(t)
   117  	properties.Run(gopter.ConsoleReporter(false))
   118  	// Output:
   119  	// ! buggy counter: Falsified after 43 passed tests.
   120  	// ARG_0: initialState=0 sequential=[INC INC INC INC DEC GET]
   121  	// ARG_0_ORIGINAL (8 shrinks): initialState=0 sequential=[RESET GET GET GET
   122  	//    RESET DEC DEC INC INC RESET RESET DEC INC RESET INC INC GET INC INC DEC
   123  	//    DEC GET RESET INC INC DEC INC INC INC RESET RESET INC INC GET INC DEC GET
   124  	//    DEC GET INC RESET INC INC]
   125  }