Skip to content

Commit

Permalink
Merge pull request #6 from danielgtaylor/query-cov
Browse files Browse the repository at this point in the history
fix: improved query test coverage
  • Loading branch information
danielgtaylor authored Oct 30, 2022
2 parents ee64257 + 38d70a6 commit eeb9de7
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 9 deletions.
14 changes: 5 additions & 9 deletions get.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,8 @@ func (d *Document) findPropRecursive(key, input any) ([]any, Error) {
return results, nil
}

func (d *Document) flatten(input any) (any, Error) {
// flatten nested arrays one level. Returns `nil` if the input is not an array.
func (d *Document) flatten(input any) any {
if d.options.DebugLogger != nil {
d.options.DebugLogger("Flattening %v", input)
}
Expand All @@ -376,9 +377,9 @@ func (d *Document) flatten(input any) (any, Error) {

out = append(out, item.([]any)...)
}
return out, nil
return out
}
return nil, nil
return nil
}

func (d *Document) getPath(input any) (any, bool, Error) {
Expand All @@ -396,10 +397,7 @@ outer:
// Special case: flatten one level
// [[1, 2], 3, [[4]]] => [1, 2, 3, [4]]
d.next()
input, err = d.flatten(input)
if err != nil {
return nil, false, err
}
input = d.flatten(input)
found = true
continue
}
Expand Down Expand Up @@ -481,11 +479,9 @@ func (d *Document) getFields(input any) (any, Error) {
for {
r = d.next()
if r == '"' {
d.buf.WriteRune('"')
if err := d.parseQuoted(true); err != nil {
return nil, err
}
d.buf.WriteRune('"')
continue
}
if r == '\\' {
Expand Down
144 changes: 144 additions & 0 deletions get_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ var getExamples = []struct {
Query: "field",
Go: "value",
},
{
Name: "Field escape",
Input: `{"a": "value"}`,
Query: `\u0061`,
Go: "value",
},
{
Name: "Field non string",
Input: map[any]any{
Expand All @@ -37,6 +43,18 @@ var getExamples = []struct {
Query: `f1.f2.f3`,
Go: true,
},
{
Name: "Nested fields with arrays",
Input: `{"f1": [{"f2": {"f3": true}}, {"missing": true}]}`,
Query: `f1.f2.f3`,
Go: []any{true},
},
{
Name: "Nested fields empty array",
Input: `{"f1": []}`,
Query: `f1.f2.f3`,
Go: nil,
},
{
Name: "Wildcard fields",
Input: `{"f1": {"unknown1": {"id": 1}, "unknown2": {"id": 2}}}`,
Expand Down Expand Up @@ -64,6 +82,21 @@ var getExamples = []struct {
Query: `..id`,
Go: []any{1.0, 2.0, 3.0},
},
{
Name: "Recursive fields any map",
Input: map[any]any{
"a": []any{
map[any]any{
"id": 1,
},
map[any]any{
"id": 2,
},
},
},
Query: `..id`,
Go: []any{1, 2},
},
{
Name: "Array index",
Input: `{"field": [1, 2, 3]}`,
Expand All @@ -82,6 +115,48 @@ var getExamples = []struct {
Query: `field[1][0][0]`,
Go: 1.0,
},
{
Name: "Array slice",
Input: `{"field": [0, 1, 2]}`,
Query: `field[0:1]`,
Go: []any{0.0, 1.0},
},
{
Name: "Array slice optional start",
Input: `{"field": [0, 1, 2]}`,
Query: `field[:1]`,
Go: []any{0.0, 1.0},
},
{
Name: "Array slice optional end",
Input: `{"field": [0, 1, 2]}`,
Query: `field[1:]`,
Go: []any{1.0, 2.0},
},
{
Name: "Index string",
Input: `{"field": "hello"}`,
Query: `field[1]`,
Go: "e",
},
{
Name: "Slice string",
Input: `{"field": "hello"}`,
Query: `field[1:]`,
Go: "ello",
},
{
Name: "Index bytes",
Input: map[string]any{"field": []byte("hello")},
Query: `field[1]`,
Go: uint8('e'),
},
{
Name: "Slice bytes",
Input: map[string]any{"field": []byte("hello")},
Query: `field[1:]`,
Go: []byte("ello"),
},
{
Name: "Array item fields",
Input: `{"items": [{"f1": {"f2": 1}}, {"f1": {"f2": 2}}, {"other": 3}]}`,
Expand All @@ -100,6 +175,12 @@ var getExamples = []struct {
Query: `items[@ startsWith a]`,
Go: []any{"a"},
},
{
Name: "Array item scalar filtering with ?",
Input: `{"items": ["a", "b", "c"]}`,
Query: `items[?@ startsWith a]`,
Go: []any{"a"},
},
{
Name: "Array item filtering",
Input: `{"items": [{"f1": {"f2": 1}}, {"f1": {"f2": 2}}, {"other": 3}]}`,
Expand All @@ -118,12 +199,39 @@ var getExamples = []struct {
Query: `items[@ startsWith a]|[0]`,
Go: "a",
},
{
Name: "Array filtering escape",
Input: `{"items": ["a", "b", "c"]}`,
Query: `items[@ startsWith \u0061]`,
Go: []any{"a"},
},
{
Name: "Field selection",
Input: `{"link": {"id": 1, "verified": true, "tags": ["a", "b"]}}`,
Query: `link.{id, tags}`,
Go: map[string]any{"id": 1.0, "tags": []any{"a", "b"}},
},
{
Name: "Field selection quoted",
Input: `{"link": {"id": 1, "verified": true, "tags ": ["a", "b"]}}`,
Query: `link.{"id", t: "tags "}`,
Go: map[string]any{"id": 1.0, "t": []any{"a", "b"}},
},
{
Name: "Field selection escaped",
Input: `{"link": {"a": true}}`,
Query: `link.{\u0061}`,
Go: map[string]any{"a": true},
},
{
Name: "Field selection map any",
Input: map[any]any{
"foo": "bar",
"baz": true,
},
Query: `{foo}`,
Go: map[string]any{"foo": "bar"},
},
{
Name: "Array field selection",
Input: `{"links": [{"rel": "next", "href": "..."}, {"rel": "prev", "href": "..."}]}`,
Expand All @@ -148,6 +256,42 @@ var getExamples = []struct {
Query: `{foo, tags: link.tags[@ startsWith a]|[0], id: link.id}`,
Go: map[string]any{"foo": "bar", "id": 1.0, "tags": "a"},
},
{
Name: "Unclosed filter",
Input: `{}`,
Query: `foo[`,
Error: "expected ']'",
},
{
Name: "Unclosed filter quote",
Input: `{}`,
Query: `foo["`,
Error: "Expected quote but found EOF",
},
{
Name: "Recursive prop unclosed quote",
Input: `{"foo": "bar"}`,
Query: `foo.."`,
Error: "Expected quote but found EOF",
},
{
Name: "Filter expr error",
Input: `{}`,
Query: `foo[1/0]"`,
Error: "cannot divide by zero",
},
{
Name: "Field select non-map",
Input: `[1, 2, 3]`,
Query: `{id}`,
Error: "field selection requires a map",
},
{
Name: "Field select unclosed",
Input: `[1, 2, 3]`,
Query: `{id`,
Error: "field selection requires a map",
},
}

func TestGet(t *testing.T) {
Expand Down

0 comments on commit eeb9de7

Please sign in to comment.