internal/mint/qc.go (54 lines of code) (raw):
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package mint
import (
"fmt"
"math/rand"
"os"
"strconv"
"testing/quick"
"time"
"github.com/urso/qcgen"
)
// SetDefaultGenerators sets default generators for use with QuickCheck.
func (t *T) SetDefaultGenerators(fns ...interface{}) {
t.defaultGenerators = fns
}
// QuickCheck runs a quick/check test. The last function passed specifies the
// test to be run. The test function can accept any parameters, but must return
// a bool value. The arguments are generated by random. Custom typed generator
// function of type `func(*rand.Rand) T` can be passed before the function
// under test. A generator with return value T will be used for every argument
// of type T.
// By default the random number generators seed is based on the current
// timestamp. Use the TEST_SEED environment value to configure a static seed value to be used by every test.
// The random number generator is not shared between tests.
func (t *T) QuickCheck(fns ...interface{}) {
L := len(fns)
check, generators := fns[L-1], fns[:L-1]
if len(t.defaultGenerators) > 0 {
if len(generators) > 0 {
tmp := make([]interface{}, len(t.defaultGenerators)+len(generators))
n := copy(tmp, t.defaultGenerators)
copy(tmp[n:], generators)
generators = tmp
} else {
generators = t.defaultGenerators
}
}
seed := qcSeed()
rng := NewRng(seed)
t.Log("quick check rng seed: ", seed)
t.NoError(quick.Check(check, &quick.Config{
Rand: rng,
Values: qcgen.NewGenerator(check, generators...).Gen,
}))
}
func NewRng(seed int64) *rand.Rand {
if seed <= 0 {
seed = qcSeed()
}
return rand.New(rand.NewSource(seed))
}
func RngSeed() int64 {
return qcSeed()
}
func qcSeed() int64 {
v := os.Getenv("TEST_SEED")
if v == "" {
return time.Now().UnixNano()
}
i, err := strconv.ParseInt(v, 10, 64)
if err != nil {
panic(fmt.Errorf("invalid seed '%v': %v", v, err))
}
return i
}