blob: 5297de66d5a927e69ad77eac99b997103d06bc01 [file] [log] [blame]
// Copyright 2015 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
package cover
import (
"math/rand"
"reflect"
"sort"
"testing"
"time"
)
func initTest(t *testing.T) (*rand.Rand, int) {
iters := 100000
if testing.Short() {
iters = 1000
}
seed := int64(time.Now().UnixNano())
rs := rand.NewSource(seed)
t.Logf("seed=%v", seed)
return rand.New(rs), iters
}
type Test struct {
V0 Cover
V1 Cover
R Cover
}
func runTest(t *testing.T, f func(Cover, Cover) Cover, sorted, symmetric bool, tests []Test) {
if symmetric {
for _, test := range tests {
tests = append(tests, Test{test.V1, test.V0, test.R})
}
}
tests = append(tests, Test{Cover{}, Cover{}, Cover{}})
for _, test := range tests {
if sorted {
if !sort.IsSorted(test.V0) {
t.Fatalf("input is not sorted: %+v", test.V0)
}
if !sort.IsSorted(test.V1) {
t.Fatalf("input is not sorted: %+v", test.V1)
}
}
if !sort.IsSorted(test.R) {
t.Fatalf("golden is not sorted: %+v", test.R)
}
res := f(test.V0, test.V1)
if !sort.IsSorted(res) {
t.Fatalf("output is not sorted: %+v", res)
}
if (len(res) != 0 || len(test.R) != 0) && !reflect.DeepEqual(res, test.R) {
t.Fatalf("f(%+v, %+v) = %+v (expect: %+v)", test.V0, test.V1, res, test.R)
}
}
}
func TestCanonicalize(t *testing.T) {
runTest(t, func(c0, c1 Cover) Cover { return Canonicalize([]uint32(c0)) }, false, false, []Test{
{Cover{1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 6}, Cover{}, Cover{1, 2, 3, 4, 5, 6}},
{Cover{6, 2, 3, 4, 5, 1}, Cover{}, Cover{1, 2, 3, 4, 5, 6}},
{Cover{6, 1, 2, 6, 3, 3, 4, 5, 1}, Cover{}, Cover{1, 2, 3, 4, 5, 6}},
})
}
func TestDifference(t *testing.T) {
runTest(t, Difference, true, false, []Test{
{Cover{1, 2, 3, 4, 5, 6}, Cover{}, Cover{1, 2, 3, 4, 5, 6}},
{Cover{1, 2, 3, 4, 5, 6}, Cover{3}, Cover{1, 2, 4, 5, 6}},
{Cover{1, 2, 3, 4, 5, 6}, Cover{1, 6}, Cover{2, 3, 4, 5}},
{Cover{1, 2, 3, 4, 5, 6}, Cover{0, 10}, Cover{1, 2, 3, 4, 5, 6}},
{Cover{1, 2, 3, 4, 5, 6}, Cover{0, 3, 6}, Cover{1, 2, 4, 5}},
})
}
func TestSymmetricDifference(t *testing.T) {
runTest(t, SymmetricDifference, true, true, []Test{
{Cover{1, 2, 3, 4, 5, 6}, Cover{}, Cover{1, 2, 3, 4, 5, 6}},
{Cover{1, 2, 3, 4, 5, 6}, Cover{1, 2, 3, 4, 5, 6}, Cover{}},
{Cover{1, 2, 3, 4, 5, 6}, Cover{2, 4, 6}, Cover{1, 3, 5}},
{Cover{2, 4, 6}, Cover{1, 3, 5}, Cover{1, 2, 3, 4, 5, 6}},
})
}
func TestUnion(t *testing.T) {
runTest(t, Union, true, true, []Test{
{Cover{1, 2, 3, 4, 5, 6}, Cover{}, Cover{1, 2, 3, 4, 5, 6}},
{Cover{1, 2, 3, 4, 5, 6}, Cover{1, 2, 3, 4, 5, 6}, Cover{1, 2, 3, 4, 5, 6}},
{Cover{1, 3, 5}, Cover{2, 4, 6}, Cover{1, 2, 3, 4, 5, 6}},
{Cover{1, 2, 3, 5}, Cover{2, 4, 5, 6}, Cover{1, 2, 3, 4, 5, 6}},
})
}
func TestIntersection(t *testing.T) {
runTest(t, Intersection, true, true, []Test{
{Cover{1, 2, 3, 4, 5, 6}, Cover{}, Cover{}},
{Cover{1, 2, 3}, Cover{4, 5, 6}, Cover{}},
{Cover{1, 2, 3}, Cover{2, 3, 5}, Cover{2, 3}},
})
}
func TestMinimize(t *testing.T) {
tests := []struct {
inp []Cover
out []int
}{
// Take all.
{
[]Cover{
{1, 2, 3},
{4, 5, 6},
{7, 8, 9},
},
[]int{0, 1, 2},
},
// Take one.
{
[]Cover{
{1, 2, 3, 4, 5, 6, 7, 8, 9},
{1},
{2, 3, 4, 5},
{6, 7, 8},
},
[]int{0},
},
// Take two.
{
[]Cover{
{1, 2, 3, 4, 5, 6, 7, 8, 9},
{1},
{2, 3, 4, 5},
{10},
},
[]int{0, 3},
},
// Take another two.
{
[]Cover{
{1, 2, 3, 4},
{1, 2},
{3, 4, 5, 6, 7},
{3, 7},
},
[]int{2, 0},
},
// Take the largest one.
{
[]Cover{
{1, 2},
{1, 2, 3, 4, 5},
{3, 4, 5},
},
[]int{1},
},
}
for _, test := range tests {
res := Minimize(test.inp)
if !reflect.DeepEqual(res, test.out) {
t.Logf("corpus:")
for _, in := range test.inp {
t.Logf(" %+v", in)
}
t.Fatalf("expect: %+v, got: %+v", test.out, res)
}
}
}
func randCover(rnd *rand.Rand, maxLen int) Cover {
tmp := make(Cover, rnd.Intn(maxLen))
for j := range tmp {
tmp[j] = uint32(rnd.Intn(100))
}
return Canonicalize(tmp)
}
func TestMinimizeRandom(t *testing.T) {
rnd, iters := initTest(t)
for i := 0; i < iters; i++ {
n := rnd.Intn(20)
cov := make([]Cover, n)
for i := range cov {
cov[i] = randCover(rnd, 10)
}
var total Cover
for _, c := range cov {
total = Union(total, c)
}
mini := Minimize(cov)
var minimized Cover
for _, idx := range mini {
minimized = Union(minimized, cov[idx])
}
if !reflect.DeepEqual(total, minimized) {
t.Logf("minimized %v -> %v", len(cov), len(mini))
t.Logf("corpus:")
for _, in := range cov {
t.Logf(" %+v", in)
}
t.Logf("minimized:")
for _, in := range cov {
t.Logf(" %+v", in)
}
t.Fatalf("better luck next time")
}
}
}
func TestHasDifference(t *testing.T) {
rnd, iters := initTest(t)
for i := 0; i < iters; i++ {
cov1 := randCover(rnd, 20)
cov2 := randCover(rnd, 20)
diff := Difference(cov1, cov2)
hasDiff := HasDifference(cov1, cov2)
if len(diff) != 0 != hasDiff {
t.Fatalf("cov1=%+v cov2=%+v diff=%+v hasDiff=%v", cov1, cov2, diff, hasDiff)
}
}
}
func BenchmarkHasDifference(b *testing.B) {
rnd := rand.New(rand.NewSource(0))
cov0 := make(Cover, 70000)
for i := range cov0 {
cov0[i] = uint32(rnd.Intn(1 << 30))
}
cov1 := Canonicalize(append(Cover{}, cov0[:500]...))
cov0 = Canonicalize(cov0)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = HasDifference(cov1, cov0)
}
}