Skip to content

Instantly share code, notes, and snippets.

@vporoshok
Created June 11, 2018 18:28
Show Gist options
  • Save vporoshok/f83f41665ea0981df7aa8111b6b43c21 to your computer and use it in GitHub Desktop.
Save vporoshok/f83f41665ea0981df7aa8111b6b43c21 to your computer and use it in GitHub Desktop.
package coverage
import (
"bytes"
"encoding/binary"
"testing"
"github.com/leanovate/gopter"
"github.com/leanovate/gopter/prop"
)
func TestCoverageProperties(t *testing.T) {
properties := gopter.NewProperties(nil)
properties.Property("Output is a coverage", prop.ForAll(
func(coverage [][]uint32) bool {
universe := universeOfCoverage(coverage)
result := universeOfCoverage(GetMinimalSubcoverage(coverage))
for item := range universe {
if _, ok := result[item]; !ok {
return false
}
}
return true
},
CoverageGen(20, 20),
))
properties.Property("Length of output less or equal length of input", prop.ForAll(
func(coverage [][]uint32) bool {
result := GetMinimalSubcoverage(coverage)
return len(coverage) >= len(result)
},
CoverageGen(200, 200),
))
properties.Property("Every output set must be in input", prop.ForAll(
func(coverage [][]uint32) bool {
coverageAsBytes := coverageToBytes(coverage)
result := GetMinimalSubcoverage(coverage)
for _, set := range result {
if !isInCoverage(set, coverageAsBytes) {
t.Log(set)
return false
}
}
return true
},
CoverageGen(200, 200),
))
properties.TestingRun(t)
}
func universeOfCoverage(coverage [][]uint32) map[uint32]struct{} {
universe := map[uint32]struct{}{}
for _, set := range coverage {
for _, item := range set {
universe[item] = struct{}{}
}
}
return universe
}
func coverageToBytes(coverage [][]uint32) [][]byte {
res := make([][]byte, len(coverage))
for i := range res {
res[i] = setToBytes(coverage[i])
}
return res
}
func isInCoverage(set []uint32, coverageAsBytes [][]byte) bool {
setAsBytes := setToBytes(set)
for _, item := range coverageAsBytes {
if bytes.Equal(setAsBytes, item) {
return true
}
}
return false
}
func setToBytes(set []uint32) []byte {
buf := bytes.Buffer{}
binary.Write(&buf, binary.LittleEndian, set)
return buf.Bytes()
}
func CoverageGen(mod uint32, count uint32) gopter.Gen {
return func(params *gopter.GenParameters) *gopter.GenResult {
coverage := make([][]uint32, count)
for i := range coverage {
n := int(uint64(mod/3) + params.NextUint64()%uint64(mod/3))
set := make(map[uint32]struct{}, n)
coverage[i] = make([]uint32, 0, n)
for len(set) < n {
x := uint32(params.NextUint64() % uint64(mod))
if _, ok := set[x]; !ok {
coverage[i] = append(coverage[i], x)
set[x] = struct{}{}
}
}
}
return gopter.NewGenResult(coverage, CoverageShrinker)
}
}
type coverageShrink struct {
coverage [][]uint32
}
func CoverageShrinker(coverage interface{}) gopter.Shrink {
shrink := coverageShrink{coverage.([][]uint32)}
return shrink.Next
}
func (cs *coverageShrink) Next() (interface{}, bool) {
cs.coverage = cs.coverage[:len(cs.coverage)/2]
if len(cs.coverage) == 0 {
return nil, false
}
return cs.coverage, true
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment