| // Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com> |
| // All rights reserved. |
| // |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package testutil |
| |
| import ( |
| "bytes" |
| "flag" |
| "math/rand" |
| "reflect" |
| "sync" |
| |
| "github.com/onsi/ginkgo/config" |
| |
| "github.com/syndtr/goleveldb/leveldb/comparer" |
| ) |
| |
| var ( |
| runfn = make(map[string][]func()) |
| runmu sync.Mutex |
| ) |
| |
| func Defer(args ...interface{}) bool { |
| var ( |
| group string |
| fn func() |
| ) |
| for _, arg := range args { |
| v := reflect.ValueOf(arg) |
| switch v.Kind() { |
| case reflect.String: |
| group = v.String() |
| case reflect.Func: |
| r := reflect.ValueOf(&fn).Elem() |
| r.Set(v) |
| } |
| } |
| if fn != nil { |
| runmu.Lock() |
| runfn[group] = append(runfn[group], fn) |
| runmu.Unlock() |
| } |
| return true |
| } |
| |
| func RunDefer(groups ...string) bool { |
| if len(groups) == 0 { |
| groups = append(groups, "") |
| } |
| runmu.Lock() |
| var runfn_ []func() |
| for _, group := range groups { |
| runfn_ = append(runfn_, runfn[group]...) |
| delete(runfn, group) |
| } |
| runmu.Unlock() |
| for _, fn := range runfn_ { |
| fn() |
| } |
| return runfn_ != nil |
| } |
| |
| func RandomSeed() int64 { |
| if !flag.Parsed() { |
| panic("random seed not initialized") |
| } |
| return config.GinkgoConfig.RandomSeed |
| } |
| |
| func NewRand() *rand.Rand { |
| return rand.New(rand.NewSource(RandomSeed())) |
| } |
| |
| var cmp = comparer.DefaultComparer |
| |
| func BytesSeparator(a, b []byte) []byte { |
| if bytes.Equal(a, b) { |
| return b |
| } |
| i, n := 0, len(a) |
| if n > len(b) { |
| n = len(b) |
| } |
| for ; i < n && (a[i] == b[i]); i++ { |
| } |
| x := append([]byte{}, a[:i]...) |
| if i < n { |
| if c := a[i] + 1; c < b[i] { |
| return append(x, c) |
| } |
| x = append(x, a[i]) |
| i++ |
| } |
| for ; i < len(a); i++ { |
| if c := a[i]; c < 0xff { |
| return append(x, c+1) |
| } else { |
| x = append(x, c) |
| } |
| } |
| if len(b) > i && b[i] > 0 { |
| return append(x, b[i]-1) |
| } |
| return append(x, 'x') |
| } |
| |
| func BytesAfter(b []byte) []byte { |
| var x []byte |
| for _, c := range b { |
| if c < 0xff { |
| return append(x, c+1) |
| } else { |
| x = append(x, c) |
| } |
| } |
| return append(x, 'x') |
| } |
| |
| func RandomIndex(rnd *rand.Rand, n, round int, fn func(i int)) { |
| if rnd == nil { |
| rnd = NewRand() |
| } |
| for x := 0; x < round; x++ { |
| fn(rnd.Intn(n)) |
| } |
| return |
| } |
| |
| func ShuffledIndex(rnd *rand.Rand, n, round int, fn func(i int)) { |
| if rnd == nil { |
| rnd = NewRand() |
| } |
| for x := 0; x < round; x++ { |
| for _, i := range rnd.Perm(n) { |
| fn(i) |
| } |
| } |
| return |
| } |
| |
| func RandomRange(rnd *rand.Rand, n, round int, fn func(start, limit int)) { |
| if rnd == nil { |
| rnd = NewRand() |
| } |
| for x := 0; x < round; x++ { |
| start := rnd.Intn(n) |
| length := 0 |
| if j := n - start; j > 0 { |
| length = rnd.Intn(j) |
| } |
| fn(start, start+length) |
| } |
| return |
| } |
| |
| func Max(x, y int) int { |
| if x > y { |
| return x |
| } |
| return y |
| } |
| |
| func Min(x, y int) int { |
| if x < y { |
| return x |
| } |
| return y |
| } |