neo-go/pkg/services/oracle/jsonpath/jsonpath_test.go
Evgeniy Stratonikov 1c30d8c395 oracle: make JSONPath compatible with C# implementation
C# node uses simplified implementation which is easy to port.
2021-05-13 11:53:28 +03:00

230 lines
8.1 KiB
Go

package jsonpath
import (
"encoding/json"
"math"
"strconv"
"testing"
"github.com/stretchr/testify/require"
)
type pathTestCase struct {
path string
result string
}
func unmarshalGet(t *testing.T, js string, path string) ([]interface{}, bool) {
var v interface{}
require.NoError(t, json.Unmarshal([]byte(js), &v))
return Get(path, v)
}
func (p *pathTestCase) testUnmarshalGet(t *testing.T, js string) {
res, ok := unmarshalGet(t, js, p.path)
require.True(t, ok)
data, err := json.Marshal(res)
require.NoError(t, err)
require.JSONEq(t, p.result, string(data))
}
func TestInvalidPaths(t *testing.T) {
bigNum := strconv.FormatInt(int64(math.MaxInt32)+1, 10)
// errCases contains invalid json path expressions.
// These are either invalid(&) or unexpected token in some positions
// or big number/invalid string.
errCases := []string{
".",
"$1",
"&",
"$&",
"$.&",
"$.[0]",
"$..",
"$..*",
"$..&",
"$..1",
"$[&]",
"$[**]",
"$[1&]",
"$[" + bigNum + "]",
"$[" + bigNum + ":]",
"$[:" + bigNum + "]",
"$[1," + bigNum + "]",
"$[" + bigNum + "[]]",
"$['a'&]",
"$['a'1]",
"$['a",
"$['\\u123']",
"$['s','\\u123']",
"$[[]]",
"$[1,'a']",
"$[1,1&",
"$[1,1[]]",
"$[1:&]",
"$[1:1[]]",
"$[1:[]]",
"$[1:[]]",
"$[",
}
for _, tc := range errCases {
t.Run(tc, func(t *testing.T) {
_, ok := unmarshalGet(t, "{}", tc)
require.False(t, ok)
})
}
}
func TestDescendByIdent(t *testing.T) {
js := `{
"store": {
"name": "big",
"sub": [
{ "name": "sub1" },
{ "name": "sub2" }
],
"partner": { "name": "ppp" }
},
"another": { "name": "small" }
}`
testCases := []pathTestCase{
{"$.store.name", `["big"]`},
{"$['store']['name']", `["big"]`},
{"$[*].name", `["small","big"]`},
{"$.*.name", `["small","big"]`},
{"$..store.name", `["big"]`},
{"$.store..name", `["big","ppp","sub1","sub2"]`},
{"$..sub[*].name", `["sub1","sub2"]`},
{"$..sub.name", `[]`},
{"$..sub..name", `["sub1","sub2"]`},
}
for _, tc := range testCases {
t.Run(tc.path, func(t *testing.T) {
tc.testUnmarshalGet(t, js)
})
}
}
func TestDescendByIndex(t *testing.T) {
js := `["a","b","c","d"]`
testCases := []pathTestCase{
{"$[0]", `["a"]`},
{"$[3]", `["d"]`},
{"$[1:2]", `["b"]`},
{"$[1:-1]", `["b","c"]`},
{"$[-3:-1]", `["b","c"]`},
{"$[-3:3]", `["b","c"]`},
{"$[:3]", `["a","b","c"]`},
{"$[:100]", `["a","b","c","d"]`},
{"$[1:]", `["b","c","d"]`},
{"$[2:1]", `[]`},
}
for _, tc := range testCases {
t.Run(tc.path, func(t *testing.T) {
tc.testUnmarshalGet(t, js)
})
}
t.Run("$[:][1], skip wrong types", func(t *testing.T) {
js := `[[1,2],{"1":"4"},[5,6]]`
p := pathTestCase{"$[:][1]", "[2,6]"}
p.testUnmarshalGet(t, js)
})
t.Run("$[*].*, flatten", func(t *testing.T) {
js := `[[1,2],{"1":"4"},[5,6]]`
p := pathTestCase{"$[*].*", "[1,2,\"4\",5,6]"}
p.testUnmarshalGet(t, js)
})
t.Run("$[*].[1:], skip wrong types", func(t *testing.T) {
js := `[[1,2],3,{"1":"4"},[5,6]]`
p := pathTestCase{"$[*][1:]", "[2,6]"}
p.testUnmarshalGet(t, js)
})
}
func TestUnion(t *testing.T) {
js := `["a",{"x":1,"y":2,"z":3},"c","d"]`
testCases := []pathTestCase{
{"$[0,2]", `["a","c"]`},
{"$[1]['x','z']", `[1,3]`},
}
for _, tc := range testCases {
t.Run(tc.path, func(t *testing.T) {
tc.testUnmarshalGet(t, js)
})
}
}
// These tests are taken directly from C# code.
func TestCSharpCompat(t *testing.T) {
js := `{
"store": {
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
},
"expensive": 10
}`
// FIXME(fyrchik): some tests are commented because of how maps are processed.
testCases := []pathTestCase{
{"$.store.book[*].author", `["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]`},
{"$..author", `["Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien"]`},
//{"$.store.*", `[[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}],{"color":"red","price":19.95}]`},
{"$.store..price", `[19.95,8.95,12.99,8.99,22.99]`},
{"$..book[2]", `[{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]`},
{"$..book[-2]", `[{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99}]`},
{"$..book[0,1]", `[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99}]`},
{"$..book[:2]", `[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99}]`},
{"$..book[1:2]", `[{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99}]`},
{"$..book[-2:]", `[{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]`},
{"$..book[2:]", `[{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}]`},
//{"$..*", `[{"book":[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}],"bicycle":{"color":"red","price":19.95}},10,[{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99}],{"color":"red","price":19.95},{"category":"reference","author":"Nigel Rees","title":"Sayings of the Century","price":8.95},{"category":"fiction","author":"Evelyn Waugh","title":"Sword of Honour","price":12.99},{"category":"fiction","author":"Herman Melville","title":"Moby Dick","isbn":"0-553-21311-3","price":8.99},{"category":"fiction","author":"J. R. R. Tolkien","title":"The Lord of the Rings","isbn":"0-395-19395-8","price":22.99},"red",19.95,"reference","Nigel Rees","Sayings of the Century",8.95,"fiction","Evelyn Waugh","Sword of Honour",12.99,"fiction","Herman Melville","Moby Dick","0-553-21311-3",8.99,"fiction","J. R. R. Tolkien","The Lord of the Rings","0-395-19395-8",22.99]`},
{"$..invalidfield", `[]`},
}
for _, tc := range testCases {
t.Run(tc.path, func(t *testing.T) {
tc.testUnmarshalGet(t, js)
})
}
}