Fix jsonpath slice step handling

pull/564/head
Jordan Liggitt 2019-01-21 16:58:52 -05:00
parent f788854e98
commit 233d7e4962
4 changed files with 145 additions and 9 deletions

View File

@ -273,12 +273,16 @@ func (j *JSONPath) evalArray(input []reflect.Value, node *ArrayNode) ([]reflect.
return result, nil return result, nil
} }
if !params[2].Known { value = value.Slice(params[0].Value, params[1].Value)
value = value.Slice(params[0].Value, params[1].Value)
} else { step := 1
value = value.Slice3(params[0].Value, params[1].Value, params[2].Value) if params[2].Known {
if params[2].Value <= 0 {
return input, fmt.Errorf("step must be >= 0")
}
step = params[2].Value
} }
for i := 0; i < value.Len(); i++ { for i := 0; i < value.Len(); i += step {
result = append(result, value.Index(i)) result = append(result, value.Index(i))
} }
} }

View File

@ -40,12 +40,15 @@ func testJSONPath(tests []jsonpathTest, allowMissingKeys bool, t *testing.T) {
j.AllowMissingKeys(allowMissingKeys) j.AllowMissingKeys(allowMissingKeys)
err := j.Parse(test.template) err := j.Parse(test.template)
if err != nil { if err != nil {
t.Errorf("in %s, parse %s error %v", test.name, test.template, err) if !test.expectError {
t.Errorf("in %s, parse %s error %v", test.name, test.template, err)
}
continue
} }
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
err = j.Execute(buf, test.input) err = j.Execute(buf, test.input)
if test.expectError { if test.expectError {
if test.expectError && err == nil { if err == nil {
t.Errorf("in %s, expected execute error", test.name) t.Errorf("in %s, expected execute error", test.name)
} }
continue continue
@ -519,3 +522,133 @@ func TestNegativeIndex(t *testing.T) {
t, t,
) )
} }
func TestStep(t *testing.T) {
var input = []byte(
`{
"apiVersion": "v1",
"kind": "Pod",
"spec": {
"containers": [
{
"image": "radial/busyboxplus:curl",
"name": "fake0"
},
{
"image": "radial/busyboxplus:curl",
"name": "fake1"
},
{
"image": "radial/busyboxplus:curl",
"name": "fake2"
},
{
"image": "radial/busyboxplus:curl",
"name": "fake3"
},
{
"image": "radial/busyboxplus:curl",
"name": "fake4"
},
{
"image": "radial/busyboxplus:curl",
"name": "fake5"
}]}}`)
var data interface{}
err := json.Unmarshal(input, &data)
if err != nil {
t.Fatal(err)
}
testJSONPath(
[]jsonpathTest{
{
"test containers[0:], it equals containers[0:6:1]",
`{.spec.containers[0:].name}`,
data,
"fake0 fake1 fake2 fake3 fake4 fake5",
false,
},
{
"test containers[0:6:], it equals containers[0:6:1]",
`{.spec.containers[0:6:].name}`,
data,
"fake0 fake1 fake2 fake3 fake4 fake5",
false,
},
{
"test containers[0:6:1]",
`{.spec.containers[0:6:1].name}`,
data,
"fake0 fake1 fake2 fake3 fake4 fake5",
false,
},
{
"test containers[0:6:0], it errors",
`{.spec.containers[0:6:0].name}`,
data,
"",
true,
},
{
"test containers[0:6:-1], it errors",
`{.spec.containers[0:6:-1].name}`,
data,
"",
true,
},
{
"test containers[1:4:2]",
`{.spec.containers[1:4:2].name}`,
data,
"fake1 fake3",
false,
},
{
"test containers[1:4:3]",
`{.spec.containers[1:4:3].name}`,
data,
"fake1",
false,
},
{
"test containers[1:4:4]",
`{.spec.containers[1:4:4].name}`,
data,
"fake1",
false,
},
{
"test containers[0:6:2]",
`{.spec.containers[0:6:2].name}`,
data,
"fake0 fake2 fake4",
false,
},
{
"test containers[0:6:3]",
`{.spec.containers[0:6:3].name}`,
data,
"fake0 fake3",
false,
},
{
"test containers[0:6:5]",
`{.spec.containers[0:6:5].name}`,
data,
"fake0 fake5",
false,
},
{
"test containers[0:6:6]",
`{.spec.containers[0:6:6].name}`,
data,
"fake0",
false,
},
},
false,
t,
)
}

View File

@ -46,7 +46,7 @@ type Parser struct {
var ( var (
ErrSyntax = errors.New("invalid syntax") ErrSyntax = errors.New("invalid syntax")
dictKeyRex = regexp.MustCompile(`^'([^']*)'$`) dictKeyRex = regexp.MustCompile(`^'([^']*)'$`)
sliceOperatorRex = regexp.MustCompile(`^(-?[\d]*)(:-?[\d]*)?(:[\d]*)?$`) sliceOperatorRex = regexp.MustCompile(`^(-?[\d]*)(:-?[\d]*)?(:-?[\d]*)?$`)
) )
// Parse parsed the given text and return a node Parser. // Parse parsed the given text and return a node Parser.

View File

@ -140,7 +140,6 @@ func TestFailParser(t *testing.T) {
{"unrecognized character", "{*}", "unrecognized character in action: U+002A '*'"}, {"unrecognized character", "{*}", "unrecognized character in action: U+002A '*'"},
{"invalid number", "{+12.3.0}", "cannot parse number +12.3.0"}, {"invalid number", "{+12.3.0}", "cannot parse number +12.3.0"},
{"unterminated array", "{[1}", "unterminated array"}, {"unterminated array", "{[1}", "unterminated array"},
{"invalid index", "{[::-1]}", "invalid array index ::-1"},
{"unterminated filter", "{[?(.price]}", "unterminated filter"}, {"unterminated filter", "{[?(.price]}", "unterminated filter"},
} }
for _, test := range failParserTests { for _, test := range failParserTests {