Add basic linter config, decrease moduled Go version

master 1.0.0
Vladimir Hodakov 2019-10-19 00:39:21 +04:00
parent 6adf5bc3b9
commit f7b8e36f03
Signed by: Vladimir Hodakov
GPG Key ID: 673980B6882F82C6
7 changed files with 108 additions and 74 deletions

24
.golangci.yaml Normal file
View File

@ -0,0 +1,24 @@
run:
deadline: 2m
linters:
enable-all: true
disable:
- gochecknoglobals
- gocritic
- funlen
linters-settings:
lll:
line-length: 180
issues:
exclude-rules:
- path: _test\.go
linters:
- dupl
- errcheck
- gocritic
- gocyclo
- gosec
- lll
- goconst
- unparam
- unused

View File

@ -15,32 +15,32 @@ type test struct {
} }
var tests = []test{ var tests = []test{
test{`key selection`, `{"aKey":32}`, `$.aKey+`, []Result{newResult(`32`, JsonNumber, `aKey`)}}, {`key selection`, `{"aKey":32}`, `$.aKey+`, []Result{newResult(`32`, JsonNumber, `aKey`)}},
test{`nested key selection`, `{"aKey":{"bKey":32}}`, `$.aKey+`, []Result{newResult(`{"bKey":32}`, JsonObject, `aKey`)}}, {`nested key selection`, `{"aKey":{"bKey":32}}`, `$.aKey+`, []Result{newResult(`{"bKey":32}`, JsonObject, `aKey`)}},
test{`empty array`, `{"aKey":[]}`, `$.aKey+`, []Result{newResult(`[]`, JsonArray, `aKey`)}}, {`empty array`, `{"aKey":[]}`, `$.aKey+`, []Result{newResult(`[]`, JsonArray, `aKey`)}},
test{`multiple same-level keys, weird spacing`, `{ "aKey" : true , "bKey": [ 1 , 2 ], "cKey" : true } `, `$.bKey+`, []Result{newResult(`[1,2]`, JsonArray, `bKey`)}}, {`multiple same-level keys, weird spacing`, `{ "aKey" : true , "bKey": [ 1 , 2 ], "cKey" : true } `, `$.bKey+`, []Result{newResult(`[1,2]`, JsonArray, `bKey`)}},
test{`array index selection`, `{"aKey":[123,456]}`, `$.aKey[1]+`, []Result{newResult(`456`, JsonNumber, `aKey`, 1)}}, {`array index selection`, `{"aKey":[123,456]}`, `$.aKey[1]+`, []Result{newResult(`456`, JsonNumber, `aKey`, 1)}},
test{`array wild index selection`, `{"aKey":[123,456]}`, `$.aKey[*]+`, []Result{newResult(`123`, JsonNumber, `aKey`, 0), newResult(`456`, JsonNumber, `aKey`, 1)}}, {`array wild index selection`, `{"aKey":[123,456]}`, `$.aKey[*]+`, []Result{newResult(`123`, JsonNumber, `aKey`, 0), newResult(`456`, JsonNumber, `aKey`, 1)}},
test{`array range index selection`, `{"aKey":[11,22,33,44]}`, `$.aKey[1:3]+`, []Result{newResult(`22`, JsonNumber, `aKey`, 1), newResult(`33`, JsonNumber, `aKey`, 2)}}, {`array range index selection`, `{"aKey":[11,22,33,44]}`, `$.aKey[1:3]+`, []Result{newResult(`22`, JsonNumber, `aKey`, 1), newResult(`33`, JsonNumber, `aKey`, 2)}},
test{`array range (no index) selection`, `{"aKey":[11,22,33,44]}`, `$.aKey[1:1]+`, []Result{}}, {`array range (no index) selection`, `{"aKey":[11,22,33,44]}`, `$.aKey[1:1]+`, []Result{}},
test{`array range (no upper bound) selection`, `{"aKey":[11,22,33]}`, `$.aKey[1:]+`, []Result{newResult(`22`, JsonNumber, `aKey`, 1), newResult(`33`, JsonNumber, `aKey`, 2)}}, {`array range (no upper bound) selection`, `{"aKey":[11,22,33]}`, `$.aKey[1:]+`, []Result{newResult(`22`, JsonNumber, `aKey`, 1), newResult(`33`, JsonNumber, `aKey`, 2)}},
test{`empty array - try selection`, `{"aKey":[]}`, `$.aKey[1]+`, []Result{}}, {`empty array - try selection`, `{"aKey":[]}`, `$.aKey[1]+`, []Result{}},
test{`null selection`, `{"aKey":[null]}`, `$.aKey[0]+`, []Result{newResult(`null`, JsonNull, `aKey`, 0)}}, {`null selection`, `{"aKey":[null]}`, `$.aKey[0]+`, []Result{newResult(`null`, JsonNull, `aKey`, 0)}},
test{`empty object`, `{"aKey":{}}`, `$.aKey+`, []Result{newResult(`{}`, JsonObject, `aKey`)}}, {`empty object`, `{"aKey":{}}`, `$.aKey+`, []Result{newResult(`{}`, JsonObject, `aKey`)}},
test{`object w/ height=2`, `{"aKey":{"bKey":32}}`, `$.aKey.bKey+`, []Result{newResult(`32`, JsonNumber, `aKey`, `bKey`)}}, {`object w/ height=2`, `{"aKey":{"bKey":32}}`, `$.aKey.bKey+`, []Result{newResult(`32`, JsonNumber, `aKey`, `bKey`)}},
test{`array of multiple types`, `{"aKey":[1,{"s":true},"asdf"]}`, `$.aKey[1]+`, []Result{newResult(`{"s":true}`, JsonObject, `aKey`, 1)}}, {`array of multiple types`, `{"aKey":[1,{"s":true},"asdf"]}`, `$.aKey[1]+`, []Result{newResult(`{"s":true}`, JsonObject, `aKey`, 1)}},
test{`nested array selection`, `{"aKey":{"bKey":[123,456]}}`, `$.aKey.bKey+`, []Result{newResult(`[123,456]`, JsonArray, `aKey`, `bKey`)}}, {`nested array selection`, `{"aKey":{"bKey":[123,456]}}`, `$.aKey.bKey+`, []Result{newResult(`[123,456]`, JsonArray, `aKey`, `bKey`)}},
test{`nested array`, `[[[[[]], [true, false, []]]]]`, `$[0][0][1][2]+`, []Result{newResult(`[]`, JsonArray, 0, 0, 1, 2)}}, {`nested array`, `[[[[[]], [true, false, []]]]]`, `$[0][0][1][2]+`, []Result{newResult(`[]`, JsonArray, 0, 0, 1, 2)}},
test{`index of array selection`, `{"aKey":{"bKey":[123, 456, 789]}}`, `$.aKey.bKey[1]+`, []Result{newResult(`456`, JsonNumber, `aKey`, `bKey`, 1)}}, {`index of array selection`, `{"aKey":{"bKey":[123, 456, 789]}}`, `$.aKey.bKey[1]+`, []Result{newResult(`456`, JsonNumber, `aKey`, `bKey`, 1)}},
test{`index of array selection (more than one)`, `{"aKey":{"bKey":[123,456]}}`, `$.aKey.bKey[1]+`, []Result{newResult(`456`, JsonNumber, `aKey`, `bKey`, 1)}}, {`index of array selection (more than one)`, `{"aKey":{"bKey":[123,456]}}`, `$.aKey.bKey[1]+`, []Result{newResult(`456`, JsonNumber, `aKey`, `bKey`, 1)}},
test{`multi-level object/array`, `{"1Key":{"aKey": null, "bKey":{"trash":[1,2]}, "cKey":[123,456] }, "2Key":false}`, `$.1Key.bKey.trash[0]+`, []Result{newResult(`1`, JsonNumber, `1Key`, `bKey`, `trash`, 0)}}, {`multi-level object/array`, `{"1Key":{"aKey": null, "bKey":{"trash":[1,2]}, "cKey":[123,456] }, "2Key":false}`, `$.1Key.bKey.trash[0]+`, []Result{newResult(`1`, JsonNumber, `1Key`, `bKey`, `trash`, 0)}},
test{`multi-level array`, `{"aKey":[true,false,null,{"michael":[5,6,7]}, ["s", "3"] ]}`, `$.*[*].michael[1]+`, []Result{newResult(`6`, JsonNumber, `aKey`, 3, `michael`, 1)}}, {`multi-level array`, `{"aKey":[true,false,null,{"michael":[5,6,7]}, ["s", "3"] ]}`, `$.*[*].michael[1]+`, []Result{newResult(`6`, JsonNumber, `aKey`, 3, `michael`, 1)}},
test{`multi-level array 2`, `{"aKey":[true,false,null,{"michael":[5,6,7]}, ["s", "3"] ]}`, `$.*[*][1]+`, []Result{newResult(`"3"`, JsonString, `aKey`, 4, 1)}}, {`multi-level array 2`, `{"aKey":[true,false,null,{"michael":[5,6,7]}, ["s", "3"] ]}`, `$.*[*][1]+`, []Result{newResult(`"3"`, JsonString, `aKey`, 4, 1)}},
test{`evaluation literal equality`, `{"items":[ {"name":"alpha", "value":11}]}`, `$.items[*]?("bravo" == "bravo").value+`, []Result{newResult(`11`, JsonNumber, `items`, 0, `value`)}}, {`evaluation literal equality`, `{"items":[ {"name":"alpha", "value":11}]}`, `$.items[*]?("bravo" == "bravo").value+`, []Result{newResult(`11`, JsonNumber, `items`, 0, `value`)}},
test{`evaluation based on string equal to path value`, `{"items":[ {"name":"alpha", "value":11}, {"name":"bravo", "value":22}, {"name":"charlie", "value":33} ]}`, `$.items[*]?(@.name == "bravo").value+`, []Result{newResult(`22`, JsonNumber, `items`, 1, `value`)}}, {`evaluation based on string equal to path value`, `{"items":[ {"name":"alpha", "value":11}, {"name":"bravo", "value":22}, {"name":"charlie", "value":33} ]}`, `$.items[*]?(@.name == "bravo").value+`, []Result{newResult(`22`, JsonNumber, `items`, 1, `value`)}},
} }
func TestPathQuery(t *testing.T) { func TestPathQuery(t *testing.T) {

2
go.mod
View File

@ -1,5 +1,5 @@
module source.wtfteam.pro/libraries/jsonpath module source.wtfteam.pro/libraries/jsonpath
go 1.13 go 1.12
require github.com/stretchr/testify v1.4.0 require github.com/stretchr/testify v1.4.0

View File

@ -46,16 +46,16 @@ func lexJsonRoot(l lexer, state *intStack) stateFn {
var next stateFn var next stateFn
switch cur { switch cur {
case '{': case '{':
next = stateJsonObjectOpen next = stateJSONObjectOpen
case '[': case '[':
next = stateJsonArrayOpen next = stateJSONArrayOpen
default: default:
next = l.errorf("Expected '{' or '[' at root of JSON instead of %#U", cur) next = l.errorf("Expected '{' or '[' at root of JSON instead of %#U", cur)
} }
return next return next
} }
func stateJsonObjectOpen(l lexer, state *intStack) stateFn { func stateJSONObjectOpen(l lexer, state *intStack) stateFn {
cur := l.take() cur := l.take()
if cur != '{' { if cur != '{' {
return l.errorf("Expected '{' as start of object instead of %#U", cur) return l.errorf("Expected '{' as start of object instead of %#U", cur)
@ -63,10 +63,10 @@ func stateJsonObjectOpen(l lexer, state *intStack) stateFn {
l.emit(jsonBraceLeft) l.emit(jsonBraceLeft)
state.push(jsonBraceLeft) state.push(jsonBraceLeft)
return stateJsonObject return stateJSONObject
} }
func stateJsonArrayOpen(l lexer, state *intStack) stateFn { func stateJSONArrayOpen(l lexer, state *intStack) stateFn {
cur := l.take() cur := l.take()
if cur != '[' { if cur != '[' {
return l.errorf("Expected '[' as start of array instead of %#U", cur) return l.errorf("Expected '[' as start of array instead of %#U", cur)
@ -74,10 +74,10 @@ func stateJsonArrayOpen(l lexer, state *intStack) stateFn {
l.emit(jsonBracketLeft) l.emit(jsonBracketLeft)
state.push(jsonBracketLeft) state.push(jsonBracketLeft)
return stateJsonArray return stateJSONArray
} }
func stateJsonObject(l lexer, state *intStack) stateFn { func stateJSONObject(l lexer, state *intStack) stateFn {
var next stateFn var next stateFn
cur := l.peek() cur := l.peek()
switch cur { switch cur {
@ -89,16 +89,16 @@ func stateJsonObject(l lexer, state *intStack) stateFn {
l.take() l.take()
l.emit(jsonBraceRight) l.emit(jsonBraceRight)
state.pop() state.pop()
next = stateJsonAfterValue next = stateJSONAfterValue
case '"': case '"':
next = stateJsonKey next = stateJSONKey
default: default:
next = l.errorf("Expected '}' or \" within an object instead of %#U", cur) next = l.errorf("Expected '}' or \" within an object instead of %#U", cur)
} }
return next return next
} }
func stateJsonArray(l lexer, state *intStack) stateFn { func stateJSONArray(l lexer, state *intStack) stateFn {
var next stateFn var next stateFn
cur := l.peek() cur := l.peek()
switch cur { switch cur {
@ -110,14 +110,14 @@ func stateJsonArray(l lexer, state *intStack) stateFn {
l.take() l.take()
l.emit(jsonBracketRight) l.emit(jsonBracketRight)
state.pop() state.pop()
next = stateJsonAfterValue next = stateJSONAfterValue
default: default:
next = stateJsonValue next = stateJSONValue
} }
return next return next
} }
func stateJsonAfterValue(l lexer, state *intStack) stateFn { func stateJSONAfterValue(l lexer, state *intStack) stateFn {
cur := l.take() cur := l.take()
top, ok := state.peek() top, ok := state.peek()
topVal := noValue topVal := noValue
@ -130,9 +130,9 @@ func stateJsonAfterValue(l lexer, state *intStack) stateFn {
l.emit(jsonComma) l.emit(jsonComma)
switch topVal { switch topVal {
case jsonBraceLeft: case jsonBraceLeft:
return stateJsonKey return stateJSONKey
case jsonBracketLeft: case jsonBracketLeft:
return stateJsonValue return stateJSONValue
case noValue: case noValue:
return l.errorf("Found %#U outside of array or object", cur) return l.errorf("Found %#U outside of array or object", cur)
default: default:
@ -143,11 +143,11 @@ func stateJsonAfterValue(l lexer, state *intStack) stateFn {
state.pop() state.pop()
switch topVal { switch topVal {
case jsonBraceLeft: case jsonBraceLeft:
return stateJsonAfterValue return stateJSONAfterValue
case jsonBracketLeft: case jsonBracketLeft:
return l.errorf("Unexpected %#U in array", cur) return l.errorf("Unexpected %#U in array", cur)
case noValue: case noValue:
return stateJsonAfterRoot return stateJSONAfterRoot
} }
case ']': case ']':
l.emit(jsonBracketRight) l.emit(jsonBracketRight)
@ -156,9 +156,9 @@ func stateJsonAfterValue(l lexer, state *intStack) stateFn {
case jsonBraceLeft: case jsonBraceLeft:
return l.errorf("Unexpected %#U in object", cur) return l.errorf("Unexpected %#U in object", cur)
case jsonBracketLeft: case jsonBracketLeft:
return stateJsonAfterValue return stateJSONAfterValue
case noValue: case noValue:
return stateJsonAfterRoot return stateJSONAfterRoot
} }
case eof: case eof:
if state.len() == 0 { if state.len() == 0 {
@ -173,65 +173,65 @@ func stateJsonAfterValue(l lexer, state *intStack) stateFn {
return nil return nil
} }
func stateJsonKey(l lexer, state *intStack) stateFn { func stateJSONKey(l lexer, state *intStack) stateFn {
if err := l.takeString(); err != nil { if err := l.takeString(); err != nil {
return l.errorf(err.Error()) return l.errorf(err.Error())
} }
l.emit(jsonKey) l.emit(jsonKey)
return stateJsonColon return stateJSONColon
} }
func stateJsonColon(l lexer, state *intStack) stateFn { func stateJSONColon(l lexer, state *intStack) stateFn {
cur := l.take() cur := l.take()
if cur != ':' { if cur != ':' {
return l.errorf("Expected ':' after key string instead of %#U", cur) return l.errorf("Expected ':' after key string instead of %#U", cur)
} }
l.emit(jsonColon) l.emit(jsonColon)
return stateJsonValue return stateJSONValue
} }
func stateJsonValue(l lexer, state *intStack) stateFn { func stateJSONValue(l lexer, state *intStack) stateFn {
cur := l.peek() cur := l.peek()
switch cur { switch cur {
case eof: case eof:
return l.errorf("Unexpected EOF instead of value") return l.errorf("Unexpected EOF instead of value")
case '"': case '"':
return stateJsonString return stateJSONString
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return stateJsonNumber return stateJSONNumber
case 't', 'f': case 't', 'f':
return stateJsonBool return stateJSONBool
case 'n': case 'n':
return stateJsonNull return stateJSONNull
case '{': case '{':
return stateJsonObjectOpen return stateJSONObjectOpen
case '[': case '[':
return stateJsonArrayOpen return stateJSONArrayOpen
default: default:
return l.errorf("Unexpected character as start of value: %#U", cur) return l.errorf("Unexpected character as start of value: %#U", cur)
} }
} }
func stateJsonString(l lexer, state *intStack) stateFn { func stateJSONString(l lexer, state *intStack) stateFn {
if err := l.takeString(); err != nil { if err := l.takeString(); err != nil {
return l.errorf(err.Error()) return l.errorf(err.Error())
} }
l.emit(jsonString) l.emit(jsonString)
return stateJsonAfterValue return stateJSONAfterValue
} }
func stateJsonNumber(l lexer, state *intStack) stateFn { func stateJSONNumber(l lexer, state *intStack) stateFn {
if err := takeJSONNumeric(l); err != nil { if err := takeJSONNumeric(l); err != nil {
return l.errorf(err.Error()) return l.errorf(err.Error())
} }
l.emit(jsonNumber) l.emit(jsonNumber)
return stateJsonAfterValue return stateJSONAfterValue
} }
func stateJsonBool(l lexer, state *intStack) stateFn { func stateJSONBool(l lexer, state *intStack) stateFn {
cur := l.peek() cur := l.peek()
var match []byte var match []byte
switch cur { switch cur {
@ -245,18 +245,18 @@ func stateJsonBool(l lexer, state *intStack) stateFn {
return l.errorf("Could not parse value as 'true' or 'false'") return l.errorf("Could not parse value as 'true' or 'false'")
} }
l.emit(jsonBool) l.emit(jsonBool)
return stateJsonAfterValue return stateJSONAfterValue
} }
func stateJsonNull(l lexer, state *intStack) stateFn { func stateJSONNull(l lexer, state *intStack) stateFn {
if !takeExactSequence(l, nullBytes) { if !takeExactSequence(l, nullBytes) {
return l.errorf("Could not parse value as 'null'") return l.errorf("Could not parse value as 'null'")
} }
l.emit(jsonNull) l.emit(jsonNull)
return stateJsonAfterValue return stateJSONAfterValue
} }
func stateJsonAfterRoot(l lexer, state *intStack) stateFn { func stateJSONAfterRoot(l lexer, state *intStack) stateFn {
cur := l.take() cur := l.take()
if cur != eof { if cur != eof {
return l.errorf("Expected EOF instead of %#U", cur) return l.errorf("Expected EOF instead of %#U", cur)

View File

@ -159,7 +159,7 @@ var examples = []string{
}`, }`,
} }
func TestMixedCaseJson(t *testing.T) { func TestMixedCaseJSON(t *testing.T) {
as := assert.New(t) as := assert.New(t)
for _, json := range examples { for _, json := range examples {
lexer := NewSliceLexer([]byte(json), JSON) lexer := NewSliceLexer([]byte(json), JSON)

14
path.go
View File

@ -93,7 +93,9 @@ func genIndexKey(tr tokenReader) (*operator, error) {
return nil, fmt.Errorf("Unexpected value within brackets after index: %q", t.val) return nil, fmt.Errorf("Unexpected value within brackets after index: %q", t.val)
} }
case pathKey: case pathKey:
k.keyStrings = map[string]struct{}{string(t.val[1 : len(t.val)-1]): struct{}{}} k.keyStrings = map[string]struct{}{
string(t.val[1 : len(t.val)-1]): {},
}
k.typ = opTypeName k.typ = opTypeName
if t, ok = tr.next(); !ok || t.typ != pathBracketRight { if t, ok = tr.next(); !ok || t.typ != pathBracketRight {
@ -185,7 +187,15 @@ func tokensToOperators(tr tokenReader) (*Path, error) {
if p.val[0] == '"' && p.val[len(p.val)-1] == '"' { if p.val[0] == '"' && p.val[len(p.val)-1] == '"' {
keyName = p.val[1 : len(p.val)-1] keyName = p.val[1 : len(p.val)-1]
} }
q.operators = append(q.operators, &operator{typ: opTypeName, keyStrings: map[string]struct{}{string(keyName): struct{}{}}}) q.operators = append(
q.operators,
&operator{
typ: opTypeName,
keyStrings: map[string]struct{}{
string(keyName): {},
},
},
)
case pathWildcard: case pathWildcard:
q.operators = append(q.operators, &operator{typ: opTypeNameWild}) q.operators = append(q.operators, &operator{typ: opTypeNameWild})
case pathValue: case pathValue:

View File

@ -13,15 +13,15 @@ type optest struct {
} }
var optests = []optest{ var optests = []optest{
optest{"single key (period) ", `$.aKey`, []int{opTypeName}}, {"single key (period) ", `$.aKey`, []int{opTypeName}},
optest{"single key (bracket)", `$["aKey"]`, []int{opTypeName}}, {"single key (bracket)", `$["aKey"]`, []int{opTypeName}},
optest{"single key (period) ", `$.*`, []int{opTypeNameWild}}, {"single key (period) ", `$.*`, []int{opTypeNameWild}},
optest{"single index", `$[12]`, []int{opTypeIndex}}, {"single index", `$[12]`, []int{opTypeIndex}},
optest{"single key", `$[23:45]`, []int{opTypeIndexRange}}, {"single key", `$[23:45]`, []int{opTypeIndexRange}},
optest{"single key", `$[*]`, []int{opTypeIndexWild}}, {"single key", `$[*]`, []int{opTypeIndexWild}},
optest{"double key", `$["aKey"]["bKey"]`, []int{opTypeName, opTypeName}}, {"double key", `$["aKey"]["bKey"]`, []int{opTypeName, opTypeName}},
optest{"double key", `$["aKey"].bKey`, []int{opTypeName, opTypeName}}, {"double key", `$["aKey"].bKey`, []int{opTypeName, opTypeName}},
} }
func TestQueryOperators(t *testing.T) { func TestQueryOperators(t *testing.T) {