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 init() {
|
|
|
|
seed := time.Now().UnixNano()
|
|
|
|
println(seed)
|
|
|
|
rand.Seed(seed)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testRandItemHead(t *testing.T, idx int, item *Item) {
|
|
|
|
t.Helper()
|
|
|
|
if idx == 0 {
|
|
|
|
if item.isPoint() {
|
|
|
|
t.Fatalf("expected false")
|
|
|
|
}
|
|
|
|
if item.fieldsLen() != 0 {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", 0, item.fieldsLen())
|
|
|
|
}
|
|
|
|
if item.idLen() != 0 {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", 0, item.idLen())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
item.setFieldsLen(fieldsLen)
|
|
|
|
item.setIDLen(idLen)
|
|
|
|
|
|
|
|
if item.isPoint() != isPoint {
|
|
|
|
t.Fatalf("isPoint: expected '%v', got '%v'", isPoint, item.isPoint())
|
|
|
|
}
|
|
|
|
if item.fieldsLen() != fieldsLen {
|
|
|
|
t.Fatalf("fieldsLen: expected '%v', got '%v'", fieldsLen, item.fieldsLen())
|
|
|
|
}
|
|
|
|
if item.idLen() != idLen {
|
|
|
|
t.Fatalf("idLen: expected '%v', got '%v'", idLen, item.idLen())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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] {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", values[i], item.GetField(i))
|
|
|
|
}
|
|
|
|
}
|
2019-02-15 18:26:55 +03:00
|
|
|
fields := item.fields()
|
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()
|
|
|
|
if weight != len(fields)*8+len(key)+points*16 {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", len(fields)*8+len(key)+points*16, weight)
|
|
|
|
}
|
|
|
|
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-16 00:02:04 +03:00
|
|
|
if !floatsEquals(values, fvalues) {
|
2019-02-15 18:26:55 +03:00
|
|
|
t.Fatalf("expected '%v', got '%v'", 1, len(fvalues))
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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()
|
|
|
|
if weight != len(values)*8+len(key)+points*16 {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", len(values)*8+len(key)+points*16, weight)
|
|
|
|
}
|
|
|
|
if points != 1 {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", 1, points)
|
|
|
|
}
|
2019-02-16 00:02:04 +03:00
|
|
|
if !floatsEquals(item.fields(), values) {
|
2019-02-15 18:26:55 +03:00
|
|
|
t.Fatalf("expected '%v', got '%v'", values, item.fields())
|
|
|
|
}
|
|
|
|
item.CopyOverFields(item)
|
|
|
|
weight, points = item.WeightAndPoints()
|
|
|
|
if weight != len(values)*8+len(key)+points*16 {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", len(values)*8+len(key)+points*16, weight)
|
|
|
|
}
|
|
|
|
if points != 1 {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", 1, points)
|
|
|
|
}
|
2019-02-16 00:02:04 +03:00
|
|
|
if !floatsEquals(item.fields(), values) {
|
2019-02-15 18:26:55 +03:00
|
|
|
t.Fatalf("expected '%v', got '%v'", values, item.fields())
|
|
|
|
}
|
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-15 18:26:55 +03:00
|
|
|
if len(item.fields()) != 0 {
|
|
|
|
t.Fatalf("expected '%#v', got '%#v'", 0, len(item.fields()))
|
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
|
|
|
}
|
|
|
|
|
|
|
|
func TestItem(t *testing.T) {
|
|
|
|
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
|
|
|
|
}
|