github.com/leanovate/gopter@v0.2.9/prop.go (about) 1 package gopter 2 3 import ( 4 "fmt" 5 "math" 6 "runtime/debug" 7 ) 8 9 // Prop represent some kind of property that (drums please) can and should be checked 10 type Prop func(*GenParameters) *PropResult 11 12 // SaveProp creates s save property by handling all panics from an inner property 13 func SaveProp(prop Prop) Prop { 14 return func(genParams *GenParameters) (result *PropResult) { 15 defer func() { 16 if r := recover(); r != nil { 17 result = &PropResult{ 18 Status: PropError, 19 Error: fmt.Errorf("Check paniced: %v", r), 20 ErrorStack: debug.Stack(), 21 } 22 } 23 }() 24 25 return prop(genParams) 26 } 27 } 28 29 // Check the property using specific parameters 30 func (prop Prop) Check(parameters *TestParameters) *TestResult { 31 iterations := math.Ceil(float64(parameters.MinSuccessfulTests) / float64(parameters.Workers)) 32 sizeStep := float64(parameters.MaxSize-parameters.MinSize) / (iterations * float64(parameters.Workers)) 33 34 genParameters := GenParameters{ 35 MinSize: parameters.MinSize, 36 MaxSize: parameters.MaxSize, 37 MaxShrinkCount: parameters.MaxShrinkCount, 38 Rng: parameters.Rng, 39 } 40 runner := &runner{ 41 parameters: parameters, 42 worker: func(workerIdx int, shouldStop shouldStop) *TestResult { 43 var n int 44 var d int 45 46 isExhaused := func() bool { 47 return n+d > parameters.MinSuccessfulTests && 48 1.0+float64(parameters.Workers*n)*parameters.MaxDiscardRatio < float64(d) 49 } 50 51 for !shouldStop() && n < int(iterations) { 52 size := float64(parameters.MinSize) + (sizeStep * float64(workerIdx+(parameters.Workers*(n+d)))) 53 propResult := prop(genParameters.WithSize(int(size))) 54 55 switch propResult.Status { 56 case PropUndecided: 57 d++ 58 if isExhaused() { 59 return &TestResult{ 60 Status: TestExhausted, 61 Succeeded: n, 62 Discarded: d, 63 } 64 } 65 case PropTrue: 66 n++ 67 case PropProof: 68 n++ 69 return &TestResult{ 70 Status: TestProved, 71 Succeeded: n, 72 Discarded: d, 73 Labels: propResult.Labels, 74 Args: propResult.Args, 75 } 76 case PropFalse: 77 return &TestResult{ 78 Status: TestFailed, 79 Succeeded: n, 80 Discarded: d, 81 Labels: propResult.Labels, 82 Args: propResult.Args, 83 } 84 case PropError: 85 return &TestResult{ 86 Status: TestError, 87 Succeeded: n, 88 Discarded: d, 89 Labels: propResult.Labels, 90 Error: propResult.Error, 91 ErrorStack: propResult.ErrorStack, 92 Args: propResult.Args, 93 } 94 } 95 } 96 97 if isExhaused() { 98 return &TestResult{ 99 Status: TestExhausted, 100 Succeeded: n, 101 Discarded: d, 102 } 103 } 104 return &TestResult{ 105 Status: TestPassed, 106 Succeeded: n, 107 Discarded: d, 108 } 109 }, 110 } 111 112 return runner.runWorkers() 113 }