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