2015-07-26 16:44:51 +02:00
|
|
|
// Copyright 2014, 2015 by Sascha L. Teichmann
|
2014-08-19 11:12:35 +02:00
|
|
|
// Use of this source code is governed by the MIT license
|
|
|
|
// that can be found in the LICENSE file.
|
|
|
|
|
2014-08-18 16:29:17 +02:00
|
|
|
package common
|
|
|
|
|
2014-09-06 19:54:53 +02:00
|
|
|
import (
|
|
|
|
"math/rand"
|
|
|
|
"testing"
|
|
|
|
)
|
2014-08-18 16:29:17 +02:00
|
|
|
|
|
|
|
var data = []int16{
|
|
|
|
-2045, -1850, -1811, -1629, -1104,
|
|
|
|
-967, -725, -646, -329, -212,
|
2014-08-18 18:01:34 +02:00
|
|
|
-150, -1, 0, 1, 88, 524, 527, 549,
|
2014-08-18 16:29:17 +02:00
|
|
|
1783, 1817, 1826, 2028, 2032}
|
|
|
|
|
2014-08-18 21:33:58 +02:00
|
|
|
func allData(f func(Coord)) {
|
2014-08-18 16:29:17 +02:00
|
|
|
for _, z := range data {
|
|
|
|
for _, y := range data {
|
|
|
|
for _, x := range data {
|
2014-08-18 21:33:58 +02:00
|
|
|
f(Coord{X: x, Y: y, Z: z})
|
2014-08-18 16:29:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-18 18:01:34 +02:00
|
|
|
func checkEncodeDecode(
|
|
|
|
desc string,
|
|
|
|
join KeyJoiner,
|
|
|
|
encode KeyEncoder, decode KeyDecoder,
|
2014-08-18 21:33:58 +02:00
|
|
|
c Coord, t *testing.T) {
|
2014-08-18 18:01:34 +02:00
|
|
|
|
2014-08-18 21:33:58 +02:00
|
|
|
k1 := join(c)
|
2014-08-18 18:01:34 +02:00
|
|
|
var err error
|
|
|
|
var b []byte
|
|
|
|
if b, err = encode(k1); err != nil {
|
2014-08-18 21:33:58 +02:00
|
|
|
t.Errorf("%s: Failed to encode %s %s\n", desc, c, err)
|
2014-08-18 18:01:34 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
var k2 int64
|
|
|
|
if k2, err = decode(b); err != nil {
|
2014-08-18 21:33:58 +02:00
|
|
|
t.Errorf("%s: Failed to decode %s %s\n", desc, c, err)
|
2014-08-18 18:01:34 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if k1 != k2 {
|
2014-08-18 21:33:58 +02:00
|
|
|
t.Errorf("%s: Expected %d got %d for %s\n", desc, k1, k2, c)
|
2014-08-18 18:01:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestEncodeDecode(t *testing.T) {
|
2014-08-18 21:33:58 +02:00
|
|
|
allData(func(c Coord) {
|
2014-08-18 18:01:34 +02:00
|
|
|
checkEncodeDecode(
|
2014-08-19 11:12:35 +02:00
|
|
|
"Big endian - interleaved",
|
2014-08-18 21:33:58 +02:00
|
|
|
CoordToInterleaved,
|
2014-08-18 18:01:34 +02:00
|
|
|
EncodeToBigEndian, DecodeFromBigEndian,
|
2014-08-18 21:33:58 +02:00
|
|
|
c, t)
|
2014-08-18 18:01:34 +02:00
|
|
|
})
|
2014-08-18 21:33:58 +02:00
|
|
|
allData(func(c Coord) {
|
2014-08-18 18:01:34 +02:00
|
|
|
checkEncodeDecode(
|
2014-08-19 11:12:35 +02:00
|
|
|
"String - interleaved",
|
2014-08-18 21:33:58 +02:00
|
|
|
CoordToInterleaved,
|
2014-08-18 18:01:34 +02:00
|
|
|
EncodeStringToBytes, DecodeStringFromBytes,
|
2014-08-18 21:33:58 +02:00
|
|
|
c, t)
|
2014-08-18 18:01:34 +02:00
|
|
|
})
|
2014-08-19 11:12:35 +02:00
|
|
|
allData(func(c Coord) {
|
|
|
|
checkEncodeDecode(
|
|
|
|
"Big endian - plain",
|
|
|
|
CoordToPlain,
|
|
|
|
EncodeToBigEndian, DecodeFromBigEndian,
|
|
|
|
c, t)
|
|
|
|
})
|
|
|
|
allData(func(c Coord) {
|
|
|
|
checkEncodeDecode(
|
|
|
|
"String - plain",
|
|
|
|
CoordToPlain,
|
|
|
|
EncodeStringToBytes, DecodeStringFromBytes,
|
|
|
|
c, t)
|
|
|
|
})
|
2014-08-18 18:01:34 +02:00
|
|
|
}
|
|
|
|
|
2014-08-18 16:29:17 +02:00
|
|
|
func checkJoinSplit(
|
|
|
|
desc string,
|
|
|
|
join KeyJoiner, split KeySplitter,
|
2014-08-18 21:33:58 +02:00
|
|
|
c Coord, t *testing.T) {
|
2014-08-18 16:29:17 +02:00
|
|
|
|
2014-08-18 21:33:58 +02:00
|
|
|
k := join(c)
|
|
|
|
s := split(k)
|
2014-09-07 09:58:09 +02:00
|
|
|
if s != c {
|
2014-08-18 21:33:58 +02:00
|
|
|
t.Errorf("%s: Expected %s got %s %b\n", desc, c, s, k)
|
2014-08-18 16:29:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestJoinSplit(t *testing.T) {
|
2014-08-18 21:33:58 +02:00
|
|
|
allData(func(c Coord) {
|
2014-08-18 16:29:17 +02:00
|
|
|
checkJoinSplit(
|
2014-08-18 21:33:58 +02:00
|
|
|
"P2C(C2P(xyz))",
|
|
|
|
CoordToPlain, PlainToCoord,
|
|
|
|
c, t)
|
2014-08-18 16:29:17 +02:00
|
|
|
})
|
2014-08-18 21:33:58 +02:00
|
|
|
allData(func(c Coord) {
|
2014-08-18 16:29:17 +02:00
|
|
|
checkJoinSplit(
|
2014-08-18 21:33:58 +02:00
|
|
|
"I2C(C2I(xyz))",
|
|
|
|
CoordToInterleaved, InterleavedToCoord,
|
|
|
|
c, t)
|
2014-08-18 16:29:17 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func checkTransformer(
|
|
|
|
desc string, joiner KeyJoiner,
|
|
|
|
transform KeyTransformer,
|
2014-08-18 21:33:58 +02:00
|
|
|
c Coord, t *testing.T) {
|
2014-08-18 16:29:17 +02:00
|
|
|
|
2014-08-18 21:33:58 +02:00
|
|
|
k1 := joiner(c)
|
2014-08-18 16:29:17 +02:00
|
|
|
k2 := transform(k1)
|
|
|
|
if k2 != k1 {
|
2014-08-18 21:33:58 +02:00
|
|
|
t.Errorf("%s: Expected %v got %v for %s\n", desc, k1, k2, c)
|
2014-08-18 16:29:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func compose(transforms ...KeyTransformer) KeyTransformer {
|
|
|
|
return func(x int64) int64 {
|
|
|
|
for _, transform := range transforms {
|
|
|
|
x = transform(x)
|
|
|
|
}
|
|
|
|
return x
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTransforms(t *testing.T) {
|
|
|
|
// Mainly to check the test itself.
|
2014-08-18 21:33:58 +02:00
|
|
|
allData(func(c Coord) {
|
2014-08-18 16:29:17 +02:00
|
|
|
checkTransformer(
|
|
|
|
"plain",
|
2014-08-18 21:33:58 +02:00
|
|
|
CoordToPlain,
|
2014-08-18 16:29:17 +02:00
|
|
|
compose(),
|
2014-08-18 21:33:58 +02:00
|
|
|
c, t)
|
2014-08-18 16:29:17 +02:00
|
|
|
})
|
2014-08-18 21:33:58 +02:00
|
|
|
allData(func(c Coord) {
|
2014-08-18 16:29:17 +02:00
|
|
|
checkTransformer(
|
|
|
|
"I2P(P2I(plain))",
|
2014-08-18 21:33:58 +02:00
|
|
|
CoordToPlain,
|
2014-09-06 19:54:53 +02:00
|
|
|
compose(TransformPlainToInterleaved, TransformInterleavedToPlain),
|
2014-08-18 21:33:58 +02:00
|
|
|
c, t)
|
2014-08-18 16:29:17 +02:00
|
|
|
})
|
2014-08-18 21:33:58 +02:00
|
|
|
allData(func(c Coord) {
|
2014-08-18 16:29:17 +02:00
|
|
|
checkTransformer(
|
|
|
|
"P2I(I2P(interleaved))",
|
2014-08-18 21:33:58 +02:00
|
|
|
CoordToInterleaved,
|
2014-09-06 19:54:53 +02:00
|
|
|
compose(TransformInterleavedToPlain, TransformPlainToInterleaved),
|
2014-08-18 21:33:58 +02:00
|
|
|
c, t)
|
2014-08-18 16:29:17 +02:00
|
|
|
})
|
|
|
|
}
|
2014-09-06 19:54:53 +02:00
|
|
|
|
2014-09-07 09:58:09 +02:00
|
|
|
func TestCoordInterleaving(t *testing.T) {
|
|
|
|
allData(func(c Coord) {
|
|
|
|
d := InterleavedToCoord(CoordToInterleaved(c))
|
|
|
|
if c != d {
|
|
|
|
t.Errorf("Expected %v got %v\n", c, d)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2014-09-07 10:12:39 +02:00
|
|
|
func outsiders(zmin, zmax int64, fn func(int64)) {
|
|
|
|
|
|
|
|
c1 := InterleavedToCoord(zmin)
|
|
|
|
c2 := InterleavedToCoord(zmax)
|
|
|
|
cub := Cuboid{P1: c1, P2: c2}
|
|
|
|
var c Coord
|
|
|
|
for c.X = c1.X; c.X <= c2.X; c.X++ {
|
|
|
|
for c.Y = c1.Y; c.Y <= c2.Y; c.Y++ {
|
|
|
|
for c.Z = c1.Z; c.Z <= c2.Z; c.Z++ {
|
|
|
|
zn := CoordToInterleaved(c) + 1
|
|
|
|
if zn > zmin && zn < zmax && !cub.Contains(InterleavedToCoord(zn)) {
|
|
|
|
fn(zn)
|
2014-09-07 00:18:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-09-07 10:12:39 +02:00
|
|
|
}
|
2014-09-07 00:18:28 +02:00
|
|
|
}
|
|
|
|
|
2014-09-06 19:54:53 +02:00
|
|
|
func TestBigMin(t *testing.T) {
|
2014-09-07 10:46:51 +02:00
|
|
|
const tries = 20
|
2014-09-06 19:54:53 +02:00
|
|
|
for i := 0; i < tries; i++ {
|
|
|
|
x1 := rand.Intn(4000) - 2000
|
|
|
|
y1 := rand.Intn(4000) - 2000
|
|
|
|
z1 := rand.Intn(4000) - 2000
|
2014-09-06 20:38:49 +02:00
|
|
|
w := rand.Intn(18) + 1
|
|
|
|
h := rand.Intn(18) + 1
|
|
|
|
d := rand.Intn(18) + 1
|
2014-09-06 19:54:53 +02:00
|
|
|
x2 := x1 + w
|
|
|
|
y2 := y1 + h
|
|
|
|
z2 := z1 + d
|
|
|
|
|
|
|
|
c1 := Coord{X: int16(x1), Y: int16(y1), Z: int16(z1)}
|
|
|
|
c2 := Coord{X: int16(x2), Y: int16(y2), Z: int16(z2)}
|
|
|
|
|
|
|
|
zmin := CoordToInterleaved(c1)
|
|
|
|
zmax := CoordToInterleaved(c2)
|
|
|
|
|
2014-09-07 09:58:09 +02:00
|
|
|
if zmin > zmax {
|
|
|
|
t.Errorf("zmin > zmax: %d > %d\n", zmin, zmax)
|
|
|
|
}
|
|
|
|
|
2014-09-07 00:18:28 +02:00
|
|
|
errors, success := 0, 0
|
2014-09-07 10:12:39 +02:00
|
|
|
outsiders(zmin, zmax, func(zcode int64) {
|
2014-09-06 19:54:53 +02:00
|
|
|
nbm := NaiveBigMin(zmin, zmax, zcode)
|
|
|
|
cbm := BigMin(zmin, zmax, zcode)
|
2014-09-06 20:38:49 +02:00
|
|
|
//fmt.Printf("nbm: %b\n", nbm)
|
|
|
|
//fmt.Printf("cbm: %b\n", cbm)
|
2014-09-06 19:54:53 +02:00
|
|
|
if nbm != cbm {
|
|
|
|
errors++
|
|
|
|
} else {
|
|
|
|
success++
|
|
|
|
}
|
2014-09-07 10:12:39 +02:00
|
|
|
})
|
2014-09-07 00:18:28 +02:00
|
|
|
if errors > 0 {
|
|
|
|
cub := Cuboid{P1: c1, P2: c2}
|
2014-09-07 09:58:09 +02:00
|
|
|
t.Errorf("BigMin: %s (%d %d) %d errors out of %d (%f)\n",
|
2014-09-07 00:18:28 +02:00
|
|
|
cub,
|
2014-09-07 09:58:09 +02:00
|
|
|
zmin, zmax,
|
2014-09-07 00:18:28 +02:00
|
|
|
errors, errors+success,
|
|
|
|
float64(errors)/float64(errors+success))
|
|
|
|
}
|
2014-09-06 19:54:53 +02:00
|
|
|
}
|
|
|
|
}
|