...

Source file src/k8s.io/client-go/util/jsonpath/parser_test.go

Documentation: k8s.io/client-go/util/jsonpath

     1  /*
     2  Copyright 2015 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package jsonpath
    18  
    19  import (
    20  	"testing"
    21  )
    22  
    23  type parserTest struct {
    24  	name        string
    25  	text        string
    26  	nodes       []Node
    27  	shouldError bool
    28  }
    29  
    30  var parserTests = []parserTest{
    31  	{"plain", `hello jsonpath`, []Node{newText("hello jsonpath")}, false},
    32  	{"variable", `hello {.jsonpath}`,
    33  		[]Node{newText("hello "), newList(), newField("jsonpath")}, false},
    34  	{"arrayfiled", `hello {['jsonpath']}`,
    35  		[]Node{newText("hello "), newList(), newField("jsonpath")}, false},
    36  	{"quote", `{"{"}`, []Node{newList(), newText("{")}, false},
    37  	{"array", `{[1:3]}`, []Node{newList(),
    38  		newArray([3]ParamsEntry{{1, true, false}, {3, true, false}, {0, false, false}})}, false},
    39  	{"allarray", `{.book[*].author}`,
    40  		[]Node{newList(), newField("book"),
    41  			newArray([3]ParamsEntry{{0, false, false}, {0, false, false}, {0, false, false}}), newField("author")}, false},
    42  	{"wildcard", `{.bicycle.*}`,
    43  		[]Node{newList(), newField("bicycle"), newWildcard()}, false},
    44  	{"filter", `{[?(@.price<3)]}`,
    45  		[]Node{newList(), newFilter(newList(), newList(), "<"),
    46  			newList(), newField("price"), newList(), newInt(3)}, false},
    47  	{"recursive", `{..}`, []Node{newList(), newRecursive()}, false},
    48  	{"recurField", `{..price}`,
    49  		[]Node{newList(), newRecursive(), newField("price")}, false},
    50  	{"arraydict", `{['book.price']}`, []Node{newList(),
    51  		newField("book"), newField("price"),
    52  	}, false},
    53  	{"union", `{['bicycle.price', 3, 'book.price']}`, []Node{newList(), newUnion([]*ListNode{}),
    54  		newList(), newField("bicycle"), newField("price"),
    55  		newList(), newArray([3]ParamsEntry{{3, true, false}, {4, true, true}, {0, false, false}}),
    56  		newList(), newField("book"), newField("price"),
    57  	}, false},
    58  	{"range", `{range .items}{.name},{end}`, []Node{
    59  		newList(), newIdentifier("range"), newField("items"),
    60  		newList(), newField("name"), newText(","),
    61  		newList(), newIdentifier("end"),
    62  	}, false},
    63  	{"malformat input", `{\\\}`, []Node{}, true},
    64  	{"paired parentheses in quotes", `{[?(@.status.nodeInfo.osImage == "()")]}`,
    65  		[]Node{newList(), newFilter(newList(), newList(), "=="), newList(), newField("status"), newField("nodeInfo"), newField("osImage"), newList(), newText("()")}, false},
    66  	{"paired parentheses in double quotes and with double quotes escape", `{[?(@.status.nodeInfo.osImage == "(\"\")")]}`,
    67  		[]Node{newList(), newFilter(newList(), newList(), "=="), newList(), newField("status"), newField("nodeInfo"), newField("osImage"), newList(), newText("(\"\")")}, false},
    68  	{"unregular parentheses in double quotes", `{[?(@.test == "())(")]}`,
    69  		[]Node{newList(), newFilter(newList(), newList(), "=="), newList(), newField("test"), newList(), newText("())(")}, false},
    70  	{"plain text in single quotes", `{[?(@.status.nodeInfo.osImage == 'Linux')]}`,
    71  		[]Node{newList(), newFilter(newList(), newList(), "=="), newList(), newField("status"), newField("nodeInfo"), newField("osImage"), newList(), newText("Linux")}, false},
    72  	{"test filter suffix", `{[?(@.status.nodeInfo.osImage == "{[()]}")]}`,
    73  		[]Node{newList(), newFilter(newList(), newList(), "=="), newList(), newField("status"), newField("nodeInfo"), newField("osImage"), newList(), newText("{[()]}")}, false},
    74  	{"double inside single", `{[?(@.status.nodeInfo.osImage == "''")]}`,
    75  		[]Node{newList(), newFilter(newList(), newList(), "=="), newList(), newField("status"), newField("nodeInfo"), newField("osImage"), newList(), newText("''")}, false},
    76  	{"single inside double", `{[?(@.status.nodeInfo.osImage == '""')]}`,
    77  		[]Node{newList(), newFilter(newList(), newList(), "=="), newList(), newField("status"), newField("nodeInfo"), newField("osImage"), newList(), newText("\"\"")}, false},
    78  	{"single containing escaped single", `{[?(@.status.nodeInfo.osImage == '\\\'')]}`,
    79  		[]Node{newList(), newFilter(newList(), newList(), "=="), newList(), newField("status"), newField("nodeInfo"), newField("osImage"), newList(), newText("\\'")}, false},
    80  	{"negative index slice, equals a[len-5] to a[len-1]", `{[-5:]}`, []Node{newList(),
    81  		newArray([3]ParamsEntry{{-5, true, false}, {0, false, false}, {0, false, false}})}, false},
    82  	{"negative index slice, equals a[len-1]", `{[-1]}`, []Node{newList(),
    83  		newArray([3]ParamsEntry{{-1, true, false}, {0, true, true}, {0, false, false}})}, false},
    84  	{"negative index slice, equals a[1] to a[len-1]", `{[1:-1]}`, []Node{newList(),
    85  		newArray([3]ParamsEntry{{1, true, false}, {-1, true, false}, {0, false, false}})}, false},
    86  }
    87  
    88  func collectNode(nodes []Node, cur Node) []Node {
    89  	nodes = append(nodes, cur)
    90  	switch cur.Type() {
    91  	case NodeList:
    92  		for _, node := range cur.(*ListNode).Nodes {
    93  			nodes = collectNode(nodes, node)
    94  		}
    95  	case NodeFilter:
    96  		nodes = collectNode(nodes, cur.(*FilterNode).Left)
    97  		nodes = collectNode(nodes, cur.(*FilterNode).Right)
    98  	case NodeUnion:
    99  		for _, node := range cur.(*UnionNode).Nodes {
   100  			nodes = collectNode(nodes, node)
   101  		}
   102  	}
   103  	return nodes
   104  }
   105  
   106  func TestParser(t *testing.T) {
   107  	for _, test := range parserTests {
   108  		parser, err := Parse(test.name, test.text)
   109  		if test.shouldError {
   110  			if err == nil {
   111  				t.Errorf("unexpected non-error when parsing %s", test.name)
   112  			}
   113  			continue
   114  		}
   115  		if err != nil {
   116  			t.Errorf("parse %s error %v", test.name, err)
   117  		}
   118  		result := collectNode([]Node{}, parser.Root)[1:]
   119  		if len(result) != len(test.nodes) {
   120  			t.Errorf("in %s, expect to get %d nodes, got %d nodes", test.name, len(test.nodes), len(result))
   121  			t.Error(result)
   122  		}
   123  		for i, expect := range test.nodes {
   124  			if result[i].String() != expect.String() {
   125  				t.Errorf("in %s, %dth node, expect %v, got %v", test.name, i, expect, result[i])
   126  			}
   127  		}
   128  	}
   129  }
   130  
   131  type failParserTest struct {
   132  	name string
   133  	text string
   134  	err  string
   135  }
   136  
   137  func TestFailParser(t *testing.T) {
   138  	failParserTests := []failParserTest{
   139  		{"unclosed action", "{.hello", "unclosed action"},
   140  		{"unrecognized character", "{*}", "unrecognized character in action: U+002A '*'"},
   141  		{"invalid number", "{+12.3.0}", "cannot parse number +12.3.0"},
   142  		{"unterminated array", "{[1}", "unterminated array"},
   143  		{"unterminated filter", "{[?(.price]}", "unterminated filter"},
   144  		{"invalid multiple recursive descent", "{........}", "invalid multiple recursive descent"},
   145  	}
   146  	for _, test := range failParserTests {
   147  		_, err := Parse(test.name, test.text)
   148  		var out string
   149  		if err == nil {
   150  			out = "nil"
   151  		} else {
   152  			out = err.Error()
   153  		}
   154  		if out != test.err {
   155  			t.Errorf("in %s, expect to get error %v, got %v", test.name, test.err, out)
   156  		}
   157  	}
   158  }
   159  

View as plain text