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
}
if !params[2].Known {
value = value.Slice(params[0].Value, params[1].Value)
} else {
value = value.Slice3(params[0].Value, params[1].Value, params[2].Value)
value = value.Slice(params[0].Value, params[1].Value)
step := 1
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))
}
}

View File

@ -40,12 +40,15 @@ func testJSONPath(tests []jsonpathTest, allowMissingKeys bool, t *testing.T) {
j.AllowMissingKeys(allowMissingKeys)
err := j.Parse(test.template)
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)
err = j.Execute(buf, test.input)
if test.expectError {
if test.expectError && err == nil {
if err == nil {
t.Errorf("in %s, expected execute error", test.name)
}
continue
@ -519,3 +522,133 @@ func TestNegativeIndex(t *testing.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 (
ErrSyntax = errors.New("invalid syntax")
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.

View File

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