tile38/internal/collection/item/item_test.go

351 lines
8.2 KiB
Go
Raw Normal View History

2019-02-13 22:43:38 +03:00
package item
import (
"encoding/json"
"math/rand"
"testing"
"time"
"github.com/tidwall/geojson"
"github.com/tidwall/geojson/geometry"
)
2019-02-15 22:51:26 +03:00
func testRandItemHead(t *testing.T, idx int, item *Item) {
t.Helper()
if idx == 0 {
if item.isPoint() {
t.Fatalf("expected false")
}
2019-02-17 23:10:02 +03:00
if item.fieldsDataSize() != 0 {
t.Fatalf("expected '%v', got '%v'", 0, item.fieldsDataSize())
2019-02-15 22:51:26 +03:00
}
2019-02-17 23:10:02 +03:00
if item.idDataSize() != 0 {
t.Fatalf("expected '%v', got '%v'", 0, item.idDataSize())
2019-02-15 22:51:26 +03:00
}
}
isPoint := rand.Int()%2 == 0
2019-02-16 00:02:04 +03:00
fieldsLen := int(rand.Uint32() << 2 >> 2)
2019-02-15 22:51:26 +03:00
idLen := int(rand.Uint32())
item.setIsPoint(isPoint)
2019-02-17 23:10:02 +03:00
item.setFieldsDataSize(fieldsLen)
item.setIDDataSize(idLen)
2019-02-15 22:51:26 +03:00
if item.isPoint() != isPoint {
t.Fatalf("isPoint: expected '%v', got '%v'", isPoint, item.isPoint())
}
2019-02-17 23:10:02 +03:00
if item.fieldsDataSize() != fieldsLen {
t.Fatalf("fieldsLen: expected '%v', got '%v'", fieldsLen, item.fieldsDataSize())
2019-02-15 22:51:26 +03:00
}
2019-02-17 23:10:02 +03:00
if item.idDataSize() != idLen {
t.Fatalf("idLen: expected '%v', got '%v'", idLen, item.idDataSize())
2019-02-15 22:51:26 +03:00
}
}
func TestItemHead(t *testing.T) {
start := time.Now()
for time.Since(start) < time.Second/2 {
var item Item
for i := 0; i < 10; i++ {
testRandItemHead(t, i, &item)
}
}
}
2019-02-13 22:43:38 +03:00
func testRandItem(t *testing.T) {
keyb := make([]byte, rand.Int()%16)
rand.Read(keyb)
key := string(keyb)
2019-02-16 00:02:04 +03:00
packed := rand.Int()%2 == 0
values := make([]float64, rand.Int()%64)
2019-02-13 22:43:38 +03:00
for i := range values {
2019-02-16 00:02:04 +03:00
if packed {
switch rand.Int() % 8 {
case 0:
values[i] = 0
case 1:
values[i] = 1
case 2:
values[i] = -1
case 3:
values[i] = float64(rand.Int() % 120)
case 4:
values[i] = float64(-(rand.Int() % 120))
case 5:
values[i] = float64(rand.Float32())
case 6:
values[i] = float64(rand.Float64())
case 7:
values[i] = float64(rand.Int()%240) / 10
}
} else {
values[i] = rand.Float64()
}
2019-02-13 22:43:38 +03:00
}
2019-02-16 00:02:04 +03:00
2019-02-15 18:26:55 +03:00
var item *Item
if rand.Int()%2 == 0 {
2019-02-16 00:02:04 +03:00
item = New(key, geojson.NewSimplePoint(geometry.Point{X: 1, Y: 2}), packed)
2019-02-15 18:26:55 +03:00
} else {
2019-02-16 00:02:04 +03:00
item = New(key, geojson.NewPoint(geometry.Point{X: 1, Y: 2}), packed)
2019-02-15 18:26:55 +03:00
}
2019-02-13 22:43:38 +03:00
if item.ID() != key {
t.Fatalf("expected '%v', got '%v'", key, item.ID())
}
var setValues []int
for _, i := range rand.Perm(len(values)) {
2019-02-16 00:02:04 +03:00
if !item.SetField(i, values[i]) && values[i] != 0 {
2019-02-13 22:43:38 +03:00
t.Fatal("expected true")
}
setValues = append(setValues, i)
if item.ID() != key {
t.Fatalf("expected '%v', got '%v'", key, item.ID())
}
for _, i := range setValues {
if item.GetField(i) != values[i] {
2019-02-17 23:10:02 +03:00
t.Fatalf("expected '%v', got '%v' for index %d", values[i], item.GetField(i), i)
2019-02-13 22:43:38 +03:00
}
}
2019-02-17 23:10:02 +03:00
fields := itemFields(item)
2019-02-13 22:43:38 +03:00
for i := 0; i < len(fields); i++ {
for _, j := range setValues {
if i == j {
if fields[i] != values[i] {
t.Fatalf("expected '%v', got '%v'", values[i], fields[i])
}
break
}
}
}
weight, points := item.WeightAndPoints()
2019-02-17 23:10:02 +03:00
if weight != item.fieldsDataSize()+len(key)+points*16 {
t.Fatalf("expected '%v', got '%v'",
item.fieldsDataSize()+len(key)+points*16, weight)
2019-02-13 22:43:38 +03:00
}
if points != 1 {
t.Fatalf("expected '%v', got '%v'", 1, points)
}
}
if item.GetField(len(values)) != 0 {
t.Fatalf("expected '%v', got '%v'", 0, item.GetField(len(values)))
}
for _, i := range rand.Perm(len(values)) {
if item.SetField(i, values[i]) {
t.Fatal("expected false")
}
}
2019-02-15 18:26:55 +03:00
var fvalues []float64
item.ForEachField(len(values), func(value float64) bool {
fvalues = append(fvalues, value)
return true
})
2019-02-16 00:02:04 +03:00
if !floatsEquals(values, fvalues) {
2019-02-15 18:26:55 +03:00
t.Fatalf("expected '%v', got '%v'", values, fvalues)
}
fvalues = nil
item.ForEachField(len(values), func(value float64) bool {
if len(fvalues) == 1 {
return false
}
fvalues = append(fvalues, value)
return true
})
if len(values) > 0 && len(fvalues) != 1 {
t.Fatalf("expected '%v', got '%v'", 1, len(fvalues))
}
fvalues = nil
item.ForEachField(-1, func(value float64) bool {
fvalues = append(fvalues, value)
return true
})
2019-02-17 23:10:02 +03:00
for len(fvalues) < len(values) {
fvalues = append(fvalues, 0)
}
2019-02-16 00:02:04 +03:00
if !floatsEquals(values, fvalues) {
2019-02-17 23:10:02 +03:00
t.Fatalf("expected true")
2019-02-15 18:26:55 +03:00
}
// should not fail, must allow nil receiver
(*Item)(nil).ForEachField(1, nil)
if (*Item)(nil).GetField(1) != 0 {
t.Fatalf("expected '%v', got '%v'", 0, (*Item)(nil).GetField(1))
}
2019-02-13 22:43:38 +03:00
if item.ID() != key {
t.Fatalf("expected '%v', got '%v'", key, item.ID())
}
if item.Obj().NumPoints() != 1 {
t.Fatalf("expected '%v', got '%v'", 1, item.Obj().NumPoints())
}
item.CopyOverFields(values)
weight, points := item.WeightAndPoints()
2019-02-17 23:10:02 +03:00
if weight != item.fieldsDataSize()+len(key)+points*16 {
t.Fatalf("expected '%v', got '%v'", item.fieldsDataSize()+len(key)+points*16, weight)
2019-02-13 22:43:38 +03:00
}
if points != 1 {
t.Fatalf("expected '%v', got '%v'", 1, points)
}
2019-02-17 23:10:02 +03:00
if !floatsEquals(itemFields(item), values) {
t.Fatalf("expected '%v', got '%v'", values, itemFields(item))
2019-02-15 18:26:55 +03:00
}
item.CopyOverFields(item)
weight, points = item.WeightAndPoints()
2019-02-17 23:10:02 +03:00
if weight != item.fieldsDataSize()+len(key)+points*16 {
t.Fatalf("expected '%v', got '%v'", item.fieldsDataSize()+len(key)+points*16, weight)
2019-02-15 18:26:55 +03:00
}
if points != 1 {
t.Fatalf("expected '%v', got '%v'", 1, points)
}
2019-02-17 23:10:02 +03:00
if !floatsEquals(itemFields(item), values) {
t.Fatalf("expected '%v', got '%v'", values, itemFields(item))
2019-02-15 18:26:55 +03:00
}
2019-02-16 00:02:04 +03:00
if len(values) > 0 && !item.HasFields() {
2019-02-15 18:26:55 +03:00
t.Fatal("expected true")
2019-02-13 22:43:38 +03:00
}
item.CopyOverFields(nil)
weight, points = item.WeightAndPoints()
if weight != len(key)+points*16 {
t.Fatalf("expected '%v', got '%v'", len(key)+points*16, weight)
}
if points != 1 {
t.Fatalf("expected '%v', got '%v'", 1, points)
}
2019-02-17 23:10:02 +03:00
if len(itemFields(item)) != 0 {
t.Fatalf("expected '%#v', got '%#v'", 0, len(itemFields(item)))
2019-02-13 22:43:38 +03:00
}
if item.ID() != key {
t.Fatalf("expected '%v', got '%v'", key, item.ID())
}
2019-02-15 18:26:55 +03:00
if item.HasFields() {
t.Fatal("expected false")
}
2019-02-13 22:43:38 +03:00
}
2019-02-17 23:10:02 +03:00
func itemFields(item *Item) []float64 {
var values []float64
item.ForEachField(-1, func(value float64) bool {
values = append(values, value)
return true
})
return values
}
2019-02-13 22:43:38 +03:00
func TestItem(t *testing.T) {
2019-02-17 23:10:02 +03:00
seed := time.Now().UnixNano()
seed = 1550371581595971000
println("TestItem seed", seed)
rand.Seed(seed)
2019-02-13 22:43:38 +03:00
start := time.Now()
2019-02-15 22:51:26 +03:00
for time.Since(start) < time.Second/2 {
2019-02-13 22:43:38 +03:00
testRandItem(t)
}
}
2019-02-16 00:02:04 +03:00
func TestItemFieldOutOfRange(t *testing.T) {
var item Item
defer func() {
if recover() == nil {
t.Fatal("expected panic")
}
}()
item.GetField(-1)
}
2019-02-13 22:43:38 +03:00
func TestItemLess(t *testing.T) {
2019-02-16 00:02:04 +03:00
item0 := New("0", testString("0"), false)
item1 := New("1", testString("1"), false)
item2 := New("1", testString("2"), false)
item3 := New("3", testString("2"), false)
2019-02-13 22:43:38 +03:00
if !item0.Less(item1, nil) {
t.Fatal("expected true")
}
if item1.Less(item0, nil) {
t.Fatal("expected false")
}
if !item1.Less(item2, nil) {
t.Fatal("expected true")
}
if item2.Less(item1, nil) {
t.Fatal("expected false")
}
if !item2.Less(item3, nil) {
t.Fatal("expected true")
}
if item3.Less(item2, nil) {
t.Fatal("expected false")
}
weight, points := item0.WeightAndPoints()
if weight != 2 {
t.Fatalf("expected '%v', got '%v'", 2, weight)
}
if points != 0 {
t.Fatalf("expected '%v', got '%v'", 0, points)
}
}
type testString string
func (s testString) Spatial() geojson.Spatial {
return geojson.EmptySpatial{}
}
func (s testString) ForEach(iter func(geom geojson.Object) bool) bool {
return iter(s)
}
func (s testString) Empty() bool {
return true
}
func (s testString) Valid() bool {
return false
}
func (s testString) Rect() geometry.Rect {
return geometry.Rect{}
}
func (s testString) Center() geometry.Point {
return geometry.Point{}
}
func (s testString) AppendJSON(dst []byte) []byte {
data, _ := json.Marshal(string(s))
return append(dst, data...)
}
func (s testString) String() string {
return string(s)
}
func (s testString) JSON() string {
return string(s.AppendJSON(nil))
}
func (s testString) MarshalJSON() ([]byte, error) {
return s.AppendJSON(nil), nil
}
func (s testString) Within(obj geojson.Object) bool {
return false
}
func (s testString) Contains(obj geojson.Object) bool {
return false
}
func (s testString) Intersects(obj geojson.Object) bool {
return false
}
func (s testString) NumPoints() int {
return 0
}
func (s testString) Distance(obj geojson.Object) float64 {
return 0
}
2019-02-16 00:02:04 +03:00
func floatsEquals(a, b []float64) bool {
if len(a) != len(b) {
return false
}
for i := 0; i < len(a); i++ {
if a[i] != b[i] {
return false
}
}
return true
}