2016-08-11 06:07:45 +03:00
|
|
|
package gjson
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/hex"
|
|
|
|
"encoding/json"
|
2016-08-22 18:25:33 +03:00
|
|
|
"fmt"
|
2016-08-11 06:07:45 +03:00
|
|
|
"math/rand"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
"time"
|
2019-02-17 04:29:39 +03:00
|
|
|
|
|
|
|
"github.com/tidwall/pretty"
|
2016-08-11 06:07:45 +03:00
|
|
|
)
|
|
|
|
|
2016-08-21 16:51:36 +03:00
|
|
|
// TestRandomData is a fuzzing test that throws random data at the Parse
|
2016-08-11 06:07:45 +03:00
|
|
|
// function looking for panics.
|
|
|
|
func TestRandomData(t *testing.T) {
|
|
|
|
var lstr string
|
|
|
|
defer func() {
|
|
|
|
if v := recover(); v != nil {
|
|
|
|
println("'" + hex.EncodeToString([]byte(lstr)) + "'")
|
|
|
|
println("'" + lstr + "'")
|
|
|
|
panic(v)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
rand.Seed(time.Now().UnixNano())
|
|
|
|
b := make([]byte, 200)
|
|
|
|
for i := 0; i < 2000000; i++ {
|
|
|
|
n, err := rand.Read(b[:rand.Int()%len(b)])
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
lstr = string(b[:n])
|
2016-09-08 18:08:53 +03:00
|
|
|
GetBytes([]byte(lstr), "zzzz")
|
2016-10-19 03:13:15 +03:00
|
|
|
Parse(lstr)
|
2016-08-11 06:07:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRandomValidStrings(t *testing.T) {
|
|
|
|
rand.Seed(time.Now().UnixNano())
|
|
|
|
b := make([]byte, 200)
|
|
|
|
for i := 0; i < 100000; i++ {
|
|
|
|
n, err := rand.Read(b[:rand.Int()%len(b)])
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
sm, err := json.Marshal(string(b[:n]))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
var su string
|
|
|
|
if err := json.Unmarshal([]byte(sm), &su); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
token := Get(`{"str":`+string(sm)+`}`, "str")
|
|
|
|
if token.Type != String || token.Str != su {
|
2019-06-28 04:03:36 +03:00
|
|
|
println("["+token.Raw+"]", "["+token.Str+"]", "["+su+"]",
|
|
|
|
"["+string(sm)+"]")
|
2016-08-11 06:07:45 +03:00
|
|
|
t.Fatal("string mismatch")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-04-10 05:40:55 +03:00
|
|
|
|
|
|
|
func TestEmoji(t *testing.T) {
|
2019-06-28 04:03:36 +03:00
|
|
|
const input = `{"utf8":"Example emoji, KO: \ud83d\udd13, \ud83c\udfc3 ` +
|
|
|
|
`OK: \u2764\ufe0f "}`
|
2017-04-10 05:40:55 +03:00
|
|
|
value := Get(input, "utf8")
|
|
|
|
var s string
|
|
|
|
json.Unmarshal([]byte(value.Raw), &s)
|
|
|
|
if value.String() != s {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", s, value.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-12 04:51:29 +03:00
|
|
|
func testEscapePath(t *testing.T, json, path, expect string) {
|
|
|
|
if Get(json, path).String() != expect {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", expect, Get(json, path).String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestEscapePath(t *testing.T) {
|
|
|
|
json := `{
|
|
|
|
"test":{
|
|
|
|
"*":"valZ",
|
|
|
|
"*v":"val0",
|
|
|
|
"keyv*":"val1",
|
|
|
|
"key*v":"val2",
|
|
|
|
"keyv?":"val3",
|
|
|
|
"key?v":"val4",
|
|
|
|
"keyv.":"val5",
|
|
|
|
"key.v":"val6",
|
|
|
|
"keyk*":{"key?":"val7"}
|
|
|
|
}
|
|
|
|
}`
|
|
|
|
|
|
|
|
testEscapePath(t, json, "test.\\*", "valZ")
|
|
|
|
testEscapePath(t, json, "test.\\*v", "val0")
|
|
|
|
testEscapePath(t, json, "test.keyv\\*", "val1")
|
|
|
|
testEscapePath(t, json, "test.key\\*v", "val2")
|
|
|
|
testEscapePath(t, json, "test.keyv\\?", "val3")
|
|
|
|
testEscapePath(t, json, "test.key\\?v", "val4")
|
|
|
|
testEscapePath(t, json, "test.keyv\\.", "val5")
|
|
|
|
testEscapePath(t, json, "test.key\\.v", "val6")
|
|
|
|
testEscapePath(t, json, "test.keyk\\*.key\\?", "val7")
|
|
|
|
}
|
2016-08-11 06:07:45 +03:00
|
|
|
|
|
|
|
// this json block is poorly formed on purpose.
|
|
|
|
var basicJSON = `{"age":100, "name":{"here":"B\\\"R"},
|
|
|
|
"noop":{"what is a wren?":"a bird"},
|
|
|
|
"happy":true,"immortal":false,
|
2016-08-15 14:56:55 +03:00
|
|
|
"items":[1,2,3,{"tags":[1,2,3],"points":[[1,2],[3,4]]},4,5,6,7],
|
2016-08-11 06:07:45 +03:00
|
|
|
"arr":["1",2,"3",{"hello":"world"},"4",5],
|
2016-08-21 16:51:36 +03:00
|
|
|
"vals":[1,2,3,{"sadf":sdf"asdf"}],"name":{"first":"tom","last":null},
|
2017-04-15 03:58:25 +03:00
|
|
|
"created":"2014-05-16T08:28:06.989Z",
|
2016-08-21 16:51:36 +03:00
|
|
|
"loggy":{
|
|
|
|
"programmers": [
|
|
|
|
{
|
2016-11-02 22:20:24 +03:00
|
|
|
"firstName": "Brett",
|
|
|
|
"lastName": "McLaughlin",
|
2016-11-30 17:52:25 +03:00
|
|
|
"email": "aaaa",
|
|
|
|
"tag": "good"
|
2016-11-02 22:20:24 +03:00
|
|
|
},
|
2016-08-21 16:51:36 +03:00
|
|
|
{
|
2016-11-02 22:20:24 +03:00
|
|
|
"firstName": "Jason",
|
|
|
|
"lastName": "Hunter",
|
2016-11-30 17:52:25 +03:00
|
|
|
"email": "bbbb",
|
|
|
|
"tag": "bad"
|
2016-11-02 22:20:24 +03:00
|
|
|
},
|
2016-08-21 16:51:36 +03:00
|
|
|
{
|
2016-11-02 22:20:24 +03:00
|
|
|
"firstName": "Elliotte",
|
|
|
|
"lastName": "Harold",
|
2016-11-30 17:52:25 +03:00
|
|
|
"email": "cccc",
|
|
|
|
"tag":, "good"
|
2016-08-22 16:05:51 +03:00
|
|
|
},
|
|
|
|
{
|
2016-08-31 23:38:53 +03:00
|
|
|
"firstName": 1002.3,
|
|
|
|
"age": 101
|
2016-08-22 16:05:51 +03:00
|
|
|
}
|
2016-08-21 16:51:36 +03:00
|
|
|
]
|
2017-04-11 18:54:19 +03:00
|
|
|
},
|
|
|
|
"lastly":{"yay":"final"}
|
2016-08-21 16:51:36 +03:00
|
|
|
}`
|
2016-09-08 18:08:53 +03:00
|
|
|
|
2017-04-15 03:58:25 +03:00
|
|
|
func TestTimeResult(t *testing.T) {
|
2019-06-28 04:03:36 +03:00
|
|
|
assert(t, Get(basicJSON, "created").String() ==
|
|
|
|
Get(basicJSON, "created").Time().Format(time.RFC3339Nano))
|
2017-04-15 03:58:25 +03:00
|
|
|
}
|
|
|
|
|
2017-04-11 18:54:19 +03:00
|
|
|
func TestParseAny(t *testing.T) {
|
|
|
|
assert(t, Parse("100").Float() == 100)
|
|
|
|
assert(t, Parse("true").Bool())
|
2018-02-23 15:25:48 +03:00
|
|
|
assert(t, Parse("false").Bool() == false)
|
2019-06-28 15:24:28 +03:00
|
|
|
assert(t, Parse("yikes").Exists() == false)
|
2017-04-11 18:54:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestManyVariousPathCounts(t *testing.T) {
|
|
|
|
json := `{"a":"a","b":"b","c":"c"}`
|
2019-06-28 04:03:36 +03:00
|
|
|
counts := []int{3, 4, 7, 8, 9, 15, 16, 17, 31, 32, 33, 63, 64, 65, 127,
|
|
|
|
128, 129, 255, 256, 257, 511, 512, 513}
|
2017-04-11 18:54:19 +03:00
|
|
|
paths := []string{"a", "b", "c"}
|
|
|
|
expects := []string{"a", "b", "c"}
|
|
|
|
for _, count := range counts {
|
|
|
|
var gpaths []string
|
|
|
|
for i := 0; i < count; i++ {
|
|
|
|
if i < len(paths) {
|
|
|
|
gpaths = append(gpaths, paths[i])
|
|
|
|
} else {
|
|
|
|
gpaths = append(gpaths, fmt.Sprintf("not%d", i))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
results := GetMany(json, gpaths...)
|
|
|
|
for i := 0; i < len(paths); i++ {
|
|
|
|
if results[i].String() != expects[i] {
|
2019-06-28 04:03:36 +03:00
|
|
|
t.Fatalf("expected '%v', got '%v'", expects[i],
|
|
|
|
results[i].String())
|
2017-04-11 18:54:19 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func TestManyRecursion(t *testing.T) {
|
|
|
|
var json string
|
|
|
|
var path string
|
|
|
|
for i := 0; i < 100; i++ {
|
|
|
|
json += `{"a":`
|
|
|
|
path += ".a"
|
|
|
|
}
|
|
|
|
json += `"b"`
|
|
|
|
for i := 0; i < 100; i++ {
|
|
|
|
json += `}`
|
|
|
|
}
|
|
|
|
path = path[1:]
|
|
|
|
assert(t, GetMany(json, path)[0].String() == "b")
|
|
|
|
}
|
2016-09-08 18:08:53 +03:00
|
|
|
func TestByteSafety(t *testing.T) {
|
2016-09-08 18:34:01 +03:00
|
|
|
jsonb := []byte(`{"name":"Janet","age":38}`)
|
2016-09-08 18:08:53 +03:00
|
|
|
mtok := GetBytes(jsonb, "name")
|
|
|
|
if mtok.String() != "Janet" {
|
|
|
|
t.Fatalf("expected %v, got %v", "Jason", mtok.String())
|
|
|
|
}
|
2016-09-08 18:34:01 +03:00
|
|
|
mtok2 := GetBytes(jsonb, "age")
|
|
|
|
if mtok2.Raw != "38" {
|
|
|
|
t.Fatalf("expected %v, got %v", "Jason", mtok2.Raw)
|
|
|
|
}
|
2016-09-08 18:08:53 +03:00
|
|
|
jsonb[9] = 'T'
|
|
|
|
jsonb[12] = 'd'
|
|
|
|
jsonb[13] = 'y'
|
|
|
|
if mtok.String() != "Janet" {
|
|
|
|
t.Fatalf("expected %v, got %v", "Jason", mtok.String())
|
|
|
|
}
|
|
|
|
}
|
2016-08-11 06:07:45 +03:00
|
|
|
|
2016-09-08 19:02:40 +03:00
|
|
|
func get(json, path string) Result {
|
2017-04-11 18:54:19 +03:00
|
|
|
return GetBytes([]byte(json), path)
|
2016-09-08 19:02:40 +03:00
|
|
|
}
|
|
|
|
|
2016-08-11 06:07:45 +03:00
|
|
|
func TestBasic(t *testing.T) {
|
2016-08-22 16:05:51 +03:00
|
|
|
var mtok Result
|
2016-11-30 17:52:25 +03:00
|
|
|
mtok = get(basicJSON, `loggy.programmers.#[tag="good"].firstName`)
|
|
|
|
if mtok.String() != "Brett" {
|
|
|
|
t.Fatalf("expected %v, got %v", "Brett", mtok.String())
|
|
|
|
}
|
|
|
|
mtok = get(basicJSON, `loggy.programmers.#[tag="good"]#.firstName`)
|
|
|
|
if mtok.String() != `["Brett","Elliotte"]` {
|
|
|
|
t.Fatalf("expected %v, got %v", `["Brett","Elliotte"]`, mtok.String())
|
|
|
|
}
|
2017-04-11 06:45:34 +03:00
|
|
|
}
|
2017-08-14 18:21:16 +03:00
|
|
|
|
2017-08-14 18:23:21 +03:00
|
|
|
func TestIsArrayIsObject(t *testing.T) {
|
|
|
|
mtok := get(basicJSON, "loggy")
|
|
|
|
assert(t, mtok.IsObject())
|
|
|
|
assert(t, !mtok.IsArray())
|
|
|
|
|
|
|
|
mtok = get(basicJSON, "loggy.programmers")
|
|
|
|
assert(t, !mtok.IsObject())
|
|
|
|
assert(t, mtok.IsArray())
|
|
|
|
|
|
|
|
mtok = get(basicJSON, `loggy.programmers.#[tag="good"]#.firstName`)
|
|
|
|
assert(t, mtok.IsArray())
|
|
|
|
|
|
|
|
mtok = get(basicJSON, `loggy.programmers.0.firstName`)
|
|
|
|
assert(t, !mtok.IsObject())
|
|
|
|
assert(t, !mtok.IsArray())
|
|
|
|
}
|
|
|
|
|
2017-05-26 05:39:18 +03:00
|
|
|
func TestPlus53BitInts(t *testing.T) {
|
|
|
|
json := `{"IdentityData":{"GameInstanceId":634866135153775564}}`
|
|
|
|
value := Get(json, "IdentityData.GameInstanceId")
|
|
|
|
assert(t, value.Uint() == 634866135153775564)
|
|
|
|
assert(t, value.Int() == 634866135153775564)
|
|
|
|
assert(t, value.Float() == 634866135153775616)
|
|
|
|
|
|
|
|
json = `{"IdentityData":{"GameInstanceId":634866135153775564.88172}}`
|
|
|
|
value = Get(json, "IdentityData.GameInstanceId")
|
|
|
|
assert(t, value.Uint() == 634866135153775616)
|
|
|
|
assert(t, value.Int() == 634866135153775616)
|
|
|
|
assert(t, value.Float() == 634866135153775616.88172)
|
|
|
|
|
|
|
|
json = `{
|
|
|
|
"min_uint64": 0,
|
|
|
|
"max_uint64": 18446744073709551615,
|
|
|
|
"overflow_uint64": 18446744073709551616,
|
|
|
|
"min_int64": -9223372036854775808,
|
|
|
|
"max_int64": 9223372036854775807,
|
|
|
|
"overflow_int64": 9223372036854775808,
|
|
|
|
"min_uint53": 0,
|
|
|
|
"max_uint53": 4503599627370495,
|
|
|
|
"overflow_uint53": 4503599627370496,
|
|
|
|
"min_int53": -2251799813685248,
|
|
|
|
"max_int53": 2251799813685247,
|
|
|
|
"overflow_int53": 2251799813685248
|
|
|
|
}`
|
|
|
|
|
|
|
|
assert(t, Get(json, "min_uint53").Uint() == 0)
|
|
|
|
assert(t, Get(json, "max_uint53").Uint() == 4503599627370495)
|
|
|
|
assert(t, Get(json, "overflow_uint53").Int() == 4503599627370496)
|
|
|
|
assert(t, Get(json, "min_int53").Int() == -2251799813685248)
|
|
|
|
assert(t, Get(json, "max_int53").Int() == 2251799813685247)
|
|
|
|
assert(t, Get(json, "overflow_int53").Int() == 2251799813685248)
|
|
|
|
assert(t, Get(json, "min_uint64").Uint() == 0)
|
|
|
|
assert(t, Get(json, "max_uint64").Uint() == 18446744073709551615)
|
|
|
|
// this next value overflows the max uint64 by one which will just
|
|
|
|
// flip the number to zero
|
|
|
|
assert(t, Get(json, "overflow_uint64").Int() == 0)
|
|
|
|
assert(t, Get(json, "min_int64").Int() == -9223372036854775808)
|
|
|
|
assert(t, Get(json, "max_int64").Int() == 9223372036854775807)
|
|
|
|
// this next value overflows the max int64 by one which will just
|
|
|
|
// flip the number to the negative sign.
|
|
|
|
assert(t, Get(json, "overflow_int64").Int() == -9223372036854775808)
|
|
|
|
}
|
2017-08-30 20:08:10 +03:00
|
|
|
func TestIssue38(t *testing.T) {
|
|
|
|
// These should not fail, even though the unicode is invalid.
|
|
|
|
Get(`["S3O PEDRO DO BUTI\udf93"]`, "0")
|
|
|
|
Get(`["S3O PEDRO DO BUTI\udf93asdf"]`, "0")
|
|
|
|
Get(`["S3O PEDRO DO BUTI\udf93\u"]`, "0")
|
|
|
|
Get(`["S3O PEDRO DO BUTI\udf93\u1"]`, "0")
|
|
|
|
Get(`["S3O PEDRO DO BUTI\udf93\u13"]`, "0")
|
|
|
|
Get(`["S3O PEDRO DO BUTI\udf93\u134"]`, "0")
|
|
|
|
Get(`["S3O PEDRO DO BUTI\udf93\u1345"]`, "0")
|
|
|
|
Get(`["S3O PEDRO DO BUTI\udf93\u1345asd"]`, "0")
|
|
|
|
}
|
2017-04-11 18:54:19 +03:00
|
|
|
func TestTypes(t *testing.T) {
|
|
|
|
assert(t, (Result{Type: String}).Type.String() == "String")
|
|
|
|
assert(t, (Result{Type: Number}).Type.String() == "Number")
|
|
|
|
assert(t, (Result{Type: Null}).Type.String() == "Null")
|
|
|
|
assert(t, (Result{Type: False}).Type.String() == "False")
|
|
|
|
assert(t, (Result{Type: True}).Type.String() == "True")
|
|
|
|
assert(t, (Result{Type: JSON}).Type.String() == "JSON")
|
|
|
|
assert(t, (Result{Type: 100}).Type.String() == "")
|
|
|
|
// bool
|
2020-11-05 02:01:22 +03:00
|
|
|
assert(t, (Result{Type: True}).Bool() == true)
|
2017-04-11 18:54:19 +03:00
|
|
|
assert(t, (Result{Type: False}).Bool() == false)
|
2020-11-05 02:01:22 +03:00
|
|
|
assert(t, (Result{Type: Number, Num: 1}).Bool() == true)
|
|
|
|
assert(t, (Result{Type: Number, Num: 0}).Bool() == false)
|
|
|
|
assert(t, (Result{Type: String, Str: "1"}).Bool() == true)
|
|
|
|
assert(t, (Result{Type: String, Str: "T"}).Bool() == true)
|
|
|
|
assert(t, (Result{Type: String, Str: "t"}).Bool() == true)
|
|
|
|
assert(t, (Result{Type: String, Str: "true"}).Bool() == true)
|
|
|
|
assert(t, (Result{Type: String, Str: "True"}).Bool() == true)
|
|
|
|
assert(t, (Result{Type: String, Str: "TRUE"}).Bool() == true)
|
|
|
|
assert(t, (Result{Type: String, Str: "tRuE"}).Bool() == true)
|
2020-05-30 13:34:47 +03:00
|
|
|
assert(t, (Result{Type: String, Str: "0"}).Bool() == false)
|
|
|
|
assert(t, (Result{Type: String, Str: "f"}).Bool() == false)
|
|
|
|
assert(t, (Result{Type: String, Str: "F"}).Bool() == false)
|
|
|
|
assert(t, (Result{Type: String, Str: "false"}).Bool() == false)
|
|
|
|
assert(t, (Result{Type: String, Str: "False"}).Bool() == false)
|
|
|
|
assert(t, (Result{Type: String, Str: "FALSE"}).Bool() == false)
|
|
|
|
assert(t, (Result{Type: String, Str: "fAlSe"}).Bool() == false)
|
|
|
|
assert(t, (Result{Type: String, Str: "random"}).Bool() == false)
|
|
|
|
|
2017-04-11 18:54:19 +03:00
|
|
|
// int
|
|
|
|
assert(t, (Result{Type: String, Str: "1"}).Int() == 1)
|
|
|
|
assert(t, (Result{Type: True}).Int() == 1)
|
|
|
|
assert(t, (Result{Type: False}).Int() == 0)
|
|
|
|
assert(t, (Result{Type: Number, Num: 1}).Int() == 1)
|
|
|
|
// uint
|
|
|
|
assert(t, (Result{Type: String, Str: "1"}).Uint() == 1)
|
|
|
|
assert(t, (Result{Type: True}).Uint() == 1)
|
|
|
|
assert(t, (Result{Type: False}).Uint() == 0)
|
|
|
|
assert(t, (Result{Type: Number, Num: 1}).Uint() == 1)
|
|
|
|
// float
|
|
|
|
assert(t, (Result{Type: String, Str: "1"}).Float() == 1)
|
|
|
|
assert(t, (Result{Type: True}).Float() == 1)
|
|
|
|
assert(t, (Result{Type: False}).Float() == 0)
|
|
|
|
assert(t, (Result{Type: Number, Num: 1}).Float() == 1)
|
|
|
|
}
|
|
|
|
func TestForEach(t *testing.T) {
|
|
|
|
Result{}.ForEach(nil)
|
|
|
|
Result{Type: String, Str: "Hello"}.ForEach(func(_, value Result) bool {
|
|
|
|
assert(t, value.String() == "Hello")
|
|
|
|
return false
|
|
|
|
})
|
|
|
|
Result{Type: JSON, Raw: "*invalid*"}.ForEach(nil)
|
|
|
|
|
|
|
|
json := ` {"name": {"first": "Janet","last": "Prichard"},
|
|
|
|
"asd\nf":"\ud83d\udd13","age": 47}`
|
|
|
|
var count int
|
|
|
|
ParseBytes([]byte(json)).ForEach(func(key, value Result) bool {
|
|
|
|
count++
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
assert(t, count == 3)
|
|
|
|
ParseBytes([]byte(`{"bad`)).ForEach(nil)
|
|
|
|
ParseBytes([]byte(`{"ok":"bad`)).ForEach(nil)
|
|
|
|
}
|
|
|
|
func TestMap(t *testing.T) {
|
|
|
|
assert(t, len(ParseBytes([]byte(`"asdf"`)).Map()) == 0)
|
2019-06-28 04:03:36 +03:00
|
|
|
assert(t, ParseBytes([]byte(`{"asdf":"ghjk"`)).Map()["asdf"].String() ==
|
|
|
|
"ghjk")
|
2017-04-11 18:54:19 +03:00
|
|
|
assert(t, len(Result{Type: JSON, Raw: "**invalid**"}.Map()) == 0)
|
|
|
|
assert(t, Result{Type: JSON, Raw: "**invalid**"}.Value() == nil)
|
|
|
|
assert(t, Result{Type: JSON, Raw: "{"}.Map() != nil)
|
|
|
|
}
|
2017-04-11 06:45:34 +03:00
|
|
|
func TestBasic1(t *testing.T) {
|
|
|
|
mtok := get(basicJSON, `loggy.programmers`)
|
2016-11-30 20:50:59 +03:00
|
|
|
var count int
|
|
|
|
mtok.ForEach(func(key, value Result) bool {
|
|
|
|
if key.Exists() {
|
|
|
|
t.Fatalf("expected %v, got %v", false, key.Exists())
|
|
|
|
}
|
|
|
|
count++
|
|
|
|
if count == 3 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if count == 1 {
|
|
|
|
i := 0
|
|
|
|
value.ForEach(func(key, value Result) bool {
|
|
|
|
switch i {
|
|
|
|
case 0:
|
2019-06-28 04:03:36 +03:00
|
|
|
if key.String() != "firstName" ||
|
|
|
|
value.String() != "Brett" {
|
|
|
|
t.Fatalf("expected %v/%v got %v/%v", "firstName",
|
|
|
|
"Brett", key.String(), value.String())
|
2016-11-30 20:50:59 +03:00
|
|
|
}
|
|
|
|
case 1:
|
2019-06-28 04:03:36 +03:00
|
|
|
if key.String() != "lastName" ||
|
|
|
|
value.String() != "McLaughlin" {
|
|
|
|
t.Fatalf("expected %v/%v got %v/%v", "lastName",
|
|
|
|
"McLaughlin", key.String(), value.String())
|
2016-11-30 20:50:59 +03:00
|
|
|
}
|
|
|
|
case 2:
|
|
|
|
if key.String() != "email" || value.String() != "aaaa" {
|
2019-06-28 04:03:36 +03:00
|
|
|
t.Fatalf("expected %v/%v got %v/%v", "email", "aaaa",
|
|
|
|
key.String(), value.String())
|
2016-11-30 20:50:59 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
i++
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
if count != 3 {
|
|
|
|
t.Fatalf("expected %v, got %v", 3, count)
|
|
|
|
}
|
2017-04-11 06:45:34 +03:00
|
|
|
}
|
|
|
|
func TestBasic2(t *testing.T) {
|
|
|
|
mtok := get(basicJSON, `loggy.programmers.#[age=101].firstName`)
|
2016-09-08 18:08:53 +03:00
|
|
|
if mtok.String() != "1002.3" {
|
2016-11-30 17:52:25 +03:00
|
|
|
t.Fatalf("expected %v, got %v", "1002.3", mtok.String())
|
2016-09-08 18:08:53 +03:00
|
|
|
}
|
2019-06-28 04:03:36 +03:00
|
|
|
mtok = get(basicJSON,
|
|
|
|
`loggy.programmers.#[firstName != "Brett"].firstName`)
|
2016-12-01 00:38:08 +03:00
|
|
|
if mtok.String() != "Jason" {
|
|
|
|
t.Fatalf("expected %v, got %v", "Jason", mtok.String())
|
|
|
|
}
|
2016-12-01 00:32:17 +03:00
|
|
|
mtok = get(basicJSON, `loggy.programmers.#[firstName % "Bre*"].email`)
|
|
|
|
if mtok.String() != "aaaa" {
|
|
|
|
t.Fatalf("expected %v, got %v", "aaaa", mtok.String())
|
|
|
|
}
|
2018-10-28 02:20:01 +03:00
|
|
|
mtok = get(basicJSON, `loggy.programmers.#[firstName !% "Bre*"].email`)
|
|
|
|
if mtok.String() != "bbbb" {
|
|
|
|
t.Fatalf("expected %v, got %v", "bbbb", mtok.String())
|
|
|
|
}
|
2016-09-08 19:02:40 +03:00
|
|
|
mtok = get(basicJSON, `loggy.programmers.#[firstName == "Brett"].email`)
|
2016-08-31 23:23:20 +03:00
|
|
|
if mtok.String() != "aaaa" {
|
|
|
|
t.Fatalf("expected %v, got %v", "aaaa", mtok.String())
|
|
|
|
}
|
2016-09-08 19:02:40 +03:00
|
|
|
mtok = get(basicJSON, "loggy")
|
2016-08-22 16:05:51 +03:00
|
|
|
if mtok.Type != JSON {
|
|
|
|
t.Fatalf("expected %v, got %v", JSON, mtok.Type)
|
|
|
|
}
|
|
|
|
if len(mtok.Map()) != 1 {
|
|
|
|
t.Fatalf("expected %v, got %v", 1, len(mtok.Map()))
|
|
|
|
}
|
|
|
|
programmers := mtok.Map()["programmers"]
|
|
|
|
if programmers.Array()[1].Map()["firstName"].Str != "Jason" {
|
2019-06-28 04:03:36 +03:00
|
|
|
t.Fatalf("expected %v, got %v", "Jason",
|
|
|
|
mtok.Map()["programmers"].Array()[1].Map()["firstName"].Str)
|
2016-08-22 16:05:51 +03:00
|
|
|
}
|
2017-04-11 06:45:34 +03:00
|
|
|
}
|
|
|
|
func TestBasic3(t *testing.T) {
|
|
|
|
var mtok Result
|
2019-06-28 04:03:36 +03:00
|
|
|
if Parse(basicJSON).Get("loggy.programmers").Get("1").
|
|
|
|
Get("firstName").Str != "Jason" {
|
|
|
|
t.Fatalf("expected %v, got %v", "Jason", Parse(basicJSON).
|
|
|
|
Get("loggy.programmers").Get("1").Get("firstName").Str)
|
2016-08-22 16:05:51 +03:00
|
|
|
}
|
2016-08-11 06:07:45 +03:00
|
|
|
var token Result
|
2016-08-22 16:05:51 +03:00
|
|
|
if token = Parse("-102"); token.Num != -102 {
|
2017-04-10 21:41:19 +03:00
|
|
|
t.Fatalf("expected %v, got %v", -102, token.Num)
|
2016-08-22 16:05:51 +03:00
|
|
|
}
|
|
|
|
if token = Parse("102"); token.Num != 102 {
|
2017-04-10 21:41:19 +03:00
|
|
|
t.Fatalf("expected %v, got %v", 102, token.Num)
|
2016-08-22 16:05:51 +03:00
|
|
|
}
|
|
|
|
if token = Parse("102.2"); token.Num != 102.2 {
|
2017-04-10 21:41:19 +03:00
|
|
|
t.Fatalf("expected %v, got %v", 102.2, token.Num)
|
2016-08-21 16:51:36 +03:00
|
|
|
}
|
2016-08-22 16:05:51 +03:00
|
|
|
if token = Parse(`"hello"`); token.Str != "hello" {
|
2017-04-10 21:41:19 +03:00
|
|
|
t.Fatalf("expected %v, got %v", "hello", token.Str)
|
2016-08-21 16:51:36 +03:00
|
|
|
}
|
2016-08-22 16:05:51 +03:00
|
|
|
if token = Parse(`"\"he\nllo\""`); token.Str != "\"he\nllo\"" {
|
2017-04-10 21:41:19 +03:00
|
|
|
t.Fatalf("expected %v, got %v", "\"he\nllo\"", token.Str)
|
2016-08-22 16:05:51 +03:00
|
|
|
}
|
2016-09-08 19:02:40 +03:00
|
|
|
mtok = get(basicJSON, "loggy.programmers.#.firstName")
|
2016-08-22 16:05:51 +03:00
|
|
|
if len(mtok.Array()) != 4 {
|
|
|
|
t.Fatalf("expected 4, got %v", len(mtok.Array()))
|
|
|
|
}
|
|
|
|
for i, ex := range []string{"Brett", "Jason", "Elliotte", "1002.3"} {
|
|
|
|
if mtok.Array()[i].String() != ex {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", ex, mtok.Array()[i].String())
|
2016-08-21 16:51:36 +03:00
|
|
|
}
|
|
|
|
}
|
2016-09-08 19:02:40 +03:00
|
|
|
mtok = get(basicJSON, "loggy.programmers.#.asd")
|
2016-08-22 16:05:51 +03:00
|
|
|
if mtok.Type != JSON {
|
2017-04-10 21:41:19 +03:00
|
|
|
t.Fatalf("expected %v, got %v", JSON, mtok.Type)
|
2016-08-21 16:51:36 +03:00
|
|
|
}
|
2016-08-22 16:05:51 +03:00
|
|
|
if len(mtok.Array()) != 0 {
|
|
|
|
t.Fatalf("expected 0, got %v", len(mtok.Array()))
|
2016-08-21 16:51:36 +03:00
|
|
|
}
|
2017-04-11 06:45:34 +03:00
|
|
|
}
|
|
|
|
func TestBasic4(t *testing.T) {
|
2016-09-08 19:02:40 +03:00
|
|
|
if get(basicJSON, "items.3.tags.#").Num != 3 {
|
|
|
|
t.Fatalf("expected 3, got %v", get(basicJSON, "items.3.tags.#").Num)
|
2016-08-15 14:56:55 +03:00
|
|
|
}
|
2016-09-08 19:02:40 +03:00
|
|
|
if get(basicJSON, "items.3.points.1.#").Num != 2 {
|
2019-06-28 04:03:36 +03:00
|
|
|
t.Fatalf("expected 2, got %v",
|
|
|
|
get(basicJSON, "items.3.points.1.#").Num)
|
2016-08-15 14:56:55 +03:00
|
|
|
}
|
2016-09-08 19:02:40 +03:00
|
|
|
if get(basicJSON, "items.#").Num != 8 {
|
|
|
|
t.Fatalf("expected 6, got %v", get(basicJSON, "items.#").Num)
|
2016-08-15 14:56:55 +03:00
|
|
|
}
|
2016-09-08 19:02:40 +03:00
|
|
|
if get(basicJSON, "vals.#").Num != 4 {
|
|
|
|
t.Fatalf("expected 4, got %v", get(basicJSON, "vals.#").Num)
|
2016-08-15 14:56:55 +03:00
|
|
|
}
|
2016-09-08 19:02:40 +03:00
|
|
|
if !get(basicJSON, "name.last").Exists() {
|
2016-08-12 18:39:08 +03:00
|
|
|
t.Fatal("expected true, got false")
|
|
|
|
}
|
2017-04-11 06:45:34 +03:00
|
|
|
token := get(basicJSON, "name.here")
|
2016-08-11 06:07:45 +03:00
|
|
|
if token.String() != "B\\\"R" {
|
|
|
|
t.Fatal("expecting 'B\\\"R'", "got", token.String())
|
|
|
|
}
|
2016-09-08 19:02:40 +03:00
|
|
|
token = get(basicJSON, "arr.#")
|
2016-08-11 06:07:45 +03:00
|
|
|
if token.String() != "6" {
|
2018-07-11 04:10:33 +03:00
|
|
|
fmt.Printf("%#v\n", token)
|
|
|
|
t.Fatal("expecting 6", "got", token.String())
|
2016-08-11 06:07:45 +03:00
|
|
|
}
|
2016-09-08 19:02:40 +03:00
|
|
|
token = get(basicJSON, "arr.3.hello")
|
2016-08-11 06:07:45 +03:00
|
|
|
if token.String() != "world" {
|
|
|
|
t.Fatal("expecting 'world'", "got", token.String())
|
|
|
|
}
|
|
|
|
_ = token.Value().(string)
|
2016-09-08 19:02:40 +03:00
|
|
|
token = get(basicJSON, "name.first")
|
2016-08-11 06:07:45 +03:00
|
|
|
if token.String() != "tom" {
|
|
|
|
t.Fatal("expecting 'tom'", "got", token.String())
|
|
|
|
}
|
|
|
|
_ = token.Value().(string)
|
2016-09-08 19:02:40 +03:00
|
|
|
token = get(basicJSON, "name.last")
|
2017-04-18 19:28:51 +03:00
|
|
|
if token.String() != "" {
|
|
|
|
t.Fatal("expecting ''", "got", token.String())
|
2016-08-11 06:07:45 +03:00
|
|
|
}
|
|
|
|
if token.Value() != nil {
|
|
|
|
t.Fatal("should be nil")
|
|
|
|
}
|
2017-04-11 06:45:34 +03:00
|
|
|
}
|
|
|
|
func TestBasic5(t *testing.T) {
|
|
|
|
token := get(basicJSON, "age")
|
2016-08-11 06:07:45 +03:00
|
|
|
if token.String() != "100" {
|
|
|
|
t.Fatal("expecting '100'", "got", token.String())
|
|
|
|
}
|
|
|
|
_ = token.Value().(float64)
|
2016-09-08 19:02:40 +03:00
|
|
|
token = get(basicJSON, "happy")
|
2016-08-11 06:07:45 +03:00
|
|
|
if token.String() != "true" {
|
|
|
|
t.Fatal("expecting 'true'", "got", token.String())
|
|
|
|
}
|
|
|
|
_ = token.Value().(bool)
|
2016-09-08 19:02:40 +03:00
|
|
|
token = get(basicJSON, "immortal")
|
2016-08-11 06:07:45 +03:00
|
|
|
if token.String() != "false" {
|
|
|
|
t.Fatal("expecting 'false'", "got", token.String())
|
|
|
|
}
|
|
|
|
_ = token.Value().(bool)
|
2016-09-08 19:02:40 +03:00
|
|
|
token = get(basicJSON, "noop")
|
2016-08-11 06:07:45 +03:00
|
|
|
if token.String() != `{"what is a wren?":"a bird"}` {
|
2019-06-28 04:03:36 +03:00
|
|
|
t.Fatal("expecting '"+`{"what is a wren?":"a bird"}`+"'", "got",
|
|
|
|
token.String())
|
2016-08-11 06:07:45 +03:00
|
|
|
}
|
2016-08-22 16:05:51 +03:00
|
|
|
_ = token.Value().(map[string]interface{})
|
2016-08-11 06:07:45 +03:00
|
|
|
|
2016-09-08 19:02:40 +03:00
|
|
|
if get(basicJSON, "").Value() != nil {
|
2016-08-11 06:07:45 +03:00
|
|
|
t.Fatal("should be nil")
|
|
|
|
}
|
|
|
|
|
2016-09-08 19:02:40 +03:00
|
|
|
get(basicJSON, "vals.hello")
|
2016-08-22 16:05:51 +03:00
|
|
|
|
2019-06-28 04:03:36 +03:00
|
|
|
type msi = map[string]interface{}
|
|
|
|
type fi = []interface{}
|
|
|
|
mm := Parse(basicJSON).Value().(msi)
|
|
|
|
fn := mm["loggy"].(msi)["programmers"].(fi)[1].(msi)["firstName"].(string)
|
2016-08-22 16:05:51 +03:00
|
|
|
if fn != "Jason" {
|
|
|
|
t.Fatalf("expecting %v, got %v", "Jason", fn)
|
|
|
|
}
|
2016-08-11 06:07:45 +03:00
|
|
|
}
|
2016-08-24 23:26:44 +03:00
|
|
|
func TestUnicode(t *testing.T) {
|
|
|
|
var json = `{"key":0,"的情况下解":{"key":1,"的情况":2}}`
|
|
|
|
if Get(json, "的情况下解.key").Num != 1 {
|
|
|
|
t.Fatal("fail")
|
|
|
|
}
|
|
|
|
if Get(json, "的情况下解.的情况").Num != 2 {
|
|
|
|
t.Fatal("fail")
|
|
|
|
}
|
|
|
|
if Get(json, "的情况下解.的?况").Num != 2 {
|
|
|
|
t.Fatal("fail")
|
|
|
|
}
|
|
|
|
if Get(json, "的情况下解.的?*").Num != 2 {
|
|
|
|
t.Fatal("fail")
|
|
|
|
}
|
|
|
|
if Get(json, "的情况下解.*?况").Num != 2 {
|
|
|
|
t.Fatal("fail")
|
|
|
|
}
|
|
|
|
if Get(json, "的情?下解.*?况").Num != 2 {
|
|
|
|
t.Fatal("fail")
|
|
|
|
}
|
|
|
|
if Get(json, "的情下解.*?况").Num != 0 {
|
|
|
|
t.Fatal("fail")
|
|
|
|
}
|
|
|
|
}
|
2016-08-25 01:50:18 +03:00
|
|
|
|
2016-08-11 06:07:45 +03:00
|
|
|
func TestUnescape(t *testing.T) {
|
|
|
|
unescape(string([]byte{'\\', '\\', 0}))
|
|
|
|
unescape(string([]byte{'\\', '/', '\\', 'b', '\\', 'f'}))
|
|
|
|
}
|
|
|
|
func assert(t testing.TB, cond bool) {
|
|
|
|
if !cond {
|
2017-05-26 05:39:18 +03:00
|
|
|
panic("assert failed")
|
2016-08-11 06:07:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
func TestLess(t *testing.T) {
|
|
|
|
assert(t, !Result{Type: Null}.Less(Result{Type: Null}, true))
|
|
|
|
assert(t, Result{Type: Null}.Less(Result{Type: False}, true))
|
|
|
|
assert(t, Result{Type: Null}.Less(Result{Type: True}, true))
|
|
|
|
assert(t, Result{Type: Null}.Less(Result{Type: JSON}, true))
|
|
|
|
assert(t, Result{Type: Null}.Less(Result{Type: Number}, true))
|
|
|
|
assert(t, Result{Type: Null}.Less(Result{Type: String}, true))
|
|
|
|
assert(t, !Result{Type: False}.Less(Result{Type: Null}, true))
|
|
|
|
assert(t, Result{Type: False}.Less(Result{Type: True}, true))
|
2019-06-28 04:03:36 +03:00
|
|
|
assert(t, Result{Type: String, Str: "abc"}.Less(Result{Type: String,
|
|
|
|
Str: "bcd"}, true))
|
|
|
|
assert(t, Result{Type: String, Str: "ABC"}.Less(Result{Type: String,
|
|
|
|
Str: "abc"}, true))
|
|
|
|
assert(t, !Result{Type: String, Str: "ABC"}.Less(Result{Type: String,
|
|
|
|
Str: "abc"}, false))
|
|
|
|
assert(t, Result{Type: Number, Num: 123}.Less(Result{Type: Number,
|
|
|
|
Num: 456}, true))
|
|
|
|
assert(t, !Result{Type: Number, Num: 456}.Less(Result{Type: Number,
|
|
|
|
Num: 123}, true))
|
|
|
|
assert(t, !Result{Type: Number, Num: 456}.Less(Result{Type: Number,
|
|
|
|
Num: 456}, true))
|
2016-08-11 06:07:45 +03:00
|
|
|
assert(t, stringLessInsensitive("abcde", "BBCDE"))
|
|
|
|
assert(t, stringLessInsensitive("abcde", "bBCDE"))
|
|
|
|
assert(t, stringLessInsensitive("Abcde", "BBCDE"))
|
|
|
|
assert(t, stringLessInsensitive("Abcde", "bBCDE"))
|
|
|
|
assert(t, !stringLessInsensitive("bbcde", "aBCDE"))
|
|
|
|
assert(t, !stringLessInsensitive("bbcde", "ABCDE"))
|
|
|
|
assert(t, !stringLessInsensitive("Bbcde", "aBCDE"))
|
|
|
|
assert(t, !stringLessInsensitive("Bbcde", "ABCDE"))
|
|
|
|
assert(t, !stringLessInsensitive("abcde", "ABCDE"))
|
|
|
|
assert(t, !stringLessInsensitive("Abcde", "ABCDE"))
|
|
|
|
assert(t, !stringLessInsensitive("abcde", "ABCDE"))
|
|
|
|
assert(t, !stringLessInsensitive("ABCDE", "ABCDE"))
|
|
|
|
assert(t, !stringLessInsensitive("abcde", "abcde"))
|
|
|
|
assert(t, !stringLessInsensitive("123abcde", "123Abcde"))
|
|
|
|
assert(t, !stringLessInsensitive("123Abcde", "123Abcde"))
|
|
|
|
assert(t, !stringLessInsensitive("123Abcde", "123abcde"))
|
|
|
|
assert(t, !stringLessInsensitive("123abcde", "123abcde"))
|
|
|
|
assert(t, !stringLessInsensitive("124abcde", "123abcde"))
|
|
|
|
assert(t, !stringLessInsensitive("124Abcde", "123Abcde"))
|
|
|
|
assert(t, !stringLessInsensitive("124Abcde", "123abcde"))
|
|
|
|
assert(t, !stringLessInsensitive("124abcde", "123abcde"))
|
|
|
|
assert(t, stringLessInsensitive("124abcde", "125abcde"))
|
|
|
|
assert(t, stringLessInsensitive("124Abcde", "125Abcde"))
|
|
|
|
assert(t, stringLessInsensitive("124Abcde", "125abcde"))
|
|
|
|
assert(t, stringLessInsensitive("124abcde", "125abcde"))
|
|
|
|
}
|
|
|
|
|
2016-08-22 18:25:33 +03:00
|
|
|
func TestIssue6(t *testing.T) {
|
|
|
|
data := `{
|
|
|
|
"code": 0,
|
|
|
|
"msg": "",
|
|
|
|
"data": {
|
|
|
|
"sz002024": {
|
|
|
|
"qfqday": [
|
|
|
|
[
|
|
|
|
"2014-01-02",
|
|
|
|
"8.93",
|
|
|
|
"9.03",
|
|
|
|
"9.17",
|
|
|
|
"8.88",
|
|
|
|
"621143.00"
|
|
|
|
],
|
|
|
|
[
|
|
|
|
"2014-01-03",
|
|
|
|
"9.03",
|
|
|
|
"9.30",
|
|
|
|
"9.47",
|
|
|
|
"8.98",
|
|
|
|
"1624438.00"
|
|
|
|
]
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}`
|
|
|
|
|
|
|
|
var num []string
|
|
|
|
for _, v := range Get(data, "data.sz002024.qfqday.0").Array() {
|
|
|
|
num = append(num, v.String())
|
|
|
|
}
|
2016-08-22 18:26:44 +03:00
|
|
|
if fmt.Sprintf("%v", num) != "[2014-01-02 8.93 9.03 9.17 8.88 621143.00]" {
|
|
|
|
t.Fatalf("invalid result")
|
|
|
|
}
|
2016-08-22 18:25:33 +03:00
|
|
|
}
|
|
|
|
|
2016-08-19 21:22:59 +03:00
|
|
|
var exampleJSON = `{
|
|
|
|
"widget": {
|
|
|
|
"debug": "on",
|
|
|
|
"window": {
|
|
|
|
"title": "Sample Konfabulator Widget",
|
|
|
|
"name": "main_window",
|
|
|
|
"width": 500,
|
|
|
|
"height": 500
|
|
|
|
},
|
2016-08-25 17:21:53 +03:00
|
|
|
"image": {
|
2016-08-19 21:22:59 +03:00
|
|
|
"src": "Images/Sun.png",
|
|
|
|
"hOffset": 250,
|
|
|
|
"vOffset": 250,
|
|
|
|
"alignment": "center"
|
|
|
|
},
|
|
|
|
"text": {
|
|
|
|
"data": "Click Here",
|
|
|
|
"size": 36,
|
|
|
|
"style": "bold",
|
|
|
|
"vOffset": 100,
|
|
|
|
"alignment": "center",
|
|
|
|
"onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
|
2016-08-11 06:07:45 +03:00
|
|
|
}
|
|
|
|
}
|
2016-08-19 21:22:59 +03:00
|
|
|
}`
|
2016-08-11 06:07:45 +03:00
|
|
|
|
2016-08-25 17:21:53 +03:00
|
|
|
func TestNewParse(t *testing.T) {
|
|
|
|
//fmt.Printf("%v\n", parse2(exampleJSON, "widget").String())
|
|
|
|
}
|
|
|
|
|
2016-08-25 01:59:54 +03:00
|
|
|
func TestUnmarshalMap(t *testing.T) {
|
|
|
|
var m1 = Parse(exampleJSON).Value().(map[string]interface{})
|
|
|
|
var m2 map[string]interface{}
|
|
|
|
if err := json.Unmarshal([]byte(exampleJSON), &m2); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
b1, err := json.Marshal(m1)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
b2, err := json.Marshal(m2)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2021-04-19 19:18:03 +03:00
|
|
|
if !bytes.Equal(b1, b2) {
|
2016-08-25 01:59:54 +03:00
|
|
|
t.Fatal("b1 != b2")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-02 22:20:24 +03:00
|
|
|
func TestSingleArrayValue(t *testing.T) {
|
2016-11-02 23:45:25 +03:00
|
|
|
var json = `{"key": "value","key2":[1,2,3,4,"A"]}`
|
2016-11-02 22:20:24 +03:00
|
|
|
var result = Get(json, "key")
|
|
|
|
var array = result.Array()
|
|
|
|
if len(array) != 1 {
|
|
|
|
t.Fatal("array is empty")
|
|
|
|
}
|
|
|
|
if array[0].String() != "value" {
|
2017-04-10 21:41:19 +03:00
|
|
|
t.Fatalf("got %s, should be %s", array[0].String(), "value")
|
2016-11-02 22:20:24 +03:00
|
|
|
}
|
2016-11-02 23:45:25 +03:00
|
|
|
|
|
|
|
array = Get(json, "key2.#").Array()
|
|
|
|
if len(array) != 1 {
|
2017-04-10 21:41:19 +03:00
|
|
|
t.Fatalf("got '%v', expected '%v'", len(array), 1)
|
2016-11-02 23:45:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
array = Get(json, "key3").Array()
|
|
|
|
if len(array) != 0 {
|
2017-04-10 21:41:19 +03:00
|
|
|
t.Fatalf("got '%v', expected '%v'", len(array), 0)
|
2016-11-02 23:45:25 +03:00
|
|
|
}
|
|
|
|
|
2016-11-02 22:20:24 +03:00
|
|
|
}
|
|
|
|
|
2016-11-29 01:10:11 +03:00
|
|
|
var manyJSON = ` {
|
|
|
|
"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{
|
|
|
|
"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{
|
|
|
|
"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{
|
|
|
|
"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{
|
|
|
|
"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{
|
|
|
|
"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{
|
|
|
|
"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"a":{"hello":"world"
|
|
|
|
}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
|
|
|
|
"position":{"type":"Point","coordinates":[-115.24,33.09]},
|
|
|
|
"loves":["world peace"],
|
|
|
|
"name":{"last":"Anderson","first":"Nancy"},
|
|
|
|
"age":31
|
|
|
|
"":{"a":"emptya","b":"emptyb"},
|
|
|
|
"name.last":"Yellow",
|
|
|
|
"name.first":"Cat",
|
|
|
|
}`
|
|
|
|
|
2021-04-19 19:18:03 +03:00
|
|
|
var testWatchForFallback bool
|
2021-03-25 18:28:15 +03:00
|
|
|
|
2016-11-29 01:10:11 +03:00
|
|
|
func TestManyBasic(t *testing.T) {
|
|
|
|
testWatchForFallback = true
|
|
|
|
defer func() {
|
|
|
|
testWatchForFallback = false
|
|
|
|
}()
|
|
|
|
testMany := func(shouldFallback bool, expect string, paths ...string) {
|
2017-04-11 18:54:19 +03:00
|
|
|
results := GetManyBytes(
|
|
|
|
[]byte(manyJSON),
|
2016-11-29 01:10:11 +03:00
|
|
|
paths...,
|
|
|
|
)
|
|
|
|
if len(results) != len(paths) {
|
|
|
|
t.Fatalf("expected %v, got %v", len(paths), len(results))
|
|
|
|
}
|
|
|
|
if fmt.Sprintf("%v", results) != expect {
|
2017-04-18 19:28:51 +03:00
|
|
|
fmt.Printf("%v\n", paths)
|
2016-11-29 01:10:11 +03:00
|
|
|
t.Fatalf("expected %v, got %v", expect, results)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
testMany(false, "[Point]", "position.type")
|
|
|
|
testMany(false, `[emptya ["world peace"] 31]`, ".a", "loves", "age")
|
|
|
|
testMany(false, `[["world peace"]]`, "loves")
|
2019-06-28 04:03:36 +03:00
|
|
|
testMany(false, `[{"last":"Anderson","first":"Nancy"} Nancy]`, "name",
|
|
|
|
"name.first")
|
2017-04-18 19:28:51 +03:00
|
|
|
testMany(true, `[]`, strings.Repeat("a.", 40)+"hello")
|
2016-11-29 01:10:11 +03:00
|
|
|
res := Get(manyJSON, strings.Repeat("a.", 48)+"a")
|
|
|
|
testMany(true, `[`+res.String()+`]`, strings.Repeat("a.", 48)+"a")
|
|
|
|
// these should fallback
|
|
|
|
testMany(true, `[Cat Nancy]`, "name\\.first", "name.first")
|
|
|
|
testMany(true, `[world]`, strings.Repeat("a.", 70)+"hello")
|
|
|
|
}
|
2017-03-29 18:19:50 +03:00
|
|
|
func testMany(t *testing.T, json string, paths, expected []string) {
|
2017-04-11 18:54:19 +03:00
|
|
|
testManyAny(t, json, paths, expected, true)
|
|
|
|
testManyAny(t, json, paths, expected, false)
|
|
|
|
}
|
2019-06-28 04:03:36 +03:00
|
|
|
func testManyAny(t *testing.T, json string, paths, expected []string,
|
|
|
|
bytes bool) {
|
2017-03-29 03:04:10 +03:00
|
|
|
var result []Result
|
|
|
|
for i := 0; i < 2; i++ {
|
|
|
|
var which string
|
|
|
|
if i == 0 {
|
|
|
|
which = "Get"
|
|
|
|
result = nil
|
2017-03-29 18:19:50 +03:00
|
|
|
for j := 0; j < len(expected); j++ {
|
2017-04-11 18:54:19 +03:00
|
|
|
if bytes {
|
|
|
|
result = append(result, GetBytes([]byte(json), paths[j]))
|
|
|
|
} else {
|
|
|
|
result = append(result, Get(json, paths[j]))
|
|
|
|
}
|
2017-03-29 03:04:10 +03:00
|
|
|
}
|
|
|
|
} else if i == 1 {
|
|
|
|
which = "GetMany"
|
2017-04-11 18:54:19 +03:00
|
|
|
if bytes {
|
|
|
|
result = GetManyBytes([]byte(json), paths...)
|
|
|
|
} else {
|
|
|
|
result = GetMany(json, paths...)
|
|
|
|
}
|
2017-03-29 03:04:10 +03:00
|
|
|
}
|
2017-03-29 18:19:50 +03:00
|
|
|
for j := 0; j < len(expected); j++ {
|
|
|
|
if result[j].String() != expected[j] {
|
2019-06-28 04:03:36 +03:00
|
|
|
t.Fatalf("Using key '%s' for '%s'\nexpected '%v', got '%v'",
|
|
|
|
paths[j], which, expected[j], result[j].String())
|
2017-03-29 03:04:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-03-29 18:19:50 +03:00
|
|
|
func TestIssue20(t *testing.T) {
|
2019-06-28 04:03:36 +03:00
|
|
|
json := `{ "name": "FirstName", "name1": "FirstName1", ` +
|
|
|
|
`"address": "address1", "addressDetails": "address2", }`
|
2017-03-29 18:19:50 +03:00
|
|
|
paths := []string{"name", "name1", "address", "addressDetails"}
|
|
|
|
expected := []string{"FirstName", "FirstName1", "address1", "address2"}
|
2019-06-28 04:03:36 +03:00
|
|
|
t.Run("SingleMany", func(t *testing.T) {
|
|
|
|
testMany(t, json, paths,
|
|
|
|
expected)
|
|
|
|
})
|
2017-03-29 18:19:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestIssue21(t *testing.T) {
|
|
|
|
json := `{ "Level1Field1":3,
|
|
|
|
"Level1Field4":4,
|
|
|
|
"Level1Field2":{ "Level2Field1":[ "value1", "value2" ],
|
|
|
|
"Level2Field2":{ "Level3Field1":[ { "key1":"value1" } ] } } }`
|
2019-06-28 04:03:36 +03:00
|
|
|
paths := []string{"Level1Field1", "Level1Field2.Level2Field1",
|
|
|
|
"Level1Field2.Level2Field2.Level3Field1", "Level1Field4"}
|
|
|
|
expected := []string{"3", `[ "value1", "value2" ]`,
|
|
|
|
`[ { "key1":"value1" } ]`, "4"}
|
|
|
|
t.Run("SingleMany", func(t *testing.T) {
|
|
|
|
testMany(t, json, paths,
|
|
|
|
expected)
|
|
|
|
})
|
2017-03-29 18:19:50 +03:00
|
|
|
}
|
2017-03-29 03:04:10 +03:00
|
|
|
|
2016-11-29 01:10:11 +03:00
|
|
|
func TestRandomMany(t *testing.T) {
|
|
|
|
var lstr string
|
|
|
|
defer func() {
|
|
|
|
if v := recover(); v != nil {
|
|
|
|
println("'" + hex.EncodeToString([]byte(lstr)) + "'")
|
|
|
|
println("'" + lstr + "'")
|
|
|
|
panic(v)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
rand.Seed(time.Now().UnixNano())
|
|
|
|
b := make([]byte, 512)
|
|
|
|
for i := 0; i < 50000; i++ {
|
|
|
|
n, err := rand.Read(b[:rand.Int()%len(b)])
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
lstr = string(b[:n])
|
|
|
|
paths := make([]string, rand.Int()%64)
|
|
|
|
for i := range paths {
|
|
|
|
var b []byte
|
|
|
|
n := rand.Int() % 5
|
|
|
|
for j := 0; j < n; j++ {
|
|
|
|
if j > 0 {
|
|
|
|
b = append(b, '.')
|
|
|
|
}
|
|
|
|
nn := rand.Int() % 10
|
|
|
|
for k := 0; k < nn; k++ {
|
|
|
|
b = append(b, 'a'+byte(rand.Int()%26))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
paths[i] = string(b)
|
|
|
|
}
|
|
|
|
GetMany(lstr, paths...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-08 04:26:54 +03:00
|
|
|
var complicatedJSON = `
|
|
|
|
{
|
|
|
|
"tagged": "OK",
|
|
|
|
"Tagged": "KO",
|
|
|
|
"NotTagged": true,
|
|
|
|
"unsettable": 101,
|
|
|
|
"Nested": {
|
|
|
|
"Yellow": "Green",
|
|
|
|
"yellow": "yellow"
|
|
|
|
},
|
|
|
|
"nestedTagged": {
|
|
|
|
"Green": "Green",
|
|
|
|
"Map": {
|
|
|
|
"this": "that",
|
|
|
|
"and": "the other thing"
|
|
|
|
},
|
|
|
|
"Ints": {
|
|
|
|
"Uint": 99,
|
|
|
|
"Uint16": 16,
|
|
|
|
"Uint32": 32,
|
|
|
|
"Uint64": 65
|
|
|
|
},
|
|
|
|
"Uints": {
|
|
|
|
"int": -99,
|
|
|
|
"Int": -98,
|
|
|
|
"Int16": -16,
|
|
|
|
"Int32": -32,
|
|
|
|
"int64": -64,
|
|
|
|
"Int64": -65
|
|
|
|
},
|
|
|
|
"Uints": {
|
|
|
|
"Float32": 32.32,
|
|
|
|
"Float64": 64.64
|
|
|
|
},
|
|
|
|
"Byte": 254,
|
|
|
|
"Bool": true
|
|
|
|
},
|
|
|
|
"LeftOut": "you shouldn't be here",
|
|
|
|
"SelfPtr": {"tagged":"OK","nestedTagged":{"Ints":{"Uint32":32}}},
|
|
|
|
"SelfSlice": [{"tagged":"OK","nestedTagged":{"Ints":{"Uint32":32}}}],
|
|
|
|
"SelfSlicePtr": [{"tagged":"OK","nestedTagged":{"Ints":{"Uint32":32}}}],
|
|
|
|
"SelfPtrSlice": [{"tagged":"OK","nestedTagged":{"Ints":{"Uint32":32}}}],
|
|
|
|
"interface": "Tile38 Rocks!",
|
|
|
|
"Interface": "Please Download",
|
|
|
|
"Array": [0,2,3,4,5],
|
|
|
|
"time": "2017-05-07T13:24:43-07:00",
|
|
|
|
"Binary": "R0lGODlhPQBEAPeo",
|
|
|
|
"NonBinary": [9,3,100,115]
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
2018-06-13 21:46:59 +03:00
|
|
|
func testvalid(t *testing.T, json string, expect bool) {
|
|
|
|
t.Helper()
|
2017-05-09 03:33:03 +03:00
|
|
|
_, ok := validpayload([]byte(json), 0)
|
|
|
|
if ok != expect {
|
2018-06-13 21:46:59 +03:00
|
|
|
t.Fatal("mismatch")
|
2017-05-09 03:33:03 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestValidBasic(t *testing.T) {
|
2018-06-13 21:46:59 +03:00
|
|
|
testvalid(t, "0", true)
|
|
|
|
testvalid(t, "00", false)
|
|
|
|
testvalid(t, "-00", false)
|
|
|
|
testvalid(t, "-.", false)
|
2021-03-29 04:30:25 +03:00
|
|
|
testvalid(t, "-.123", false)
|
2018-06-13 21:46:59 +03:00
|
|
|
testvalid(t, "0.0", true)
|
|
|
|
testvalid(t, "10.0", true)
|
|
|
|
testvalid(t, "10e1", true)
|
|
|
|
testvalid(t, "10EE", false)
|
|
|
|
testvalid(t, "10E-", false)
|
|
|
|
testvalid(t, "10E+", false)
|
|
|
|
testvalid(t, "10E123", true)
|
|
|
|
testvalid(t, "10E-123", true)
|
|
|
|
testvalid(t, "10E-0123", true)
|
|
|
|
testvalid(t, "", false)
|
|
|
|
testvalid(t, " ", false)
|
|
|
|
testvalid(t, "{}", true)
|
|
|
|
testvalid(t, "{", false)
|
|
|
|
testvalid(t, "-", false)
|
|
|
|
testvalid(t, "-1", true)
|
|
|
|
testvalid(t, "-1.", false)
|
|
|
|
testvalid(t, "-1.0", true)
|
|
|
|
testvalid(t, " -1.0", true)
|
|
|
|
testvalid(t, " -1.0 ", true)
|
|
|
|
testvalid(t, "-1.0 ", true)
|
|
|
|
testvalid(t, "-1.0 i", false)
|
|
|
|
testvalid(t, "-1.0 i", false)
|
|
|
|
testvalid(t, "true", true)
|
|
|
|
testvalid(t, " true", true)
|
|
|
|
testvalid(t, " true ", true)
|
|
|
|
testvalid(t, " True ", false)
|
|
|
|
testvalid(t, " tru", false)
|
|
|
|
testvalid(t, "false", true)
|
|
|
|
testvalid(t, " false", true)
|
|
|
|
testvalid(t, " false ", true)
|
|
|
|
testvalid(t, " False ", false)
|
|
|
|
testvalid(t, " fals", false)
|
|
|
|
testvalid(t, "null", true)
|
|
|
|
testvalid(t, " null", true)
|
|
|
|
testvalid(t, " null ", true)
|
|
|
|
testvalid(t, " Null ", false)
|
|
|
|
testvalid(t, " nul", false)
|
|
|
|
testvalid(t, " []", true)
|
|
|
|
testvalid(t, " [true]", true)
|
|
|
|
testvalid(t, " [ true, null ]", true)
|
|
|
|
testvalid(t, " [ true,]", false)
|
|
|
|
testvalid(t, `{"hello":"world"}`, true)
|
|
|
|
testvalid(t, `{ "hello": "world" }`, true)
|
|
|
|
testvalid(t, `{ "hello": "world", }`, false)
|
|
|
|
testvalid(t, `{"a":"b",}`, false)
|
|
|
|
testvalid(t, `{"a":"b","a"}`, false)
|
|
|
|
testvalid(t, `{"a":"b","a":}`, false)
|
|
|
|
testvalid(t, `{"a":"b","a":1}`, true)
|
|
|
|
testvalid(t, `{"a":"b",2"1":2}`, false)
|
|
|
|
testvalid(t, `{"a":"b","a": 1, "c":{"hi":"there"} }`, true)
|
2019-06-28 04:03:36 +03:00
|
|
|
testvalid(t, `{"a":"b","a": 1, "c":{"hi":"there", "easy":["going",`+
|
|
|
|
`{"mixed":"bag"}]} }`, true)
|
2018-06-13 21:46:59 +03:00
|
|
|
testvalid(t, `""`, true)
|
|
|
|
testvalid(t, `"`, false)
|
|
|
|
testvalid(t, `"\n"`, true)
|
|
|
|
testvalid(t, `"\"`, false)
|
|
|
|
testvalid(t, `"\\"`, true)
|
|
|
|
testvalid(t, `"a\\b"`, true)
|
|
|
|
testvalid(t, `"a\\b\\\"a"`, true)
|
|
|
|
testvalid(t, `"a\\b\\\uFFAAa"`, true)
|
|
|
|
testvalid(t, `"a\\b\\\uFFAZa"`, false)
|
|
|
|
testvalid(t, `"a\\b\\\uFFA"`, false)
|
|
|
|
testvalid(t, string(complicatedJSON), true)
|
|
|
|
testvalid(t, string(exampleJSON), true)
|
2021-03-29 04:30:25 +03:00
|
|
|
testvalid(t, "[-]", false)
|
|
|
|
testvalid(t, "[-.123]", false)
|
2017-05-09 03:33:03 +03:00
|
|
|
}
|
|
|
|
|
2019-06-28 04:03:36 +03:00
|
|
|
var jsonchars = []string{"{", "[", ",", ":", "}", "]", "1", "0", "true",
|
|
|
|
"false", "null", `""`, `"\""`, `"a"`}
|
2017-05-09 03:33:03 +03:00
|
|
|
|
|
|
|
func makeRandomJSONChars(b []byte) {
|
|
|
|
var bb []byte
|
|
|
|
for len(bb) < len(b) {
|
|
|
|
bb = append(bb, jsonchars[rand.Int()%len(jsonchars)]...)
|
|
|
|
}
|
|
|
|
copy(b, bb[:len(b)])
|
|
|
|
}
|
2019-06-28 15:24:28 +03:00
|
|
|
|
2017-05-09 03:33:03 +03:00
|
|
|
func TestValidRandom(t *testing.T) {
|
|
|
|
rand.Seed(time.Now().UnixNano())
|
|
|
|
b := make([]byte, 100000)
|
|
|
|
start := time.Now()
|
|
|
|
for time.Since(start) < time.Second*3 {
|
|
|
|
n := rand.Int() % len(b)
|
|
|
|
rand.Read(b[:n])
|
|
|
|
validpayload(b[:n], 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
start = time.Now()
|
|
|
|
for time.Since(start) < time.Second*3 {
|
|
|
|
n := rand.Int() % len(b)
|
|
|
|
makeRandomJSONChars(b[:n])
|
|
|
|
validpayload(b[:n], 0)
|
|
|
|
}
|
|
|
|
}
|
2017-09-25 14:37:57 +03:00
|
|
|
|
|
|
|
func TestGetMany47(t *testing.T) {
|
2019-06-28 04:03:36 +03:00
|
|
|
json := `{"bar": {"id": 99, "mybar": "my mybar" }, "foo": ` +
|
|
|
|
`{"myfoo": [605]}}`
|
2017-09-25 14:37:57 +03:00
|
|
|
paths := []string{"foo.myfoo", "bar.id", "bar.mybar", "bar.mybarx"}
|
|
|
|
expected := []string{"[605]", "99", "my mybar", ""}
|
|
|
|
results := GetMany(json, paths...)
|
|
|
|
if len(expected) != len(results) {
|
|
|
|
t.Fatalf("expected %v, got %v", len(expected), len(results))
|
|
|
|
}
|
|
|
|
for i, path := range paths {
|
|
|
|
if results[i].String() != expected[i] {
|
2019-06-28 04:03:36 +03:00
|
|
|
t.Fatalf("expected '%v', got '%v' for path '%v'", expected[i],
|
|
|
|
results[i].String(), path)
|
2017-09-25 14:37:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-09-25 14:39:06 +03:00
|
|
|
|
|
|
|
func TestGetMany48(t *testing.T) {
|
|
|
|
json := `{"bar": {"id": 99, "xyz": "my xyz"}, "foo": {"myfoo": [605]}}`
|
|
|
|
paths := []string{"foo.myfoo", "bar.id", "bar.xyz", "bar.abc"}
|
|
|
|
expected := []string{"[605]", "99", "my xyz", ""}
|
|
|
|
results := GetMany(json, paths...)
|
|
|
|
if len(expected) != len(results) {
|
|
|
|
t.Fatalf("expected %v, got %v", len(expected), len(results))
|
|
|
|
}
|
|
|
|
for i, path := range paths {
|
|
|
|
if results[i].String() != expected[i] {
|
2019-06-28 04:03:36 +03:00
|
|
|
t.Fatalf("expected '%v', got '%v' for path '%v'", expected[i],
|
|
|
|
results[i].String(), path)
|
2017-09-25 14:39:06 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-11-20 20:55:52 +03:00
|
|
|
|
|
|
|
func TestResultRawForLiteral(t *testing.T) {
|
|
|
|
for _, lit := range []string{"null", "true", "false"} {
|
|
|
|
result := Parse(lit)
|
|
|
|
if result.Raw != lit {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", lit, result.Raw)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-12-02 00:13:24 +03:00
|
|
|
|
|
|
|
func TestNullArray(t *testing.T) {
|
|
|
|
n := len(Get(`{"data":null}`, "data").Array())
|
|
|
|
if n != 0 {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", 0, n)
|
|
|
|
}
|
|
|
|
n = len(Get(`{}`, "data").Array())
|
|
|
|
if n != 0 {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", 0, n)
|
|
|
|
}
|
|
|
|
n = len(Get(`{"data":[]}`, "data").Array())
|
|
|
|
if n != 0 {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", 0, n)
|
|
|
|
}
|
|
|
|
n = len(Get(`{"data":[null]}`, "data").Array())
|
|
|
|
if n != 1 {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", 1, n)
|
|
|
|
}
|
|
|
|
}
|
2017-12-14 02:29:27 +03:00
|
|
|
|
|
|
|
func TestIssue54(t *testing.T) {
|
|
|
|
var r []Result
|
|
|
|
json := `{"MarketName":null,"Nounce":6115}`
|
|
|
|
r = GetMany(json, "Nounce", "Buys", "Sells", "Fills")
|
|
|
|
if strings.Replace(fmt.Sprintf("%v", r), " ", "", -1) != "[6115]" {
|
2019-06-28 04:03:36 +03:00
|
|
|
t.Fatalf("expected '%v', got '%v'", "[6115]",
|
|
|
|
strings.Replace(fmt.Sprintf("%v", r), " ", "", -1))
|
2017-12-14 02:29:27 +03:00
|
|
|
}
|
|
|
|
r = GetMany(json, "Nounce", "Buys", "Sells")
|
|
|
|
if strings.Replace(fmt.Sprintf("%v", r), " ", "", -1) != "[6115]" {
|
2019-06-28 04:03:36 +03:00
|
|
|
t.Fatalf("expected '%v', got '%v'", "[6115]",
|
|
|
|
strings.Replace(fmt.Sprintf("%v", r), " ", "", -1))
|
2017-12-14 02:29:27 +03:00
|
|
|
}
|
|
|
|
r = GetMany(json, "Nounce")
|
|
|
|
if strings.Replace(fmt.Sprintf("%v", r), " ", "", -1) != "[6115]" {
|
2019-06-28 04:03:36 +03:00
|
|
|
t.Fatalf("expected '%v', got '%v'", "[6115]",
|
|
|
|
strings.Replace(fmt.Sprintf("%v", r), " ", "", -1))
|
2017-12-14 02:29:27 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-22 16:58:04 +03:00
|
|
|
func TestIssue55(t *testing.T) {
|
|
|
|
json := `{"one": {"two": 2, "three": 3}, "four": 4, "five": 5}`
|
|
|
|
results := GetMany(json, "four", "five", "one.two", "one.six")
|
|
|
|
expected := []string{"4", "5", "2", ""}
|
|
|
|
for i, r := range results {
|
|
|
|
if r.String() != expected[i] {
|
|
|
|
t.Fatalf("expected %v, got %v", expected[i], r.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-01-23 15:45:05 +03:00
|
|
|
func TestIssue58(t *testing.T) {
|
|
|
|
json := `{"data":[{"uid": 1},{"uid": 2}]}`
|
|
|
|
res := Get(json, `data.#[uid!=1]`).Raw
|
|
|
|
if res != `{"uid": 2}` {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", `{"uid": 1}`, res)
|
|
|
|
}
|
|
|
|
}
|
Added support for JSON Lines
Added support for JSON Lines (http://jsonlines.org) using the `..` prefix.
Which when specified, treats the multi-lined document as an array.
For example:
```
{"name": "Gilbert", "age": 61}
{"name": "Alexa", "age": 34}
{"name": "May", "age": 57}
{"name": "Deloise", "age": 44}
```
```
..# >> 4
..1 >> {"name": "Alexa", "age": 34}
..3 >> {"name": "Deloise", "age": 44}
..#.name >> ["Gilbert","Alexa","May","Deloise"]
..#[name="May"].age >> 57
```
Closes #60
2018-02-10 01:41:16 +03:00
|
|
|
|
|
|
|
func TestObjectGrouping(t *testing.T) {
|
|
|
|
json := `
|
|
|
|
[
|
|
|
|
true,
|
|
|
|
{"name":"tom"},
|
|
|
|
false,
|
|
|
|
{"name":"janet"},
|
|
|
|
null
|
|
|
|
]
|
|
|
|
`
|
|
|
|
res := Get(json, "#.name")
|
|
|
|
if res.String() != `["tom","janet"]` {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", `["tom","janet"]`, res.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestJSONLines(t *testing.T) {
|
|
|
|
json := `
|
|
|
|
true
|
|
|
|
false
|
|
|
|
{"name":"tom"}
|
|
|
|
[1,2,3,4,5]
|
|
|
|
{"name":"janet"}
|
|
|
|
null
|
|
|
|
12930.1203
|
|
|
|
`
|
|
|
|
paths := []string{"..#", "..0", "..2.name", "..#.name", "..6", "..7"}
|
|
|
|
ress := []string{"7", "true", "tom", `["tom","janet"]`, "12930.1203", ""}
|
|
|
|
for i, path := range paths {
|
|
|
|
res := Get(json, path)
|
|
|
|
if res.String() != ress[i] {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", ress[i], res.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
json = `
|
|
|
|
{"name": "Gilbert", "wins": [["straight", "7♣"], ["one pair", "10♥"]]}
|
|
|
|
{"name": "Alexa", "wins": [["two pair", "4♠"], ["two pair", "9♠"]]}
|
|
|
|
{"name": "May", "wins": []}
|
|
|
|
{"name": "Deloise", "wins": [["three of a kind", "5♣"]]}
|
|
|
|
`
|
|
|
|
|
|
|
|
var i int
|
|
|
|
lines := strings.Split(strings.TrimSpace(json), "\n")
|
|
|
|
ForEachLine(json, func(line Result) bool {
|
|
|
|
if line.Raw != lines[i] {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", lines[i], line.Raw)
|
|
|
|
}
|
|
|
|
i++
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
if i != 4 {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", 4, i)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2018-07-11 04:10:33 +03:00
|
|
|
|
|
|
|
func TestNumUint64String(t *testing.T) {
|
2019-01-14 18:40:04 +03:00
|
|
|
var i int64 = 9007199254740993 //2^53 + 1
|
2018-07-11 04:10:33 +03:00
|
|
|
j := fmt.Sprintf(`{"data": [ %d, "hello" ] }`, i)
|
|
|
|
res := Get(j, "data.0")
|
|
|
|
if res.String() != "9007199254740993" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "9007199254740993", res.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNumInt64String(t *testing.T) {
|
2019-01-14 18:40:04 +03:00
|
|
|
var i int64 = -9007199254740993
|
2018-07-11 04:10:33 +03:00
|
|
|
j := fmt.Sprintf(`{"data":[ "hello", %d ]}`, i)
|
|
|
|
res := Get(j, "data.1")
|
|
|
|
if res.String() != "-9007199254740993" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "-9007199254740993", res.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNumBigString(t *testing.T) {
|
|
|
|
i := "900719925474099301239109123101" // very big
|
|
|
|
j := fmt.Sprintf(`{"data":[ "hello", "%s" ]}`, i)
|
|
|
|
res := Get(j, "data.1")
|
|
|
|
if res.String() != "900719925474099301239109123101" {
|
2019-06-28 04:03:36 +03:00
|
|
|
t.Fatalf("expected '%v', got '%v'", "900719925474099301239109123101",
|
|
|
|
res.String())
|
2018-07-11 04:10:33 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNumFloatString(t *testing.T) {
|
2019-01-14 18:40:04 +03:00
|
|
|
var i int64 = -9007199254740993
|
2018-07-11 04:10:33 +03:00
|
|
|
j := fmt.Sprintf(`{"data":[ "hello", %d ]}`, i) //No quotes around value!!
|
|
|
|
res := Get(j, "data.1")
|
|
|
|
if res.String() != "-9007199254740993" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "-9007199254740993", res.String())
|
|
|
|
}
|
|
|
|
}
|
2018-07-31 00:44:31 +03:00
|
|
|
|
|
|
|
func TestDuplicateKeys(t *testing.T) {
|
|
|
|
// this is vaild json according to the JSON spec
|
|
|
|
var json = `{"name": "Alex","name": "Peter"}`
|
|
|
|
if Parse(json).Get("name").String() !=
|
|
|
|
Parse(json).Map()["name"].String() {
|
|
|
|
t.Fatalf("expected '%v', got '%v'",
|
|
|
|
Parse(json).Get("name").String(),
|
|
|
|
Parse(json).Map()["name"].String(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
if !Valid(json) {
|
|
|
|
t.Fatal("should be valid")
|
|
|
|
}
|
|
|
|
}
|
2018-08-02 18:58:17 +03:00
|
|
|
|
|
|
|
func TestArrayValues(t *testing.T) {
|
|
|
|
var json = `{"array": ["PERSON1","PERSON2",0],}`
|
|
|
|
values := Get(json, "array").Array()
|
|
|
|
var output string
|
|
|
|
for i, val := range values {
|
|
|
|
if i > 0 {
|
|
|
|
output += "\n"
|
|
|
|
}
|
|
|
|
output += fmt.Sprintf("%#v", val)
|
|
|
|
}
|
|
|
|
expect := strings.Join([]string{
|
2019-06-28 04:03:36 +03:00
|
|
|
`gjson.Result{Type:3, Raw:"\"PERSON1\"", Str:"PERSON1", Num:0, ` +
|
|
|
|
`Index:0}`,
|
|
|
|
`gjson.Result{Type:3, Raw:"\"PERSON2\"", Str:"PERSON2", Num:0, ` +
|
|
|
|
`Index:0}`,
|
2018-08-02 18:58:17 +03:00
|
|
|
`gjson.Result{Type:2, Raw:"0", Str:"", Num:0, Index:0}`,
|
|
|
|
}, "\n")
|
|
|
|
if output != expect {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", expect, output)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2019-02-17 00:50:53 +03:00
|
|
|
|
|
|
|
func BenchmarkValid(b *testing.B) {
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
Valid(complicatedJSON)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkValidBytes(b *testing.B) {
|
|
|
|
complicatedJSON := []byte(complicatedJSON)
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
ValidBytes(complicatedJSON)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkGoStdlibValidBytes(b *testing.B) {
|
|
|
|
complicatedJSON := []byte(complicatedJSON)
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
json.Valid(complicatedJSON)
|
|
|
|
}
|
|
|
|
}
|
2019-02-17 04:29:39 +03:00
|
|
|
|
|
|
|
func TestModifier(t *testing.T) {
|
|
|
|
json := `{"other":{"hello":"world"},"arr":[1,2,3,4,5,6]}`
|
|
|
|
opts := *pretty.DefaultOptions
|
|
|
|
opts.SortKeys = true
|
|
|
|
exp := string(pretty.PrettyOptions([]byte(json), &opts))
|
|
|
|
res := Get(json, `@pretty:{"sortKeys":true}`).String()
|
|
|
|
if res != exp {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", exp, res)
|
|
|
|
}
|
|
|
|
res = Get(res, "@pretty|@reverse|@ugly").String()
|
|
|
|
if res != json {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", json, res)
|
|
|
|
}
|
2020-01-13 13:51:52 +03:00
|
|
|
if res := Get(res, "@this").String(); res != json {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", json, res)
|
|
|
|
}
|
|
|
|
if res := Get(res, "other.@this").String(); res != `{"hello":"world"}` {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", json, res)
|
|
|
|
}
|
2019-02-17 04:29:39 +03:00
|
|
|
res = Get(res, "@pretty|@reverse|arr|@reverse|2").String()
|
|
|
|
if res != "4" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "4", res)
|
|
|
|
}
|
|
|
|
AddModifier("case", func(json, arg string) string {
|
|
|
|
if arg == "upper" {
|
|
|
|
return strings.ToUpper(json)
|
|
|
|
}
|
|
|
|
if arg == "lower" {
|
|
|
|
return strings.ToLower(json)
|
|
|
|
}
|
|
|
|
return json
|
|
|
|
})
|
|
|
|
res = Get(json, "other|@case:upper").String()
|
|
|
|
if res != `{"HELLO":"WORLD"}` {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", `{"HELLO":"WORLD"}`, res)
|
|
|
|
}
|
|
|
|
}
|
2019-02-17 05:06:55 +03:00
|
|
|
|
|
|
|
func TestChaining(t *testing.T) {
|
|
|
|
json := `{
|
2019-06-28 03:51:42 +03:00
|
|
|
"info": {
|
|
|
|
"friends": [
|
|
|
|
{"first": "Dale", "last": "Murphy", "age": 44},
|
|
|
|
{"first": "Roger", "last": "Craig", "age": 68},
|
|
|
|
{"first": "Jane", "last": "Murphy", "age": 47}
|
|
|
|
]
|
|
|
|
}
|
2019-02-17 05:06:55 +03:00
|
|
|
}`
|
2019-06-28 03:51:42 +03:00
|
|
|
res := Get(json, "info.friends|0|first").String()
|
2019-02-17 05:06:55 +03:00
|
|
|
if res != "Dale" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "Dale", res)
|
|
|
|
}
|
2019-06-28 03:51:42 +03:00
|
|
|
res = Get(json, "info.friends|@reverse|0|age").String()
|
2019-02-17 05:06:55 +03:00
|
|
|
if res != "47" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "47", res)
|
|
|
|
}
|
2019-06-28 03:51:42 +03:00
|
|
|
res = Get(json, "@ugly|i\\nfo|friends.0.first").String()
|
|
|
|
if res != "Dale" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "Dale", res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSplitPipe(t *testing.T) {
|
|
|
|
split := func(t *testing.T, path, el, er string, eo bool) {
|
|
|
|
t.Helper()
|
|
|
|
left, right, ok := splitPossiblePipe(path)
|
|
|
|
// fmt.Printf("%-40s [%v] [%v] [%v]\n", path, left, right, ok)
|
|
|
|
if left != el || right != er || ok != eo {
|
|
|
|
t.Fatalf("expected '%v/%v/%v', got '%v/%v/%v",
|
|
|
|
el, er, eo, left, right, ok)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
split(t, "hello", "", "", false)
|
|
|
|
split(t, "hello.world", "", "", false)
|
|
|
|
split(t, "hello|world", "hello", "world", true)
|
|
|
|
split(t, "hello\\|world", "", "", false)
|
|
|
|
split(t, "hello.#", "", "", false)
|
|
|
|
split(t, `hello.#[a|1="asdf\"|1324"]#\|that`, "", "", false)
|
|
|
|
split(t, `hello.#[a|1="asdf\"|1324"]#|that.more|yikes`,
|
|
|
|
`hello.#[a|1="asdf\"|1324"]#`, "that.more|yikes", true)
|
|
|
|
split(t, `a.#[]#\|b`, "", "", false)
|
2019-02-17 05:06:55 +03:00
|
|
|
|
|
|
|
}
|
2019-06-28 01:50:15 +03:00
|
|
|
|
|
|
|
func TestArrayEx(t *testing.T) {
|
2019-06-28 03:51:42 +03:00
|
|
|
json := `
|
2019-06-28 01:50:15 +03:00
|
|
|
[
|
|
|
|
{
|
|
|
|
"c":[
|
|
|
|
{"a":10.11}
|
|
|
|
]
|
|
|
|
}, {
|
|
|
|
"c":[
|
|
|
|
{"a":11.11}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]`
|
2019-06-28 03:51:42 +03:00
|
|
|
res := Get(json, "@ugly|#.c.#[a=10.11]").String()
|
2019-06-28 01:50:15 +03:00
|
|
|
if res != `[{"a":10.11}]` {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", `[{"a":10.11}]`, res)
|
|
|
|
}
|
2019-06-28 03:51:42 +03:00
|
|
|
res = Get(json, "@ugly|#.c.#").String()
|
2019-06-28 01:50:15 +03:00
|
|
|
if res != `[1,1]` {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", `[1,1]`, res)
|
|
|
|
}
|
2019-06-28 03:51:42 +03:00
|
|
|
res = Get(json, "@reverse|0|c|0|a").String()
|
|
|
|
if res != "11.11" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "11.11", res)
|
|
|
|
}
|
|
|
|
res = Get(json, "#.c|#").String()
|
|
|
|
if res != "2" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "2", res)
|
|
|
|
}
|
2019-06-28 01:50:15 +03:00
|
|
|
}
|
2019-06-28 04:27:53 +03:00
|
|
|
|
|
|
|
func TestPipeDotMixing(t *testing.T) {
|
|
|
|
json := `{
|
|
|
|
"info": {
|
|
|
|
"friends": [
|
|
|
|
{"first": "Dale", "last": "Murphy", "age": 44},
|
|
|
|
{"first": "Roger", "last": "Craig", "age": 68},
|
|
|
|
{"first": "Jane", "last": "Murphy", "age": 47}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`
|
|
|
|
var res string
|
|
|
|
res = Get(json, `info.friends.#[first="Dale"].last`).String()
|
|
|
|
if res != "Murphy" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "Murphy", res)
|
|
|
|
}
|
|
|
|
res = Get(json, `info|friends.#[first="Dale"].last`).String()
|
|
|
|
if res != "Murphy" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "Murphy", res)
|
|
|
|
}
|
|
|
|
res = Get(json, `info|friends.#[first="Dale"]|last`).String()
|
|
|
|
if res != "Murphy" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "Murphy", res)
|
|
|
|
}
|
|
|
|
res = Get(json, `info|friends|#[first="Dale"]|last`).String()
|
|
|
|
if res != "Murphy" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "Murphy", res)
|
|
|
|
}
|
|
|
|
res = Get(json, `@ugly|info|friends|#[first="Dale"]|last`).String()
|
|
|
|
if res != "Murphy" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "Murphy", res)
|
|
|
|
}
|
|
|
|
res = Get(json, `@ugly|info.@ugly|friends|#[first="Dale"]|last`).String()
|
|
|
|
if res != "Murphy" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "Murphy", res)
|
|
|
|
}
|
|
|
|
res = Get(json, `@ugly.info|@ugly.friends|#[first="Dale"]|last`).String()
|
|
|
|
if res != "Murphy" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "Murphy", res)
|
|
|
|
}
|
|
|
|
}
|
2019-06-28 04:37:09 +03:00
|
|
|
|
|
|
|
func TestDeepSelectors(t *testing.T) {
|
|
|
|
json := `{
|
|
|
|
"info": {
|
|
|
|
"friends": [
|
|
|
|
{
|
|
|
|
"first": "Dale", "last": "Murphy",
|
|
|
|
"extra": [10,20,30],
|
|
|
|
"details": {
|
|
|
|
"city": "Tempe",
|
|
|
|
"state": "Arizona"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"first": "Roger", "last": "Craig",
|
|
|
|
"extra": [40,50,60],
|
|
|
|
"details": {
|
|
|
|
"city": "Phoenix",
|
|
|
|
"state": "Arizona"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`
|
|
|
|
var res string
|
|
|
|
res = Get(json, `info.friends.#[first="Dale"].extra.0`).String()
|
|
|
|
if res != "10" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "10", res)
|
|
|
|
}
|
|
|
|
res = Get(json, `info.friends.#[first="Dale"].extra|0`).String()
|
|
|
|
if res != "10" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "10", res)
|
|
|
|
}
|
|
|
|
res = Get(json, `info.friends.#[first="Dale"]|extra|0`).String()
|
|
|
|
if res != "10" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "10", res)
|
|
|
|
}
|
|
|
|
res = Get(json, `info.friends.#[details.city="Tempe"].last`).String()
|
|
|
|
if res != "Murphy" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "Murphy", res)
|
|
|
|
}
|
|
|
|
res = Get(json, `info.friends.#[details.city="Phoenix"].last`).String()
|
|
|
|
if res != "Craig" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "Craig", res)
|
|
|
|
}
|
|
|
|
res = Get(json, `info.friends.#[details.state="Arizona"].last`).String()
|
|
|
|
if res != "Murphy" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "Murphy", res)
|
|
|
|
}
|
|
|
|
}
|
2019-06-28 14:41:32 +03:00
|
|
|
|
|
|
|
func TestMultiArrayEx(t *testing.T) {
|
|
|
|
json := `{
|
|
|
|
"info": {
|
|
|
|
"friends": [
|
|
|
|
{
|
|
|
|
"first": "Dale", "last": "Murphy", "kind": "Person",
|
|
|
|
"cust1": true,
|
|
|
|
"extra": [10,20,30],
|
|
|
|
"details": {
|
|
|
|
"city": "Tempe",
|
|
|
|
"state": "Arizona"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"first": "Roger", "last": "Craig", "kind": "Person",
|
|
|
|
"cust2": false,
|
|
|
|
"extra": [40,50,60],
|
|
|
|
"details": {
|
|
|
|
"city": "Phoenix",
|
|
|
|
"state": "Arizona"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`
|
|
|
|
|
|
|
|
var res string
|
|
|
|
|
|
|
|
res = Get(json, `info.friends.#[kind="Person"]#.kind|0`).String()
|
|
|
|
if res != "Person" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "Person", res)
|
|
|
|
}
|
|
|
|
res = Get(json, `info.friends.#.kind|0`).String()
|
|
|
|
if res != "Person" {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", "Person", res)
|
|
|
|
}
|
|
|
|
|
|
|
|
res = Get(json, `info.friends.#[kind="Person"]#.kind`).String()
|
|
|
|
if res != `["Person","Person"]` {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", `["Person","Person"]`, res)
|
|
|
|
}
|
|
|
|
res = Get(json, `info.friends.#.kind`).String()
|
|
|
|
if res != `["Person","Person"]` {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", `["Person","Person"]`, res)
|
|
|
|
}
|
|
|
|
|
|
|
|
res = Get(json, `info.friends.#[kind="Person"]#|kind`).String()
|
|
|
|
if res != `` {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", ``, res)
|
|
|
|
}
|
|
|
|
res = Get(json, `info.friends.#|kind`).String()
|
|
|
|
if res != `` {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", ``, res)
|
|
|
|
}
|
|
|
|
|
2019-06-28 15:24:28 +03:00
|
|
|
res = Get(json, `i*.f*.#[kind="Other"]#`).String()
|
|
|
|
if res != `[]` {
|
|
|
|
t.Fatalf("expected '%v', got '%v'", `[]`, res)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestQueries(t *testing.T) {
|
|
|
|
json := `{
|
|
|
|
"info": {
|
|
|
|
"friends": [
|
|
|
|
{
|
|
|
|
"first": "Dale", "last": "Murphy", "kind": "Person",
|
|
|
|
"cust1": true,
|
|
|
|
"extra": [10,20,30],
|
|
|
|
"details": {
|
|
|
|
"city": "Tempe",
|
|
|
|
"state": "Arizona"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"first": "Roger", "last": "Craig", "kind": "Person",
|
|
|
|
"cust2": false,
|
|
|
|
"extra": [40,50,60],
|
|
|
|
"details": {
|
|
|
|
"city": "Phoenix",
|
|
|
|
"state": "Arizona"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`
|
|
|
|
|
|
|
|
// numbers
|
|
|
|
assert(t, Get(json, "i*.f*.#[extra.0<11].first").Exists())
|
|
|
|
assert(t, Get(json, "i*.f*.#[extra.0<=11].first").Exists())
|
|
|
|
assert(t, !Get(json, "i*.f*.#[extra.0<10].first").Exists())
|
|
|
|
assert(t, Get(json, "i*.f*.#[extra.0<=10].first").Exists())
|
|
|
|
assert(t, Get(json, "i*.f*.#[extra.0=10].first").Exists())
|
|
|
|
assert(t, !Get(json, "i*.f*.#[extra.0=11].first").Exists())
|
|
|
|
assert(t, Get(json, "i*.f*.#[extra.0!=10].first").String() == "Roger")
|
|
|
|
assert(t, Get(json, "i*.f*.#[extra.0>10].first").String() == "Roger")
|
|
|
|
assert(t, Get(json, "i*.f*.#[extra.0>=10].first").String() == "Dale")
|
|
|
|
|
|
|
|
// strings
|
|
|
|
assert(t, Get(json, `i*.f*.#[extra.0<"11"].first`).Exists())
|
|
|
|
assert(t, Get(json, `i*.f*.#[first>"Dale"].last`).String() == "Craig")
|
|
|
|
assert(t, Get(json, `i*.f*.#[first>="Dale"].last`).String() == "Murphy")
|
|
|
|
assert(t, Get(json, `i*.f*.#[first="Dale"].last`).String() == "Murphy")
|
|
|
|
assert(t, Get(json, `i*.f*.#[first!="Dale"].last`).String() == "Craig")
|
|
|
|
assert(t, !Get(json, `i*.f*.#[first<"Dale"].last`).Exists())
|
|
|
|
assert(t, Get(json, `i*.f*.#[first<="Dale"].last`).Exists())
|
|
|
|
assert(t, Get(json, `i*.f*.#[first%"Da*"].last`).Exists())
|
|
|
|
assert(t, Get(json, `i*.f*.#[first%"Dale"].last`).Exists())
|
|
|
|
assert(t, Get(json, `i*.f*.#[first%"*a*"]#|#`).String() == "1")
|
|
|
|
assert(t, Get(json, `i*.f*.#[first%"*e*"]#|#`).String() == "2")
|
|
|
|
assert(t, Get(json, `i*.f*.#[first!%"*e*"]#|#`).String() == "0")
|
|
|
|
|
|
|
|
// trues
|
|
|
|
assert(t, Get(json, `i*.f*.#[cust1=true].first`).String() == "Dale")
|
|
|
|
assert(t, Get(json, `i*.f*.#[cust2=false].first`).String() == "Roger")
|
|
|
|
assert(t, Get(json, `i*.f*.#[cust1!=false].first`).String() == "Dale")
|
|
|
|
assert(t, Get(json, `i*.f*.#[cust2!=true].first`).String() == "Roger")
|
|
|
|
assert(t, !Get(json, `i*.f*.#[cust1>true].first`).Exists())
|
|
|
|
assert(t, Get(json, `i*.f*.#[cust1>=true].first`).Exists())
|
|
|
|
assert(t, !Get(json, `i*.f*.#[cust2<false].first`).Exists())
|
|
|
|
assert(t, Get(json, `i*.f*.#[cust2<=false].first`).Exists())
|
|
|
|
|
2019-06-28 14:41:32 +03:00
|
|
|
}
|
2019-06-28 15:55:18 +03:00
|
|
|
|
|
|
|
func TestQueryArrayValues(t *testing.T) {
|
|
|
|
json := `{
|
|
|
|
"artists": [
|
|
|
|
["Bob Dylan"],
|
|
|
|
"John Lennon",
|
|
|
|
"Mick Jagger",
|
|
|
|
"Elton John",
|
|
|
|
"Michael Jackson",
|
|
|
|
"John Smith",
|
|
|
|
true,
|
|
|
|
123,
|
|
|
|
456,
|
|
|
|
false,
|
|
|
|
null
|
|
|
|
]
|
|
|
|
}`
|
|
|
|
assert(t, Get(json, `a*.#[0="Bob Dylan"]#|#`).String() == "1")
|
|
|
|
assert(t, Get(json, `a*.#[0="Bob Dylan 2"]#|#`).String() == "0")
|
|
|
|
assert(t, Get(json, `a*.#[%"John*"]#|#`).String() == "2")
|
2019-06-28 20:18:23 +03:00
|
|
|
assert(t, Get(json, `a*.#[_%"John*"]#|#`).String() == "0")
|
2019-06-28 15:55:18 +03:00
|
|
|
assert(t, Get(json, `a*.#[="123"]#|#`).String() == "1")
|
|
|
|
}
|
2019-06-29 21:31:27 +03:00
|
|
|
|
|
|
|
func TestParenQueries(t *testing.T) {
|
|
|
|
json := `{
|
|
|
|
"friends": [{"a":10},{"a":20},{"a":30},{"a":40}]
|
|
|
|
}`
|
|
|
|
assert(t, Get(json, "friends.#(a>9)#|#").Int() == 4)
|
|
|
|
assert(t, Get(json, "friends.#(a>10)#|#").Int() == 3)
|
|
|
|
assert(t, Get(json, "friends.#(a>40)#|#").Int() == 0)
|
|
|
|
}
|
Added Subselectors
It now possible to select multiple independent paths and join
their results into a single JSON document.
For example, given the following JSON
{
"info": {
"friends": [
{"first": "Dale", "last": "Murphy", "age": 44},
{"first": "Roger", "last": "Craig", "age": 68},
{"first": "Jane", "last": "Murphy", "age": 47}
]
}
}
The path `[info.friends.0.first,info.friends.1.last]` returns
["Dale","Craig"]
Or path `{info.friends.0.first,info.friends.1.last}` returns
{"first":"Dale","last":"Craig"}
You can also rename Object members such as
`{"alt1":info.friends.0.first,"alt2":info.friends.1.last}` returns
{"alt1":"Dale","alt2":"Craig"}
Finally you can combine this with any GJSON component
`info.friends.[0.first,1.age]` returns
["Dale",68]
This feature was request by @errashe in issue #113.
2019-06-30 01:23:32 +03:00
|
|
|
|
|
|
|
func TestSubSelectors(t *testing.T) {
|
|
|
|
json := `{
|
|
|
|
"info": {
|
|
|
|
"friends": [
|
|
|
|
{
|
|
|
|
"first": "Dale", "last": "Murphy", "kind": "Person",
|
|
|
|
"cust1": true,
|
|
|
|
"extra": [10,20,30],
|
|
|
|
"details": {
|
|
|
|
"city": "Tempe",
|
|
|
|
"state": "Arizona"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"first": "Roger", "last": "Craig", "kind": "Person",
|
|
|
|
"cust2": false,
|
|
|
|
"extra": [40,50,60],
|
|
|
|
"details": {
|
|
|
|
"city": "Phoenix",
|
|
|
|
"state": "Arizona"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`
|
|
|
|
assert(t, Get(json, "[]").String() == "[]")
|
|
|
|
assert(t, Get(json, "{}").String() == "{}")
|
|
|
|
res := Get(json, `{`+
|
|
|
|
`abc:info.friends.0.first,`+
|
|
|
|
`info.friends.1.last,`+
|
|
|
|
`"a`+"\r"+`a":info.friends.0.kind,`+
|
|
|
|
`"abc":info.friends.1.kind,`+
|
|
|
|
`{123:info.friends.1.cust2},`+
|
|
|
|
`[info.friends.#[details.city="Phoenix"]#|#]`+
|
|
|
|
`}.@pretty.@ugly`).String()
|
|
|
|
// println(res)
|
|
|
|
// {"abc":"Dale","last":"Craig","\"a\ra\"":"Person","_":{"123":false},"_":[1]}
|
|
|
|
assert(t, Get(res, "abc").String() == "Dale")
|
|
|
|
assert(t, Get(res, "last").String() == "Craig")
|
|
|
|
assert(t, Get(res, "\"a\ra\"").String() == "Person")
|
|
|
|
assert(t, Get(res, "@reverse.abc").String() == "Person")
|
|
|
|
assert(t, Get(res, "_.123").String() == "false")
|
|
|
|
assert(t, Get(res, "@reverse._.0").String() == "1")
|
|
|
|
assert(t, Get(json, "info.friends.[0.first,1.extra.0]").String() ==
|
|
|
|
`["Dale",40]`)
|
|
|
|
assert(t, Get(json, "info.friends.#.[first,extra.0]").String() ==
|
|
|
|
`[["Dale",10],["Roger",40]]`)
|
|
|
|
}
|
2019-06-30 14:48:53 +03:00
|
|
|
|
|
|
|
func TestArrayCountRawOutput(t *testing.T) {
|
|
|
|
assert(t, Get(`[1,2,3,4]`, "#").Raw == "4")
|
|
|
|
}
|
2019-07-12 16:14:45 +03:00
|
|
|
|
|
|
|
func TestParseQuery(t *testing.T) {
|
|
|
|
var path, op, value, remain string
|
|
|
|
var ok bool
|
|
|
|
|
2021-04-19 19:43:16 +03:00
|
|
|
path, op, value, remain, _, _, ok =
|
2019-07-12 16:14:45 +03:00
|
|
|
parseQuery(`#(service_roles.#(=="one").()==asdf).cap`)
|
|
|
|
assert(t, ok &&
|
|
|
|
path == `service_roles.#(=="one").()` &&
|
|
|
|
op == "=" &&
|
|
|
|
value == `asdf` &&
|
|
|
|
remain == `.cap`)
|
|
|
|
|
2021-04-19 19:43:16 +03:00
|
|
|
path, op, value, remain, _, _, ok = parseQuery(`#(first_name%"Murphy").last`)
|
2019-07-12 16:14:45 +03:00
|
|
|
assert(t, ok &&
|
|
|
|
path == `first_name` &&
|
|
|
|
op == `%` &&
|
|
|
|
value == `"Murphy"` &&
|
|
|
|
remain == `.last`)
|
|
|
|
|
2021-04-19 19:43:16 +03:00
|
|
|
path, op, value, remain, _, _, ok = parseQuery(`#( first_name !% "Murphy" ).last`)
|
2019-07-12 16:14:45 +03:00
|
|
|
assert(t, ok &&
|
|
|
|
path == `first_name` &&
|
|
|
|
op == `!%` &&
|
|
|
|
value == `"Murphy"` &&
|
|
|
|
remain == `.last`)
|
|
|
|
|
2021-04-19 19:43:16 +03:00
|
|
|
path, op, value, remain, _, _, ok = parseQuery(`#(service_roles.#(=="one"))`)
|
2019-07-12 16:14:45 +03:00
|
|
|
assert(t, ok &&
|
|
|
|
path == `service_roles.#(=="one")` &&
|
|
|
|
op == `` &&
|
|
|
|
value == `` &&
|
|
|
|
remain == ``)
|
|
|
|
|
2021-04-19 19:43:16 +03:00
|
|
|
path, op, value, remain, _, _, ok =
|
2019-07-12 16:14:45 +03:00
|
|
|
parseQuery(`#(a\("\"(".#(=="o\"(ne")%"ab\")").remain`)
|
|
|
|
assert(t, ok &&
|
|
|
|
path == `a\("\"(".#(=="o\"(ne")` &&
|
|
|
|
op == "%" &&
|
|
|
|
value == `"ab\")"` &&
|
|
|
|
remain == `.remain`)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestParentSubQuery(t *testing.T) {
|
|
|
|
var json = `{
|
|
|
|
"topology": {
|
|
|
|
"instances": [
|
|
|
|
{
|
|
|
|
"service_version": "1.2.3",
|
|
|
|
"service_locale": {"lang": "en"},
|
|
|
|
"service_roles": ["one", "two"]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"service_version": "1.2.4",
|
|
|
|
"service_locale": {"lang": "th"},
|
|
|
|
"service_roles": ["three", "four"]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"service_version": "1.2.2",
|
|
|
|
"service_locale": {"lang": "en"},
|
|
|
|
"service_roles": ["one"]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}`
|
|
|
|
res := Get(json, `topology.instances.#( service_roles.#(=="one"))#.service_version`)
|
|
|
|
// should return two instances
|
|
|
|
assert(t, res.String() == `["1.2.3","1.2.2"]`)
|
|
|
|
}
|
2019-07-15 17:54:31 +03:00
|
|
|
|
|
|
|
func TestSingleModifier(t *testing.T) {
|
|
|
|
var data = `{"@key": "value"}`
|
|
|
|
assert(t, Get(data, "@key").String() == "value")
|
|
|
|
assert(t, Get(data, "\\@key").String() == "value")
|
|
|
|
}
|
2019-11-01 15:08:48 +03:00
|
|
|
|
2019-11-01 15:15:43 +03:00
|
|
|
func TestModifiersInMultipaths(t *testing.T) {
|
2019-11-01 15:08:48 +03:00
|
|
|
AddModifier("case", func(json, arg string) string {
|
|
|
|
if arg == "upper" {
|
|
|
|
return strings.ToUpper(json)
|
|
|
|
}
|
|
|
|
if arg == "lower" {
|
|
|
|
return strings.ToLower(json)
|
|
|
|
}
|
|
|
|
return json
|
|
|
|
})
|
|
|
|
json := `{"friends": [
|
|
|
|
{"age": 44, "first": "Dale", "last": "Murphy"},
|
|
|
|
{"age": 68, "first": "Roger", "last": "Craig"},
|
|
|
|
{"age": 47, "first": "Jane", "last": "Murphy"}
|
|
|
|
]}`
|
|
|
|
|
|
|
|
res := Get(json, `friends.#.{age,first|@case:upper}|@ugly`)
|
|
|
|
exp := `[{"age":44,"@case:upper":"DALE"},{"age":68,"@case:upper":"ROGER"},{"age":47,"@case:upper":"JANE"}]`
|
|
|
|
assert(t, res.Raw == exp)
|
|
|
|
|
|
|
|
res = Get(json, `{friends.#.{age,first:first|@case:upper}|0.first}`)
|
|
|
|
exp = `{"first":"DALE"}`
|
|
|
|
assert(t, res.Raw == exp)
|
|
|
|
|
|
|
|
}
|
2019-11-03 00:52:36 +03:00
|
|
|
|
|
|
|
func TestIssue141(t *testing.T) {
|
|
|
|
json := `{"data": [{"q": 11, "w": 12}, {"q": 21, "w": 22}, {"q": 31, "w": 32} ], "sql": "some stuff here"}`
|
|
|
|
assert(t, Get(json, "data.#").Int() == 3)
|
|
|
|
assert(t, Get(json, "data.#.{q}|@ugly").Raw == `[{"q":11},{"q":21},{"q":31}]`)
|
|
|
|
assert(t, Get(json, "data.#.q|@ugly").Raw == `[11,21,31]`)
|
|
|
|
}
|
2019-11-18 19:51:37 +03:00
|
|
|
|
|
|
|
func TestChainedModifierStringArgs(t *testing.T) {
|
|
|
|
// issue #143
|
|
|
|
AddModifier("push", func(json, arg string) string {
|
|
|
|
json = strings.TrimSpace(json)
|
|
|
|
if len(json) < 2 || !Parse(json).IsArray() {
|
|
|
|
return json
|
|
|
|
}
|
|
|
|
json = strings.TrimSpace(json[1 : len(json)-1])
|
|
|
|
if len(json) == 0 {
|
|
|
|
return "[" + arg + "]"
|
|
|
|
}
|
|
|
|
return "[" + json + "," + arg + "]"
|
|
|
|
})
|
|
|
|
res := Get("[]", `@push:"2"|@push:"3"|@push:{"a":"b","c":["e","f"]}|@push:true|@push:10.23`)
|
|
|
|
assert(t, res.String() == `["2","3",{"a":"b","c":["e","f"]},true,10.23]`)
|
|
|
|
}
|
Added new modifiers
`@flatten` Flattens an array with child arrays.
[1,[2],[3,4],[5,[6,7]]] -> [1,2,3,4,5,[6,7]]
The {"deep":true} arg can be provide for deep flattening.
[1,[2],[3,4],[5,[6,7]]] -> [1,2,3,4,5,6,7]
The original json is returned when the json is not an array.
`@join` Joins multiple objects into a single object.
[{"first":"Tom"},{"last":"Smith"}] -> {"first","Tom","last":"Smith"}
The arg can be "true" to specify that duplicate keys should be preserved.
[{"first":"Tom","age":37},{"age":41}] -> {"first","Tom","age":37,"age":41}
Without preserved keys:
[{"first":"Tom","age":37},{"age":41}] -> {"first","Tom","age":41}
The original json is returned when the json is not an object.
`@valid` Ensures that the json is valid before moving on. An
empty string is returned when the json is not valid, otherwise
it returns the original json.
2020-02-10 21:13:30 +03:00
|
|
|
|
|
|
|
func TestFlatten(t *testing.T) {
|
|
|
|
json := `[1,[2],[3,4],[5,[6,[7]]],{"hi":"there"},8,[9]]`
|
|
|
|
assert(t, Get(json, "@flatten").String() == `[1,2,3,4,5,[6,[7]],{"hi":"there"},8,9]`)
|
|
|
|
assert(t, Get(json, `@flatten:{"deep":true}`).String() == `[1,2,3,4,5,6,7,{"hi":"there"},8,9]`)
|
|
|
|
assert(t, Get(`{"9999":1234}`, "@flatten").String() == `{"9999":1234}`)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestJoin(t *testing.T) {
|
|
|
|
assert(t, Get(`[{},{}]`, "@join").String() == `{}`)
|
|
|
|
assert(t, Get(`[{"a":1},{"b":2}]`, "@join").String() == `{"a":1,"b":2}`)
|
|
|
|
assert(t, Get(`[{"a":1,"b":1},{"b":2}]`, "@join").String() == `{"a":1,"b":2}`)
|
|
|
|
assert(t, Get(`[{"a":1,"b":1},{"b":2},5,{"c":3}]`, "@join").String() == `{"a":1,"b":2,"c":3}`)
|
|
|
|
assert(t, Get(`[{"a":1,"b":1},{"b":2},5,{"c":3}]`, `@join:{"preserve":true}`).String() == `{"a":1,"b":1,"b":2,"c":3}`)
|
|
|
|
assert(t, Get(`[{"a":1,"b":1},{"b":2},5,{"c":3}]`, `@join:{"preserve":true}.b`).String() == `1`)
|
|
|
|
assert(t, Get(`{"9999":1234}`, "@join").String() == `{"9999":1234}`)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestValid(t *testing.T) {
|
|
|
|
assert(t, Get("[{}", "@valid").Exists() == false)
|
|
|
|
assert(t, Get("[{}]", "@valid").Exists() == true)
|
|
|
|
}
|
|
|
|
|
|
|
|
// https://github.com/tidwall/gjson/issues/152
|
|
|
|
func TestJoin152(t *testing.T) {
|
|
|
|
var json = `{
|
|
|
|
"distance": 1374.0,
|
|
|
|
"validFrom": "2005-11-14",
|
|
|
|
"historical": {
|
|
|
|
"type": "Day",
|
|
|
|
"name": "last25Hours",
|
|
|
|
"summary": {
|
|
|
|
"units": {
|
|
|
|
"temperature": "C",
|
|
|
|
"wind": "m/s",
|
|
|
|
"snow": "cm",
|
|
|
|
"precipitation": "mm"
|
|
|
|
},
|
|
|
|
"days": [
|
|
|
|
{
|
|
|
|
"time": "2020-02-08",
|
|
|
|
"hours": [
|
|
|
|
{
|
|
|
|
"temperature": {
|
|
|
|
"min": -2.0,
|
|
|
|
"max": -1.6,
|
|
|
|
"value": -1.6
|
|
|
|
},
|
|
|
|
"wind": {},
|
|
|
|
"precipitation": {},
|
|
|
|
"humidity": {
|
|
|
|
"value": 92.0
|
|
|
|
},
|
|
|
|
"snow": {
|
|
|
|
"depth": 49.0
|
|
|
|
},
|
|
|
|
"time": "2020-02-08T16:00:00+01:00"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"temperature": {
|
|
|
|
"min": -1.7,
|
|
|
|
"max": -1.3,
|
|
|
|
"value": -1.3
|
|
|
|
},
|
|
|
|
"wind": {},
|
|
|
|
"precipitation": {},
|
|
|
|
"humidity": {
|
|
|
|
"value": 92.0
|
|
|
|
},
|
|
|
|
"snow": {
|
|
|
|
"depth": 49.0
|
|
|
|
},
|
|
|
|
"time": "2020-02-08T17:00:00+01:00"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"temperature": {
|
|
|
|
"min": -1.3,
|
|
|
|
"max": -0.9,
|
|
|
|
"value": -1.2
|
|
|
|
},
|
|
|
|
"wind": {},
|
|
|
|
"precipitation": {},
|
|
|
|
"humidity": {
|
|
|
|
"value": 91.0
|
|
|
|
},
|
|
|
|
"snow": {
|
|
|
|
"depth": 49.0
|
|
|
|
},
|
|
|
|
"time": "2020-02-08T18:00:00+01:00"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"time": "2020-02-09",
|
|
|
|
"hours": [
|
|
|
|
{
|
|
|
|
"temperature": {
|
|
|
|
"min": -1.7,
|
|
|
|
"max": -0.9,
|
|
|
|
"value": -1.5
|
|
|
|
},
|
|
|
|
"wind": {},
|
|
|
|
"precipitation": {},
|
|
|
|
"humidity": {
|
|
|
|
"value": 91.0
|
|
|
|
},
|
|
|
|
"snow": {
|
|
|
|
"depth": 49.0
|
|
|
|
},
|
|
|
|
"time": "2020-02-09T00:00:00+01:00"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"temperature": {
|
|
|
|
"min": -1.5,
|
|
|
|
"max": 0.9,
|
|
|
|
"value": 0.2
|
|
|
|
},
|
|
|
|
"wind": {},
|
|
|
|
"precipitation": {},
|
|
|
|
"humidity": {
|
|
|
|
"value": 67.0
|
|
|
|
},
|
|
|
|
"snow": {
|
|
|
|
"depth": 49.0
|
|
|
|
},
|
|
|
|
"time": "2020-02-09T01:00:00+01:00"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}`
|
|
|
|
|
|
|
|
res := Get(json, "historical.summary.days.#.hours|@flatten|#.humidity.value")
|
|
|
|
assert(t, res.Raw == `[92.0,92.0,91.0,91.0,67.0]`)
|
|
|
|
}
|
2020-12-07 15:25:20 +03:00
|
|
|
|
2020-12-25 16:42:20 +03:00
|
|
|
func TestVariousFuzz(t *testing.T) {
|
|
|
|
// Issue #192 assert(t, squash(`"000"hello`) == `"000"`)
|
2020-12-07 15:25:20 +03:00
|
|
|
assert(t, squash(`"000"`) == `"000"`)
|
|
|
|
assert(t, squash(`"000`) == `"000`)
|
|
|
|
assert(t, squash(`"`) == `"`)
|
|
|
|
|
|
|
|
assert(t, squash(`[000]hello`) == `[000]`)
|
|
|
|
assert(t, squash(`[000]`) == `[000]`)
|
|
|
|
assert(t, squash(`[000`) == `[000`)
|
|
|
|
assert(t, squash(`[`) == `[`)
|
|
|
|
assert(t, squash(`]`) == `]`)
|
|
|
|
|
|
|
|
testJSON := `0.#[[{}]].@valid:"000`
|
|
|
|
Get(testJSON, testJSON)
|
|
|
|
|
2020-12-25 16:42:20 +03:00
|
|
|
// Issue #195
|
|
|
|
testJSON = `\************************************` +
|
2020-12-23 15:00:23 +03:00
|
|
|
`**********{**",**,,**,**,**,**,"",**,**,**,**,**,**,**,**,**,**]`
|
|
|
|
Get(testJSON, testJSON)
|
2020-12-24 19:51:53 +03:00
|
|
|
|
2020-12-25 16:42:20 +03:00
|
|
|
// Issue #196
|
|
|
|
testJSON = `[#.@pretty.@join:{""[]""preserve"3,"][{]]]`
|
2020-12-24 19:51:53 +03:00
|
|
|
Get(testJSON, testJSON)
|
2020-12-25 16:42:20 +03:00
|
|
|
|
2020-12-24 19:51:53 +03:00
|
|
|
}
|
2021-03-22 14:19:47 +03:00
|
|
|
|
|
|
|
func TestSubpathsWithMultipaths(t *testing.T) {
|
|
|
|
const json = `
|
|
|
|
[
|
|
|
|
{"a": 1},
|
|
|
|
{"a": 2, "values": ["a", "b", "c", "d", "e"]},
|
|
|
|
true,
|
|
|
|
["a", "b", "c", "d", "e"],
|
|
|
|
4
|
|
|
|
]
|
|
|
|
`
|
|
|
|
assert(t, Get(json, `1.values.@ugly`).Raw == `["a","b","c","d","e"]`)
|
|
|
|
assert(t, Get(json, `1.values.[0,3]`).Raw == `["a","d"]`)
|
|
|
|
assert(t, Get(json, `3.@ugly`).Raw == `["a","b","c","d","e"]`)
|
|
|
|
assert(t, Get(json, `3.[0,3]`).Raw == `["a","d"]`)
|
|
|
|
assert(t, Get(json, `#.@ugly`).Raw == `[{"a":1},{"a":2,"values":["a","b","c","d","e"]},true,["a","b","c","d","e"],4]`)
|
|
|
|
assert(t, Get(json, `#.[0,3]`).Raw == `[[],[],[],["a","d"],[]]`)
|
|
|
|
}
|
2021-03-25 18:28:15 +03:00
|
|
|
|
|
|
|
func TestFlattenRemoveNonExist(t *testing.T) {
|
|
|
|
raw := Get("[[1],[2,[[],[3]],[4,[5],[],[[[6]]]]]]", `@flatten:{"deep":true}`).Raw
|
|
|
|
assert(t, raw == "[1,2,3,4,5,6]")
|
|
|
|
}
|
2021-03-26 01:31:00 +03:00
|
|
|
|
|
|
|
func TestPipeEmptyArray(t *testing.T) {
|
|
|
|
raw := Get("[]", `#(hello)#`).Raw
|
|
|
|
assert(t, raw == "[]")
|
|
|
|
}
|
2021-04-19 19:43:16 +03:00
|
|
|
|
|
|
|
func TestEncodedQueryString(t *testing.T) {
|
|
|
|
json := `{
|
|
|
|
"friends": [
|
|
|
|
{"first": "Dale", "last": "Mur\nphy", "age": 44},
|
|
|
|
{"first": "Roger", "last": "Craig", "age": 68},
|
|
|
|
{"first": "Jane", "last": "Murphy", "age": 47}
|
|
|
|
]
|
|
|
|
}`
|
|
|
|
assert(t, Get(json, `friends.#(last=="Mur\nphy").age`).Int() == 44)
|
|
|
|
assert(t, Get(json, `friends.#(last=="Murphy").age`).Int() == 47)
|
|
|
|
}
|
Add tilde boolean operator
This commit adds the new tilde '~' operator, which when used will
convert a value to a boolean before comparison.
For example, using the following JSON:
{
"vals": [
{ "a": 1, "b": true },
{ "a": 2, "b": true },
{ "a": 3, "b": false },
{ "a": 4, "b": "0" },
{ "a": 5, "b": 0 },
{ "a": 6, "b": "1" },
{ "a": 7, "b": 1 }
{ "a": 8, "b": "true" },
{ "a": 9, "b": false }
{ "a": 10, "b": null }
{ "a": 11 }
]
}
You can now query for all true(ish) values:
vals.#(b==~true)#
Which returns:
[1,2,6,7,8]
Or all false(ish) values:
vals.#(b==~false)#
Which returns:
[3,4,5,9,10,11]
The last value which was non-existent is treated as "false"
2021-05-14 18:53:58 +03:00
|
|
|
|
|
|
|
func TestBoolConvertQuery(t *testing.T) {
|
|
|
|
json := `{
|
|
|
|
"vals": [
|
|
|
|
{ "a": 1, "b": true },
|
|
|
|
{ "a": 2, "b": true },
|
|
|
|
{ "a": 3, "b": false },
|
|
|
|
{ "a": 4, "b": "0" },
|
|
|
|
{ "a": 5, "b": 0 },
|
|
|
|
{ "a": 6, "b": "1" },
|
2021-05-14 19:02:12 +03:00
|
|
|
{ "a": 7, "b": 1 },
|
Add tilde boolean operator
This commit adds the new tilde '~' operator, which when used will
convert a value to a boolean before comparison.
For example, using the following JSON:
{
"vals": [
{ "a": 1, "b": true },
{ "a": 2, "b": true },
{ "a": 3, "b": false },
{ "a": 4, "b": "0" },
{ "a": 5, "b": 0 },
{ "a": 6, "b": "1" },
{ "a": 7, "b": 1 }
{ "a": 8, "b": "true" },
{ "a": 9, "b": false }
{ "a": 10, "b": null }
{ "a": 11 }
]
}
You can now query for all true(ish) values:
vals.#(b==~true)#
Which returns:
[1,2,6,7,8]
Or all false(ish) values:
vals.#(b==~false)#
Which returns:
[3,4,5,9,10,11]
The last value which was non-existent is treated as "false"
2021-05-14 18:53:58 +03:00
|
|
|
{ "a": 8, "b": "true" },
|
2021-05-14 19:02:12 +03:00
|
|
|
{ "a": 9, "b": false },
|
|
|
|
{ "a": 10, "b": null },
|
Add tilde boolean operator
This commit adds the new tilde '~' operator, which when used will
convert a value to a boolean before comparison.
For example, using the following JSON:
{
"vals": [
{ "a": 1, "b": true },
{ "a": 2, "b": true },
{ "a": 3, "b": false },
{ "a": 4, "b": "0" },
{ "a": 5, "b": 0 },
{ "a": 6, "b": "1" },
{ "a": 7, "b": 1 }
{ "a": 8, "b": "true" },
{ "a": 9, "b": false }
{ "a": 10, "b": null }
{ "a": 11 }
]
}
You can now query for all true(ish) values:
vals.#(b==~true)#
Which returns:
[1,2,6,7,8]
Or all false(ish) values:
vals.#(b==~false)#
Which returns:
[3,4,5,9,10,11]
The last value which was non-existent is treated as "false"
2021-05-14 18:53:58 +03:00
|
|
|
{ "a": 11 }
|
|
|
|
]
|
|
|
|
}`
|
|
|
|
trues := Get(json, `vals.#(b==~true)#.a`).Raw
|
|
|
|
falses := Get(json, `vals.#(b==~false)#.a`).Raw
|
|
|
|
assert(t, trues == "[1,2,6,7,8]")
|
|
|
|
assert(t, falses == "[3,4,5,9,10,11]")
|
|
|
|
}
|