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  }