tile38/internal/field/list_test.go
tidwall 51e6862797 Fix field floating point parsing misrepresentation
This commit fixes an issue where fields with floating points
that have zero prefixes and underscores are being parsed as
numbers.

Now those are treated as string values.

See #736
2024-05-03 18:14:06 -07:00

233 lines
5.6 KiB
Go

package field
import (
"fmt"
"math/rand"
"testing"
"time"
"github.com/tidwall/assert"
"github.com/tidwall/btree"
)
func TestList(t *testing.T) {
var fields List
fields = fields.Set(Make("hello", "123"))
assert.Assert(fields.Len() == 1)
// println(fields.Weight())
// assert.Assert(fields.Weight() == 16)
fields = fields.Set(Make("jello", "456"))
assert.Assert(fields.Len() == 2)
// assert.Assert(fields.Weight() == 32)
value := fields.Get("jello")
assert.Assert(value.Value().Data() == "456")
assert.Assert(value.Value().JSON() == "456")
assert.Assert(value.Value().Num() == 456)
value = fields.Get("nello")
assert.Assert(value.Name() == "")
assert.Assert(value.Value().IsZero())
fields = fields.Set(Make("jello", "789"))
assert.Assert(fields.Len() == 2)
// assert.Assert(fields.Weight() == 32)
fields = fields.Set(Make("nello", "0"))
assert.Assert(fields.Len() == 2)
// assert.Assert(fields.Weight() == 32)
fields = fields.Set(Make("jello", "789"))
assert.Assert(fields.Len() == 2)
// assert.Assert(fields.Weight() == 32)
fields = fields.Set(Make("jello", "0"))
assert.Assert(fields.Len() == 1)
// assert.Assert(fields.Weight() == 16)
fields = fields.Set(Make("nello", "012"))
fields = fields.Set(Make("hello", "456"))
fields = fields.Set(Make("fello", "123"))
fields = fields.Set(Make("jello", "789"))
var names string
var datas string
var nums float64
fields.Scan(func(f Field) bool {
names += f.Name()
datas += f.Value().Data()
nums += f.Value().Num()
return true
})
assert.Assert(names == "fellohellojellonello")
assert.Assert(datas == "123456789012")
assert.Assert(nums == 1368)
names = ""
datas = ""
nums = 0
fields.Scan(func(f Field) bool {
names += f.Name()
datas += f.Value().Data()
nums += f.Value().Num()
return false
})
assert.Assert(names == "fello")
assert.Assert(datas == "123")
assert.Assert(nums == 123)
}
func randStr(n int) string {
b := make([]byte, n)
rand.Read(b)
for i := 0; i < n; i++ {
b[i] = 'a' + b[i]%26
}
return string(b)
}
func randVal(n int) string {
switch rand.Intn(10) {
case 0:
return "null"
case 1:
return "true"
case 2:
return "false"
case 3:
return `{"a":"` + randStr(n) + `"}`
case 4:
return `["` + randStr(n) + `"]`
case 5:
return `"` + randStr(n) + `"`
case 6:
return randStr(n)
default:
return fmt.Sprintf("%f", rand.Float64()*360)
}
}
func TestRandom(t *testing.T) {
seed := time.Now().UnixNano()
// seed = 1663607868546669000
rand.Seed(seed)
start := time.Now()
var total int
for time.Since(start) < time.Second*2 {
N := rand.Intn(500)
var org []Field
var tr btree.Map[string, Field]
var fields List
for i := 0; i < N; i++ {
name := randStr(rand.Intn(10))
value := randVal(rand.Intn(10))
field := Make(name, value)
org = append(org, field)
fields = fields.Set(field)
v := fields.Get(name)
// println(name, v.Value().Data(), field.Value().Data())
if !v.Value().Equals(field.Value()) {
t.Fatalf("seed: %d, expected true", seed)
}
tr.Set(name, field)
if fields.Len() != tr.Len() {
t.Fatalf("seed: %d, expected %d, got %d",
seed, tr.Len(), fields.Len())
}
}
comp := func() {
var all []Field
fields.Scan(func(f Field) bool {
all = append(all, f)
return true
})
if len(all) != fields.Len() {
t.Fatalf("seed: %d, expected %d, got %d",
seed, fields.Len(), len(all))
}
if fields.Len() != tr.Len() {
t.Fatalf("seed: %d, expected %d, got %d",
seed, tr.Len(), fields.Len())
}
var i int
tr.Scan(func(name string, f Field) bool {
if name != f.Name() || all[i].Name() != f.Name() {
t.Fatalf("seed: %d, out of order", seed)
}
i++
return true
})
}
comp()
rand.Shuffle(len(org), func(i, j int) {
org[i], org[j] = org[j], org[i]
})
for _, f := range org {
comp()
tr.Delete(f.Name())
fields = fields.Set(Make(f.Name(), "0"))
if fields.Len() != tr.Len() {
t.Fatalf("seed: %d, expected %d, got %d",
seed, tr.Len(), fields.Len())
}
comp()
}
total++
}
}
func TestJSONGet(t *testing.T) {
var list List
list = list.Set(Make("hello", "world"))
list = list.Set(Make("hello", `"world"`))
list = list.Set(Make("jello", "planet"))
list = list.Set(Make("telly", `{"a":[1,2,3],"b":null,"c":true,"d":false}`))
list = list.Set(Make("belly", `{"a":{"b":{"c":"fancy"}}}`))
json := list.String()
exp := `{"belly":{"a":{"b":{"c":"fancy"}}},"hello":"world","jello":` +
`"planet","telly":{"a":[1,2,3],"b":null,"c":true,"d":false}}`
if json != exp {
t.Fatalf("expected '%s', got '%s'", exp, json)
}
data := list.Get("hello").Value().Data()
if data != "world" {
t.Fatalf("expected '%s', got '%s'", "world", data)
}
data = list.Get("telly").Value().Data()
if data != `{"a":[1,2,3],"b":null,"c":true,"d":false}` {
t.Fatalf("expected '%s', got '%s'",
`{"a":[1,2,3],"b":null,"c":true,"d":false}`, data)
}
data = list.Get("belly").Value().Data()
if data != `{"a":{"b":{"c":"fancy"}}}` {
t.Fatalf("expected '%s', got '%s'",
`{"a":{"b":{"c":"fancy"}}}`, data)
}
data = list.Get("belly.a").Value().Data()
if data != `{"b":{"c":"fancy"}}` {
t.Fatalf("expected '%s', got '%s'",
`{"b":{"c":"fancy"}}`, data)
}
data = list.Get("belly.a.b").Value().Data()
if data != `{"c":"fancy"}` {
t.Fatalf("expected '%s', got '%s'",
`{"c":"fancy"}`, data)
}
data = list.Get("belly.a.b.c").Value().Data()
if data != `fancy` {
t.Fatalf("expected '%s', got '%s'",
`fancy`, data)
}
// Tile38 defaults non-existent fields to zero.
data = list.Get("belly.a.b.c.d").Value().Data()
if data != `0` {
t.Fatalf("expected '%s', got '%s'",
`0`, data)
}
}