Import Upstream version 0.1.3
Clint Adams
5 years ago
0 | Apache License | |
1 | Version 2.0, January 2004 | |
2 | http://www.apache.org/licenses/ | |
3 | ||
4 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | |
5 | ||
6 | 1. Definitions. | |
7 | ||
8 | "License" shall mean the terms and conditions for use, reproduction, | |
9 | and distribution as defined by Sections 1 through 9 of this document. | |
10 | ||
11 | "Licensor" shall mean the copyright owner or entity authorized by | |
12 | the copyright owner that is granting the License. | |
13 | ||
14 | "Legal Entity" shall mean the union of the acting entity and all | |
15 | other entities that control, are controlled by, or are under common | |
16 | control with that entity. For the purposes of this definition, | |
17 | "control" means (i) the power, direct or indirect, to cause the | |
18 | direction or management of such entity, whether by contract or | |
19 | otherwise, or (ii) ownership of fifty percent (50%) or more of the | |
20 | outstanding shares, or (iii) beneficial ownership of such entity. | |
21 | ||
22 | "You" (or "Your") shall mean an individual or Legal Entity | |
23 | exercising permissions granted by this License. | |
24 | ||
25 | "Source" form shall mean the preferred form for making modifications, | |
26 | including but not limited to software source code, documentation | |
27 | source, and configuration files. | |
28 | ||
29 | "Object" form shall mean any form resulting from mechanical | |
30 | transformation or translation of a Source form, including but | |
31 | not limited to compiled object code, generated documentation, | |
32 | and conversions to other media types. | |
33 | ||
34 | "Work" shall mean the work of authorship, whether in Source or | |
35 | Object form, made available under the License, as indicated by a | |
36 | copyright notice that is included in or attached to the work | |
37 | (an example is provided in the Appendix below). | |
38 | ||
39 | "Derivative Works" shall mean any work, whether in Source or Object | |
40 | form, that is based on (or derived from) the Work and for which the | |
41 | editorial revisions, annotations, elaborations, or other modifications | |
42 | represent, as a whole, an original work of authorship. For the purposes | |
43 | of this License, Derivative Works shall not include works that remain | |
44 | separable from, or merely link (or bind by name) to the interfaces of, | |
45 | the Work and Derivative Works thereof. | |
46 | ||
47 | "Contribution" shall mean any work of authorship, including | |
48 | the original version of the Work and any modifications or additions | |
49 | to that Work or Derivative Works thereof, that is intentionally | |
50 | submitted to Licensor for inclusion in the Work by the copyright owner | |
51 | or by an individual or Legal Entity authorized to submit on behalf of | |
52 | the copyright owner. For the purposes of this definition, "submitted" | |
53 | means any form of electronic, verbal, or written communication sent | |
54 | to the Licensor or its representatives, including but not limited to | |
55 | communication on electronic mailing lists, source code control systems, | |
56 | and issue tracking systems that are managed by, or on behalf of, the | |
57 | Licensor for the purpose of discussing and improving the Work, but | |
58 | excluding communication that is conspicuously marked or otherwise | |
59 | designated in writing by the copyright owner as "Not a Contribution." | |
60 | ||
61 | "Contributor" shall mean Licensor and any individual or Legal Entity | |
62 | on behalf of whom a Contribution has been received by Licensor and | |
63 | subsequently incorporated within the Work. | |
64 | ||
65 | 2. Grant of Copyright License. Subject to the terms and conditions of | |
66 | this License, each Contributor hereby grants to You a perpetual, | |
67 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |
68 | copyright license to reproduce, prepare Derivative Works of, | |
69 | publicly display, publicly perform, sublicense, and distribute the | |
70 | Work and such Derivative Works in Source or Object form. | |
71 | ||
72 | 3. Grant of Patent License. Subject to the terms and conditions of | |
73 | this License, each Contributor hereby grants to You a perpetual, | |
74 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |
75 | (except as stated in this section) patent license to make, have made, | |
76 | use, offer to sell, sell, import, and otherwise transfer the Work, | |
77 | where such license applies only to those patent claims licensable | |
78 | by such Contributor that are necessarily infringed by their | |
79 | Contribution(s) alone or by combination of their Contribution(s) | |
80 | with the Work to which such Contribution(s) was submitted. If You | |
81 | institute patent litigation against any entity (including a | |
82 | cross-claim or counterclaim in a lawsuit) alleging that the Work | |
83 | or a Contribution incorporated within the Work constitutes direct | |
84 | or contributory patent infringement, then any patent licenses | |
85 | granted to You under this License for that Work shall terminate | |
86 | as of the date such litigation is filed. | |
87 | ||
88 | 4. Redistribution. You may reproduce and distribute copies of the | |
89 | Work or Derivative Works thereof in any medium, with or without | |
90 | modifications, and in Source or Object form, provided that You | |
91 | meet the following conditions: | |
92 | ||
93 | (a) You must give any other recipients of the Work or | |
94 | Derivative Works a copy of this License; and | |
95 | ||
96 | (b) You must cause any modified files to carry prominent notices | |
97 | stating that You changed the files; and | |
98 | ||
99 | (c) You must retain, in the Source form of any Derivative Works | |
100 | that You distribute, all copyright, patent, trademark, and | |
101 | attribution notices from the Source form of the Work, | |
102 | excluding those notices that do not pertain to any part of | |
103 | the Derivative Works; and | |
104 | ||
105 | (d) If the Work includes a "NOTICE" text file as part of its | |
106 | distribution, then any Derivative Works that You distribute must | |
107 | include a readable copy of the attribution notices contained | |
108 | within such NOTICE file, excluding those notices that do not | |
109 | pertain to any part of the Derivative Works, in at least one | |
110 | of the following places: within a NOTICE text file distributed | |
111 | as part of the Derivative Works; within the Source form or | |
112 | documentation, if provided along with the Derivative Works; or, | |
113 | within a display generated by the Derivative Works, if and | |
114 | wherever such third-party notices normally appear. The contents | |
115 | of the NOTICE file are for informational purposes only and | |
116 | do not modify the License. You may add Your own attribution | |
117 | notices within Derivative Works that You distribute, alongside | |
118 | or as an addendum to the NOTICE text from the Work, provided | |
119 | that such additional attribution notices cannot be construed | |
120 | as modifying the License. | |
121 | ||
122 | You may add Your own copyright statement to Your modifications and | |
123 | may provide additional or different license terms and conditions | |
124 | for use, reproduction, or distribution of Your modifications, or | |
125 | for any such Derivative Works as a whole, provided Your use, | |
126 | reproduction, and distribution of the Work otherwise complies with | |
127 | the conditions stated in this License. | |
128 | ||
129 | 5. Submission of Contributions. Unless You explicitly state otherwise, | |
130 | any Contribution intentionally submitted for inclusion in the Work | |
131 | by You to the Licensor shall be under the terms and conditions of | |
132 | this License, without any additional terms or conditions. | |
133 | Notwithstanding the above, nothing herein shall supersede or modify | |
134 | the terms of any separate license agreement you may have executed | |
135 | with Licensor regarding such Contributions. | |
136 | ||
137 | 6. Trademarks. This License does not grant permission to use the trade | |
138 | names, trademarks, service marks, or product names of the Licensor, | |
139 | except as required for reasonable and customary use in describing the | |
140 | origin of the Work and reproducing the content of the NOTICE file. | |
141 | ||
142 | 7. Disclaimer of Warranty. Unless required by applicable law or | |
143 | agreed to in writing, Licensor provides the Work (and each | |
144 | Contributor provides its Contributions) on an "AS IS" BASIS, | |
145 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |
146 | implied, including, without limitation, any warranties or conditions | |
147 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | |
148 | PARTICULAR PURPOSE. You are solely responsible for determining the | |
149 | appropriateness of using or redistributing the Work and assume any | |
150 | risks associated with Your exercise of permissions under this License. | |
151 | ||
152 | 8. Limitation of Liability. In no event and under no legal theory, | |
153 | whether in tort (including negligence), contract, or otherwise, | |
154 | unless required by applicable law (such as deliberate and grossly | |
155 | negligent acts) or agreed to in writing, shall any Contributor be | |
156 | liable to You for damages, including any direct, indirect, special, | |
157 | incidental, or consequential damages of any character arising as a | |
158 | result of this License or out of the use or inability to use the | |
159 | Work (including but not limited to damages for loss of goodwill, | |
160 | work stoppage, computer failure or malfunction, or any and all | |
161 | other commercial damages or losses), even if such Contributor | |
162 | has been advised of the possibility of such damages. | |
163 | ||
164 | 9. Accepting Warranty or Additional Liability. While redistributing | |
165 | the Work or Derivative Works thereof, You may choose to offer, | |
166 | and charge a fee for, acceptance of support, warranty, indemnity, | |
167 | or other liability obligations and/or rights consistent with this | |
168 | License. However, in accepting such obligations, You may act only | |
169 | on Your own behalf and on Your sole responsibility, not on behalf | |
170 | of any other Contributor, and only if You agree to indemnify, | |
171 | defend, and hold each Contributor harmless for any liability | |
172 | incurred by, or claims asserted against, such Contributor by reason | |
173 | of your accepting any such warranty or additional liability. | |
174 | ||
175 | END OF TERMS AND CONDITIONS | |
176 | ||
177 | APPENDIX: How to apply the Apache License to your work. | |
178 | ||
179 | To apply the Apache License to your work, attach the following | |
180 | boilerplate notice, with the fields enclosed by brackets "[]" | |
181 | replaced with your own identifying information. (Don't include | |
182 | the brackets!) The text should be enclosed in the appropriate | |
183 | comment syntax for the file format. We also recommend that a | |
184 | file or class name and description of purpose be included on the | |
185 | same "printed page" as the copyright notice for easier | |
186 | identification within third-party archives. | |
187 | ||
188 | Copyright [yyyy] [name of copyright owner] | |
189 | ||
190 | Licensed under the Apache License, Version 2.0 (the "License"); | |
191 | you may not use this file except in compliance with the License. | |
192 | You may obtain a copy of the License at | |
193 | ||
194 | http://www.apache.org/licenses/LICENSE-2.0 | |
195 | ||
196 | Unless required by applicable law or agreed to in writing, software | |
197 | distributed under the License is distributed on an "AS IS" BASIS, | |
198 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
199 | See the License for the specific language governing permissions and | |
200 | limitations under the License. |
0 | JP_VERSION="" | |
1 | ||
2 | help: | |
3 | @echo "Please use \`make <target>' where <target> is one of" | |
4 | @echo " test to run all the tests." | |
5 | ||
6 | test: | |
7 | # CLI specific test cases. | |
8 | test/vendor/bats/libexec/bats test/cases | |
9 | # JMESPath compliance tests, using the jp-compliance | |
10 | # runner from github.com/jmespath/jmespath.test | |
11 | test/jp-compliance -d test/compliance/ -e ./jp | |
12 | ||
13 | # This will create/tag a new release locally, but not push anything. | |
14 | # The workflow for a new release is: | |
15 | # | |
16 | # 1. $ make new-release JP_VERSION=1.0.0 | |
17 | # < you'll get prompted for a few things > | |
18 | # | |
19 | ||
20 | # 2. $ git push origin master --tags | |
21 | # | |
22 | # | |
23 | # 3. Go to github and create a release | |
24 | # Right now, the last step isn't automated. You still | |
25 | # have to manually upload the release assets from build/. | |
26 | new-release: | |
27 | scripts/bump-version $(JP_VERSION) | |
28 | git add jp.go && git commit -m "Bumping version to $(JP_VERSION)" | |
29 | git tag -s -m "Tagging $(JP_VERSION) release" $(JP_VERSION) | |
30 | scripts/build-all-platforms | |
31 | scripts/sign-all | |
32 | ||
33 | .PHONY: help test |
0 | jp | |
1 | == | |
2 | ||
3 | The ``jp`` command is a command line interface to | |
4 | [JMESPath](http://jmespath.org), an expression | |
5 | language for manipulating JSON: | |
6 | ||
7 | ``` | |
8 | $ echo '{"foo": {"bar": ["a", "b", "c"]}}' | jp foo.bar[1] | |
9 | "b" | |
10 | ``` | |
11 | ||
12 | ||
13 | # Installing | |
14 | ||
15 | If you're a Mac user, you can install via homebrew from the JMESPath | |
16 | Homebrew tap: | |
17 | ||
18 | ``` | |
19 | brew tap jmespath/jmespath | |
20 | brew install jp | |
21 | ``` | |
22 | ||
23 | You can download prebuilt binaries if you prefer. | |
24 | Check the [Release page](https://github.com/jmespath/jp/releases) | |
25 | to download the latest ``jp`` executable. There are binaries | |
26 | available for Windows, Linux, Mac, FreeBSD. | |
27 | ||
28 | For example, to install version 0.1.2 on a 64 bit Linux environment use: | |
29 | ||
30 | ``` | |
31 | sudo wget https://github.com/jmespath/jp/releases/download/0.1.2/jp-linux-amd64 -O /usr/local/bin/jp \ | |
32 | && sudo chmod +x /usr/local/bin/jp | |
33 | ``` | |
34 | ||
35 | ## Building from Source | |
36 | ||
37 | If you have a Go environment installed you can also run: | |
38 | ``go get -u github.com/jmespath/jp`` to get the latest version | |
39 | of jmespath. If you have the repo checked out locally you can also | |
40 | just ``go build`` the project: | |
41 | ||
42 | ``` | |
43 | git clone git://github.com/jmespath/jp | |
44 | cd jp | |
45 | go build | |
46 | ./jp --help | |
47 | ``` | |
48 | ||
49 | And finally, if you have a go environment setup, but don't | |
50 | have a workspace/GOPATH configured, you can just run | |
51 | ``scripts/build-self-contained`` and it will build the | |
52 | ``jp`` executable for you: | |
53 | ||
54 | ``` | |
55 | git clone git://github.com/jmespath/jp | |
56 | cd jp | |
57 | scripts/build-self-contained | |
58 | ./jp --help | |
59 | ``` | |
60 | ||
61 | ## Cross platform binaries | |
62 | ||
63 | If you have a go 1.5 environment setup, you can build cross platform binaries | |
64 | by running ``scripts/build-all-platforms``. | |
65 | This will put executables in the ``build/`` directory and each | |
66 | executable will be named ``jp-<platform>``, e.g | |
67 | ``jp-darwin-amd64``, ``jp-linux-386``, etc. | |
68 | ||
69 | ||
70 | # Usage | |
71 | ||
72 | The most basic usage of ``jp`` is to accept input JSON data through stdin, | |
73 | apply the JMESPath expression you've provided as an argument to ``jp``, and | |
74 | print the resulting JSON data to stdout. | |
75 | ||
76 | ``` | |
77 | $ echo '{"key": "value"}' | jp key | |
78 | "value" | |
79 | ||
80 | $ echo '{"foo": {"bar": ["a", "b", "c"]}}' | jp foo.bar[1] | |
81 | "b" | |
82 | ``` | |
83 | ||
84 | Note the argument after ``jp``. This is a JMESPath expression. | |
85 | If you have no idea what that is, there's a | |
86 | [JMESPath Tutorial](http://jmespath.org/tutorial.html) that | |
87 | will take you through the JMESPath language. | |
88 | ||
89 | ## Input From a File | |
90 | ||
91 | In addition to this basic usage, there's also other ways to use | |
92 | ``jp``. First, instead of reading from stdin, you can provide | |
93 | a JSON file as input using the ``-f/--filename`` option: | |
94 | ||
95 | ||
96 | ``` | |
97 | $ echo '{"foo": {"bar": "baz"}}' > /tmp/input.json | |
98 | $ jp -f /tmp/input.json foo.bar | |
99 | "baz" | |
100 | ``` | |
101 | ||
102 | ## Unquoted Output | |
103 | ||
104 | [[Notice]] the output of the above command is ``"baz"``, that is, | |
105 | a double quote ``"``, followed by baz, followed by another | |
106 | a final double quote. This can be problematic if you're | |
107 | trying to use this with other commands that just want | |
108 | the string and *not* the quoted string. For example: | |
109 | ||
110 | ||
111 | ``` | |
112 | $ curl -s https://api.github.com/repos/golang/go/events | jp [0].actor.url | |
113 | "https://api.github.com/users/robpike" | |
114 | ``` | |
115 | ||
116 | Now let's suppose we want to then curl the above URL. Our first | |
117 | attempt might look something like this: | |
118 | ||
119 | ``` | |
120 | $ curl $(curl -s https://api.github.com/repos/golang/go/events | ./jp [0].actor.url) | |
121 | ``` | |
122 | ||
123 | And it would fail with: | |
124 | ||
125 | ``` | |
126 | curl: (1) Protocol "https not supported or disabled in libcurl | |
127 | ``` | |
128 | ||
129 | To fix this, we can use the ``-u/--unquoted`` option to specify that | |
130 | any result that is a string will be printed without quotes. Note | |
131 | that the result is not surrounded by double quotes: | |
132 | ||
133 | ``` | |
134 | $ curl -s https://api.github.com/repos/golang/go/events | jp --unquoted [0].actor.url | |
135 | https://api.github.com/users/robpike | |
136 | ``` | |
137 | ||
138 | If this is a common enough occurance for you, you can set the ``JP_UNQUOTED`` environment | |
139 | variable to make this the default behavior: | |
140 | ||
141 | ``` | |
142 | $ export JP_UNQUOTED=true | |
143 | $ curl -s https://api.github.com/repos/golang/go/events | jp --unquoted [0].actor.url | |
144 | https://api.github.com/users/robpike | |
145 | ``` | |
146 | ||
147 | ||
148 | Also keep in mind that this behavior | |
149 | only applies if the result of evaluating the JMESPath expression is a string: | |
150 | ||
151 | ``` | |
152 | $ echo '{"foo": ["bar", "baz"]}' | jp -u foo[0] | |
153 | bar | |
154 | # But -u does nothing here because the result is an array, not a string: | |
155 | $ echo '{"foo": ["bar", "baz"]}' | jp -u foo | |
156 | [ | |
157 | "bar", | |
158 | "baz" | |
159 | ] | |
160 | ``` | |
161 | ||
162 | You can also use the ``-u/--unquoted`` option along with the | |
163 | [join](http://jmespath.org/specification.html#join) function to create a list | |
164 | of strings that can be piped into other POSIX text tools. For example: | |
165 | ||
166 | ``` | |
167 | $ echo '{"foo": {"bar": ["a", "b", "c"]}}' | jp foo.bar | |
168 | [ | |
169 | "a", | |
170 | "b", | |
171 | "c" | |
172 | ] | |
173 | ``` | |
174 | ||
175 | Suppose we want to iterate over the 3 values in the list and | |
176 | run some bash code for each value. We can do this by running: | |
177 | ||
178 | ``` | |
179 | $ for name in $(echo '{"foo": {"bar": ["a", "b", "c"]}}' | \ | |
180 | jp -u 'join(`"\n"`, foo.bar)'); | |
181 | do | |
182 | echo "Processing: $name"; | |
183 | done | |
184 | Processing: a | |
185 | Processing: b | |
186 | Processing: c | |
187 | ``` | |
188 | ||
189 | ||
190 | ## Examples | |
191 | ||
192 | If you're new to the JMESPath language, or just want to see what the language is | |
193 | capable of, you can check out the [JMESPath tutorial](http://jmespath.org/tutorial.html) | |
194 | as well as the [JMESPath examples](http://jmespath.org/examples.html), which contains | |
195 | a curated set of JMESPath examples. But for now, here's a real world example. | |
196 | Let's say you wanted to see what the latest activity was with regard to the issue | |
197 | tracker for one of your github issues. Here's a simple way to do this: | |
198 | ||
199 | ``` | |
200 | $ curl -s https://api.github.com/repos/golang/go/events | jp \ | |
201 | "[?type=='IssuesEvent'].payload.\ | |
202 | {Title: issue.title, URL: issue.url, User: issue.user.login, Event: action}" | |
203 | ||
204 | [ | |
205 | { | |
206 | "Event": "opened", | |
207 | "Title": "release: cherry pick changes for 1.5 to release branch", | |
208 | "URL": "https://api.github.com/repos/golang/go/issues/12093", | |
209 | "User": "adg" | |
210 | }, | |
211 | { | |
212 | "Event": "closed", | |
213 | "Title": "fmt: x format verb for []byte fails in a recursive call to Fscanf from a scanln call in go1.5rc1", | |
214 | "URL": "https://api.github.com/repos/golang/go/issues/12090", | |
215 | "User": "hubslave" | |
216 | }, | |
217 | { | |
218 | "Event": "closed", | |
219 | "Title": "doc: release notes recommend wrong version of NaCl", | |
220 | "URL": "https://api.github.com/repos/golang/go/issues/12062", | |
221 | "User": "davecheney" | |
222 | }, | |
223 | { | |
224 | "Event": "opened", | |
225 | "Title": "cmd/godoc: show internal packages when explicitly requested", | |
226 | "URL": "https://api.github.com/repos/golang/go/issues/12092", | |
227 | "User": "jacobsa" | |
228 | } | |
229 | ] | |
230 | ``` | |
231 | ||
232 | Try it for your own repo, instead of ``/golang/go``, replace it with your own | |
233 | ``/owner/repo`` value. In words, this expression says: | |
234 | ||
235 | * For each element in the top level list, select only the elements where the | |
236 | ``type`` key is equal to the string ``IssueEvent`` | |
237 | * For each of those filtered elements select the ``payload`` hash. | |
238 | * Each each ``payload`` hash, we're going to create our own hash that has | |
239 | 4 keys: ``Title``, ``URL``, ``User``, ``Event``. The value for each of key | |
240 | is the result of evaluating these expressions in their respective order: | |
241 | ``issue.title``, ``issue.url``, ``issue.user.login``, ``action``. | |
242 | ||
243 | Ensure that if your expression has spaces you surround the expression | |
244 | in quotes, as shown in the example above. | |
245 | ||
246 | ## Testing | |
247 | ||
248 | The parsing and evaluation of JMESPath expression is done in the | |
249 | go-jmespath library, which is a dependency of this project. ``go-jmespath`` | |
250 | has extensive testing to ensure it is parsing and evaluating JMESPath | |
251 | expressions correctly. | |
252 | ||
253 | To ensure that there are no regressions between `go-imespath` and `jp`, | |
254 | the entire suite of [JMESPath compliance tests](https://github.com/jmespath/jmespath.test) | |
255 | are run against the `jp` executable. | |
256 | ||
257 | This repo also include CLI specific test that verify the command line | |
258 | options and output work as intended. | |
259 | ||
260 | You can run all of these tests for `jp` by running `make test`: | |
261 | ||
262 | ``` | |
263 | $ make test | |
264 | # CLI specific test cases. | |
265 | test/vendor/bats/libexec/bats test/cases | |
266 | ✓ Has valid help output | |
267 | ✓ Can display version | |
268 | ✓ Can search basic expression | |
269 | ✓ Can search subexpr expression | |
270 | ✓ Can read input from file | |
271 | ✓ Can print result unquoted | |
272 | ✓ Bad JMESPath expression has non zero rc | |
273 | - Large numbers are not printed with scientific notation (skipped) | |
274 | ✓ Can accept expression from file | |
275 | ✓ Can pretty print expr AST | |
276 | ✓ Can sort int array | |
277 | ||
278 | X tests, 0 failures, 1 skipped | |
279 | # JMESPath compliance tests, using the jp-compliance | |
280 | # runner from github.com/jmespath/jmespath.test | |
281 | test/jp-compliance -d test/compliance/ -e ./jp | |
282 | ............................................................ | |
283 | ............................................................ | |
284 | ............................................................ | |
285 | ............................................................ | |
286 | ............................................................ | |
287 | ............................................................ | |
288 | ............................................................ | |
289 | ............................................................ | |
290 | OK | |
291 | ``` |
0 | package main | |
1 | ||
2 | import ( | |
3 | "encoding/json" | |
4 | "fmt" | |
5 | "io/ioutil" | |
6 | "os" | |
7 | ||
8 | "github.com/jmespath/jp/Godeps/_workspace/src/github.com/codegangsta/cli" | |
9 | "github.com/jmespath/jp/Godeps/_workspace/src/github.com/jmespath/go-jmespath" | |
10 | ) | |
11 | ||
12 | const version = "0.1.3" | |
13 | ||
14 | func main() { | |
15 | app := cli.NewApp() | |
16 | app.Name = "jp" | |
17 | app.Version = version | |
18 | app.Usage = "jp [<options>] <expression>" | |
19 | app.Author = "" | |
20 | app.Email = "" | |
21 | app.Flags = []cli.Flag{ | |
22 | cli.StringFlag{ | |
23 | Name: "filename, f", | |
24 | Usage: "Read input JSON from a file instead of stdin.", | |
25 | }, | |
26 | cli.StringFlag{ | |
27 | Name: "expr-file, e", | |
28 | Usage: "Read JMESPath expression from the specified file.", | |
29 | }, | |
30 | cli.BoolFlag{ | |
31 | Name: "unquoted, u", | |
32 | Usage: "If the final result is a string, it will be printed without quotes.", | |
33 | EnvVar: "JP_UNQUOTED", | |
34 | }, | |
35 | cli.BoolFlag{ | |
36 | Name: "ast", | |
37 | Usage: "Only print the AST of the parsed expression. Do not rely on this output, only useful for debugging purposes.", | |
38 | }, | |
39 | } | |
40 | app.Action = runMainAndExit | |
41 | ||
42 | app.Run(os.Args) | |
43 | } | |
44 | ||
45 | func runMainAndExit(c *cli.Context) { | |
46 | os.Exit(runMain(c)) | |
47 | } | |
48 | ||
49 | func errMsg(msg string, a ...interface{}) int { | |
50 | fmt.Fprintf(os.Stderr, msg, a...) | |
51 | fmt.Fprintln(os.Stderr) | |
52 | return 1 | |
53 | } | |
54 | ||
55 | func runMain(c *cli.Context) int { | |
56 | var expression string | |
57 | if c.String("expr-file") != "" { | |
58 | byteExpr, err := ioutil.ReadFile(c.String("expr-file")) | |
59 | expression = string(byteExpr) | |
60 | if err != nil { | |
61 | return errMsg("Error opening expression file: %s", err) | |
62 | } | |
63 | } else { | |
64 | if len(c.Args()) == 0 { | |
65 | return errMsg("Must provide at least one argument.") | |
66 | } | |
67 | expression = c.Args()[0] | |
68 | } | |
69 | if c.Bool("ast") { | |
70 | parser := jmespath.NewParser() | |
71 | parsed, err := parser.Parse(expression) | |
72 | if err != nil { | |
73 | if syntaxError, ok := err.(jmespath.SyntaxError); ok { | |
74 | return errMsg("%s\n%s\n", | |
75 | syntaxError, | |
76 | syntaxError.HighlightLocation()) | |
77 | } | |
78 | return errMsg("%s", err) | |
79 | } | |
80 | fmt.Println("") | |
81 | fmt.Printf("%s\n", parsed) | |
82 | return 0 | |
83 | } | |
84 | var input interface{} | |
85 | var jsonParser *json.Decoder | |
86 | if c.String("filename") != "" { | |
87 | f, err := os.Open(c.String("filename")) | |
88 | if err != nil { | |
89 | return errMsg("Error opening input file: %s", err) | |
90 | } | |
91 | jsonParser = json.NewDecoder(f) | |
92 | ||
93 | } else { | |
94 | jsonParser = json.NewDecoder(os.Stdin) | |
95 | } | |
96 | if err := jsonParser.Decode(&input); err != nil { | |
97 | errMsg("Error parsing input json: %s\n", err) | |
98 | return 2 | |
99 | } | |
100 | result, err := jmespath.Search(expression, input) | |
101 | if err != nil { | |
102 | if syntaxError, ok := err.(jmespath.SyntaxError); ok { | |
103 | return errMsg("%s\n%s\n", | |
104 | syntaxError, | |
105 | syntaxError.HighlightLocation()) | |
106 | } | |
107 | return errMsg("Error evaluating JMESPath expression: %s", err) | |
108 | } | |
109 | converted, isString := result.(string) | |
110 | if c.Bool("unquoted") && isString { | |
111 | os.Stdout.WriteString(converted) | |
112 | } else { | |
113 | toJSON, err := json.MarshalIndent(result, "", " ") | |
114 | if err != nil { | |
115 | errMsg("Error marshalling result to JSON: %s\n", err) | |
116 | return 3 | |
117 | } | |
118 | os.Stdout.Write(toJSON) | |
119 | } | |
120 | os.Stdout.WriteString("\n") | |
121 | return 0 | |
122 | } |
0 | #!/bin/bash | |
1 | go get ./... | |
2 | rm -rf ./build/jp-* | |
3 | for goos in darwin linux windows freebsd; do | |
4 | export GOOS="$goos" | |
5 | for goarch in 386 amd64; do | |
6 | export GOARCH="$goarch" | |
7 | echo "Building for $GOOS/$GOARCH" | |
8 | go build -v -o build/jp-$GOOS-$GOARCH 2>/dev/null | |
9 | done | |
10 | done | |
11 | # Also build for ARM7/linux | |
12 | export GOOS=linux | |
13 | export GOARCH=arm | |
14 | export GOARM=7 | |
15 | echo "Building for $GOOS/$GOARCH/$GOARM" | |
16 | go build -v -o build/jp-$GOOS-$GOARCH-arm$GOARM 2> /dev/null |
0 | #!/bin/bash | |
1 | # This is a self contained shell script for building jp without having to set | |
2 | # up GOPATH. You just need go installed. | |
3 | tempdir="$(mktemp -d -t jpbuild)" | |
4 | tempgopath="$tempdir/go" | |
5 | jppath="${tempgopath}/src/github.com/jmespath" | |
6 | fakerepo="$jppath/jp" | |
7 | mkdir -p $jppath | |
8 | ln -s "$(pwd)" "$jppath/jp" | |
9 | export GOPATH="$tempgopath" | |
10 | cd "$fakerepo" | |
11 | go build |
0 | #!/usr/bin/env python | |
1 | import sys | |
2 | import re | |
3 | import os | |
4 | ||
5 | version_line_re = re.compile(r'^const version = "\d+\.\d+\.\d+"') | |
6 | ||
7 | ||
8 | if len(sys.argv) == 1 or sys.argv[1] == '': | |
9 | print "Must provide jp version to bump to. (make new-release JP_VERSION=1.0.0)" | |
10 | sys.exit(1) | |
11 | ||
12 | new_version = sys.argv[1] | |
13 | source_file = os.path.join( | |
14 | os.path.dirname( | |
15 | os.path.dirname(os.path.abspath(__file__))), | |
16 | 'jp.go') | |
17 | ||
18 | assert os.path.isfile(source_file) | |
19 | ||
20 | with open(source_file, 'r') as f: | |
21 | contents = f.readlines() | |
22 | for i, line in enumerate(contents): | |
23 | if version_line_re.search(line) is not None: | |
24 | contents[i] = 'const version = "%s"\n' % new_version | |
25 | break | |
26 | else: | |
27 | sys.stderr.write("Could not find version string in %s\n" % source_file) | |
28 | ||
29 | with open(source_file, 'w') as f: | |
30 | for line in contents: | |
31 | f.write(line) |
0 | #!/bin/bash | |
1 | # Helper script to build "jp" on all supported platforms. | |
2 | # This script uses docker so you don't have to have the cross | |
3 | # platform golang environment setup. Just make sure you have docker | |
4 | # installed. The built executables will be in build/ | |
5 | docker run --rm -v "$PWD:/go/src/jp" -w /go/src/jp golang:1.4.2-cross scripts/build-all-platforms |
0 | #!/bin/bash | |
1 | ||
2 | set -e | |
3 | ||
4 | cd build | |
5 | shasum -a 256 ./jp-* > jp-checksums.sha256 | |
6 | gpg --clearsign --output jp-checksums.sha256.asc jp-checksums.sha256 | |
7 | rm jp-checksums.sha256 |
0 | @test "Has valid help output" { | |
1 | run ./jp --help | |
2 | [ "$status" -eq 0 ] | |
3 | echo $output | grep "\-\-filename" | |
4 | } | |
5 | ||
6 | @test "Can display version" { | |
7 | run ./jp --version | |
8 | [ "$status" -eq 0 ] | |
9 | } | |
10 | ||
11 | @test "Can search basic expression" { | |
12 | output=$(echo '{"foo": "bar"}' | ./jp foo) | |
13 | [ "$output" == "\"bar\"" ] | |
14 | } | |
15 | ||
16 | @test "Can search subexpr expression" { | |
17 | output=$(echo '{"foo": {"bar": "baz"}}' | ./jp foo.bar) | |
18 | [ "$output" == "\"baz\"" ] | |
19 | } | |
20 | ||
21 | @test "Can read input from file" { | |
22 | echo '{"foo": "bar"}' > "$BATS_TMPDIR/input.json" | |
23 | run ./jp -f "$BATS_TMPDIR/input.json" foo | |
24 | [ "$output" == "\"bar\"" ] | |
25 | } | |
26 | ||
27 | @test "Can print result unquoted" { | |
28 | output=$(echo '{"foo": "bar"}' | ./jp -u foo) | |
29 | [ "$output" == "bar" ] | |
30 | } | |
31 | ||
32 | @test "Bad JMESPath expression has non zero rc" { | |
33 | echo '{"foo": "bar"}' > "$BATS_TMPDIR/input.json" | |
34 | run ./jp -f "$BATS_TMPDIR/input.json" "bax[expre]ssion" | |
35 | [ "$status" -eq 1 ] | |
36 | } | |
37 | ||
38 | @test "Large numbers are not printed with scientific notation" { | |
39 | skip | |
40 | echo '{"foo": 47268765}' > "$BATS_TMPDIR/input.json" | |
41 | run ./jp -f "$BATS_TMPDIR/input.json" "foo" | |
42 | [ "$status" -eq 0 ] | |
43 | [ "$output" == "47268765" ] | |
44 | } | |
45 | ||
46 | @test "Can accept expression from file" { | |
47 | echo 'foo.bar' > "$BATS_TMPDIR/expr" | |
48 | echo '{"foo": {"bar": "baz"}}' > "$BATS_TMPDIR/input.json" | |
49 | run ./jp -u -f "$BATS_TMPDIR/input.json" -e "$BATS_TMPDIR/expr" | |
50 | [ "$output" == "baz" ] | |
51 | } | |
52 | ||
53 | @test "Can pretty print expr AST" { | |
54 | run ./jp --ast "foo" | |
55 | expected=' | |
56 | ASTField { | |
57 | value: "foo" | |
58 | }' | |
59 | echo "$output" | |
60 | echo "$expected" | |
61 | [ "$output" == "$expected" ] | |
62 | } | |
63 | ||
64 | @test "Can sort int array" { | |
65 | echo '[2,1,3,5,4]' > "$BATS_TMPDIR/input.json" | |
66 | echo "sort(@) | map(&to_string(@), @) | join('', @)" > "$BATS_TMPDIR/expr" | |
67 | run ./jp -u -f "$BATS_TMPDIR/input.json" -e "$BATS_TMPDIR/expr" | |
68 | [ "$status" -eq 0 ] | |
69 | [ "$output" == "12345" ] | |
70 | } |
0 | [{ | |
1 | "given": | |
2 | {"foo": {"bar": {"baz": "correct"}}}, | |
3 | "cases": [ | |
4 | { | |
5 | "expression": "foo", | |
6 | "result": {"bar": {"baz": "correct"}} | |
7 | }, | |
8 | { | |
9 | "expression": "foo.bar", | |
10 | "result": {"baz": "correct"} | |
11 | }, | |
12 | { | |
13 | "expression": "foo.bar.baz", | |
14 | "result": "correct" | |
15 | }, | |
16 | { | |
17 | "expression": "foo\n.\nbar\n.baz", | |
18 | "result": "correct" | |
19 | }, | |
20 | { | |
21 | "expression": "foo.bar.baz.bad", | |
22 | "result": null | |
23 | }, | |
24 | { | |
25 | "expression": "foo.bar.bad", | |
26 | "result": null | |
27 | }, | |
28 | { | |
29 | "expression": "foo.bad", | |
30 | "result": null | |
31 | }, | |
32 | { | |
33 | "expression": "bad", | |
34 | "result": null | |
35 | }, | |
36 | { | |
37 | "expression": "bad.morebad.morebad", | |
38 | "result": null | |
39 | } | |
40 | ] | |
41 | }, | |
42 | { | |
43 | "given": | |
44 | {"foo": {"bar": ["one", "two", "three"]}}, | |
45 | "cases": [ | |
46 | { | |
47 | "expression": "foo", | |
48 | "result": {"bar": ["one", "two", "three"]} | |
49 | }, | |
50 | { | |
51 | "expression": "foo.bar", | |
52 | "result": ["one", "two", "three"] | |
53 | } | |
54 | ] | |
55 | }, | |
56 | { | |
57 | "given": ["one", "two", "three"], | |
58 | "cases": [ | |
59 | { | |
60 | "expression": "one", | |
61 | "result": null | |
62 | }, | |
63 | { | |
64 | "expression": "two", | |
65 | "result": null | |
66 | }, | |
67 | { | |
68 | "expression": "three", | |
69 | "result": null | |
70 | }, | |
71 | { | |
72 | "expression": "one.two", | |
73 | "result": null | |
74 | } | |
75 | ] | |
76 | }, | |
77 | { | |
78 | "given": | |
79 | {"foo": {"1": ["one", "two", "three"], "-1": "bar"}}, | |
80 | "cases": [ | |
81 | { | |
82 | "expression": "foo.\"1\"", | |
83 | "result": ["one", "two", "three"] | |
84 | }, | |
85 | { | |
86 | "expression": "foo.\"1\"[0]", | |
87 | "result": "one" | |
88 | }, | |
89 | { | |
90 | "expression": "foo.\"-1\"", | |
91 | "result": "bar" | |
92 | } | |
93 | ] | |
94 | } | |
95 | ] |
0 | [ | |
1 | { | |
2 | "given": { | |
3 | "outer": { | |
4 | "foo": "foo", | |
5 | "bar": "bar", | |
6 | "baz": "baz" | |
7 | } | |
8 | }, | |
9 | "cases": [ | |
10 | { | |
11 | "expression": "outer.foo || outer.bar", | |
12 | "result": "foo" | |
13 | }, | |
14 | { | |
15 | "expression": "outer.foo||outer.bar", | |
16 | "result": "foo" | |
17 | }, | |
18 | { | |
19 | "expression": "outer.bar || outer.baz", | |
20 | "result": "bar" | |
21 | }, | |
22 | { | |
23 | "expression": "outer.bar||outer.baz", | |
24 | "result": "bar" | |
25 | }, | |
26 | { | |
27 | "expression": "outer.bad || outer.foo", | |
28 | "result": "foo" | |
29 | }, | |
30 | { | |
31 | "expression": "outer.bad||outer.foo", | |
32 | "result": "foo" | |
33 | }, | |
34 | { | |
35 | "expression": "outer.foo || outer.bad", | |
36 | "result": "foo" | |
37 | }, | |
38 | { | |
39 | "expression": "outer.foo||outer.bad", | |
40 | "result": "foo" | |
41 | }, | |
42 | { | |
43 | "expression": "outer.bad || outer.alsobad", | |
44 | "result": null | |
45 | }, | |
46 | { | |
47 | "expression": "outer.bad||outer.alsobad", | |
48 | "result": null | |
49 | } | |
50 | ] | |
51 | }, | |
52 | { | |
53 | "given": { | |
54 | "outer": { | |
55 | "foo": "foo", | |
56 | "bool": false, | |
57 | "empty_list": [], | |
58 | "empty_string": "" | |
59 | } | |
60 | }, | |
61 | "cases": [ | |
62 | { | |
63 | "expression": "outer.empty_string || outer.foo", | |
64 | "result": "foo" | |
65 | }, | |
66 | { | |
67 | "expression": "outer.nokey || outer.bool || outer.empty_list || outer.empty_string || outer.foo", | |
68 | "result": "foo" | |
69 | } | |
70 | ] | |
71 | }, | |
72 | { | |
73 | "given": { | |
74 | "True": true, | |
75 | "False": false, | |
76 | "Number": 5, | |
77 | "EmptyList": [], | |
78 | "Zero": 0 | |
79 | }, | |
80 | "cases": [ | |
81 | { | |
82 | "expression": "True && False", | |
83 | "result": false | |
84 | }, | |
85 | { | |
86 | "expression": "False && True", | |
87 | "result": false | |
88 | }, | |
89 | { | |
90 | "expression": "True && True", | |
91 | "result": true | |
92 | }, | |
93 | { | |
94 | "expression": "False && False", | |
95 | "result": false | |
96 | }, | |
97 | { | |
98 | "expression": "True && Number", | |
99 | "result": 5 | |
100 | }, | |
101 | { | |
102 | "expression": "Number && True", | |
103 | "result": true | |
104 | }, | |
105 | { | |
106 | "expression": "Number && False", | |
107 | "result": false | |
108 | }, | |
109 | { | |
110 | "expression": "Number && EmptyList", | |
111 | "result": [] | |
112 | }, | |
113 | { | |
114 | "expression": "Number && True", | |
115 | "result": true | |
116 | }, | |
117 | { | |
118 | "expression": "EmptyList && True", | |
119 | "result": [] | |
120 | }, | |
121 | { | |
122 | "expression": "EmptyList && False", | |
123 | "result": [] | |
124 | }, | |
125 | { | |
126 | "expression": "True || False", | |
127 | "result": true | |
128 | }, | |
129 | { | |
130 | "expression": "True || True", | |
131 | "result": true | |
132 | }, | |
133 | { | |
134 | "expression": "False || True", | |
135 | "result": true | |
136 | }, | |
137 | { | |
138 | "expression": "False || False", | |
139 | "result": false | |
140 | }, | |
141 | { | |
142 | "expression": "Number || EmptyList", | |
143 | "result": 5 | |
144 | }, | |
145 | { | |
146 | "expression": "Number || True", | |
147 | "result": 5 | |
148 | }, | |
149 | { | |
150 | "expression": "Number || True && False", | |
151 | "result": 5 | |
152 | }, | |
153 | { | |
154 | "expression": "(Number || True) && False", | |
155 | "result": false | |
156 | }, | |
157 | { | |
158 | "expression": "Number || (True && False)", | |
159 | "result": 5 | |
160 | }, | |
161 | { | |
162 | "expression": "!True", | |
163 | "result": false | |
164 | }, | |
165 | { | |
166 | "expression": "!False", | |
167 | "result": true | |
168 | }, | |
169 | { | |
170 | "expression": "!Number", | |
171 | "result": false | |
172 | }, | |
173 | { | |
174 | "expression": "!EmptyList", | |
175 | "result": true | |
176 | }, | |
177 | { | |
178 | "expression": "True && !False", | |
179 | "result": true | |
180 | }, | |
181 | { | |
182 | "expression": "True && !EmptyList", | |
183 | "result": true | |
184 | }, | |
185 | { | |
186 | "expression": "!False && !EmptyList", | |
187 | "result": true | |
188 | }, | |
189 | { | |
190 | "expression": "!(True && False)", | |
191 | "result": true | |
192 | }, | |
193 | { | |
194 | "expression": "!Zero", | |
195 | "result": false | |
196 | }, | |
197 | { | |
198 | "expression": "!!Zero", | |
199 | "result": true | |
200 | } | |
201 | ] | |
202 | }, | |
203 | { | |
204 | "given": { | |
205 | "one": 1, | |
206 | "two": 2, | |
207 | "three": 3 | |
208 | }, | |
209 | "cases": [ | |
210 | { | |
211 | "expression": "one < two", | |
212 | "result": true | |
213 | }, | |
214 | { | |
215 | "expression": "one <= two", | |
216 | "result": true | |
217 | }, | |
218 | { | |
219 | "expression": "one == one", | |
220 | "result": true | |
221 | }, | |
222 | { | |
223 | "expression": "one == two", | |
224 | "result": false | |
225 | }, | |
226 | { | |
227 | "expression": "one > two", | |
228 | "result": false | |
229 | }, | |
230 | { | |
231 | "expression": "one >= two", | |
232 | "result": false | |
233 | }, | |
234 | { | |
235 | "expression": "one != two", | |
236 | "result": true | |
237 | }, | |
238 | { | |
239 | "expression": "one < two && three > one", | |
240 | "result": true | |
241 | }, | |
242 | { | |
243 | "expression": "one < two || three > one", | |
244 | "result": true | |
245 | }, | |
246 | { | |
247 | "expression": "one < two || three < one", | |
248 | "result": true | |
249 | }, | |
250 | { | |
251 | "expression": "two < one || three < one", | |
252 | "result": false | |
253 | } | |
254 | ] | |
255 | } | |
256 | ] |
0 | [ | |
1 | { | |
2 | "given": { | |
3 | "foo": [{"name": "a"}, {"name": "b"}], | |
4 | "bar": {"baz": "qux"} | |
5 | }, | |
6 | "cases": [ | |
7 | { | |
8 | "expression": "@", | |
9 | "result": { | |
10 | "foo": [{"name": "a"}, {"name": "b"}], | |
11 | "bar": {"baz": "qux"} | |
12 | } | |
13 | }, | |
14 | { | |
15 | "expression": "@.bar", | |
16 | "result": {"baz": "qux"} | |
17 | }, | |
18 | { | |
19 | "expression": "@.foo[0]", | |
20 | "result": {"name": "a"} | |
21 | } | |
22 | ] | |
23 | } | |
24 | ] |
0 | [{ | |
1 | "given": { | |
2 | "foo.bar": "dot", | |
3 | "foo bar": "space", | |
4 | "foo\nbar": "newline", | |
5 | "foo\"bar": "doublequote", | |
6 | "c:\\\\windows\\path": "windows", | |
7 | "/unix/path": "unix", | |
8 | "\"\"\"": "threequotes", | |
9 | "bar": {"baz": "qux"} | |
10 | }, | |
11 | "cases": [ | |
12 | { | |
13 | "expression": "\"foo.bar\"", | |
14 | "result": "dot" | |
15 | }, | |
16 | { | |
17 | "expression": "\"foo bar\"", | |
18 | "result": "space" | |
19 | }, | |
20 | { | |
21 | "expression": "\"foo\\nbar\"", | |
22 | "result": "newline" | |
23 | }, | |
24 | { | |
25 | "expression": "\"foo\\\"bar\"", | |
26 | "result": "doublequote" | |
27 | }, | |
28 | { | |
29 | "expression": "\"c:\\\\\\\\windows\\\\path\"", | |
30 | "result": "windows" | |
31 | }, | |
32 | { | |
33 | "expression": "\"/unix/path\"", | |
34 | "result": "unix" | |
35 | }, | |
36 | { | |
37 | "expression": "\"\\\"\\\"\\\"\"", | |
38 | "result": "threequotes" | |
39 | }, | |
40 | { | |
41 | "expression": "\"bar\".\"baz\"", | |
42 | "result": "qux" | |
43 | } | |
44 | ] | |
45 | }] |
0 | [ | |
1 | { | |
2 | "given": {"foo": [{"name": "a"}, {"name": "b"}]}, | |
3 | "cases": [ | |
4 | { | |
5 | "comment": "Matching a literal", | |
6 | "expression": "foo[?name == 'a']", | |
7 | "result": [{"name": "a"}] | |
8 | } | |
9 | ] | |
10 | }, | |
11 | { | |
12 | "given": {"foo": [0, 1], "bar": [2, 3]}, | |
13 | "cases": [ | |
14 | { | |
15 | "comment": "Matching a literal", | |
16 | "expression": "*[?[0] == `0`]", | |
17 | "result": [[], []] | |
18 | } | |
19 | ] | |
20 | }, | |
21 | { | |
22 | "given": {"foo": [{"first": "foo", "last": "bar"}, | |
23 | {"first": "foo", "last": "foo"}, | |
24 | {"first": "foo", "last": "baz"}]}, | |
25 | "cases": [ | |
26 | { | |
27 | "comment": "Matching an expression", | |
28 | "expression": "foo[?first == last]", | |
29 | "result": [{"first": "foo", "last": "foo"}] | |
30 | }, | |
31 | { | |
32 | "comment": "Verify projection created from filter", | |
33 | "expression": "foo[?first == last].first", | |
34 | "result": ["foo"] | |
35 | } | |
36 | ] | |
37 | }, | |
38 | { | |
39 | "given": {"foo": [{"age": 20}, | |
40 | {"age": 25}, | |
41 | {"age": 30}]}, | |
42 | "cases": [ | |
43 | { | |
44 | "comment": "Greater than with a number", | |
45 | "expression": "foo[?age > `25`]", | |
46 | "result": [{"age": 30}] | |
47 | }, | |
48 | { | |
49 | "expression": "foo[?age >= `25`]", | |
50 | "result": [{"age": 25}, {"age": 30}] | |
51 | }, | |
52 | { | |
53 | "comment": "Greater than with a number", | |
54 | "expression": "foo[?age > `30`]", | |
55 | "result": [] | |
56 | }, | |
57 | { | |
58 | "comment": "Greater than with a number", | |
59 | "expression": "foo[?age < `25`]", | |
60 | "result": [{"age": 20}] | |
61 | }, | |
62 | { | |
63 | "comment": "Greater than with a number", | |
64 | "expression": "foo[?age <= `25`]", | |
65 | "result": [{"age": 20}, {"age": 25}] | |
66 | }, | |
67 | { | |
68 | "comment": "Greater than with a number", | |
69 | "expression": "foo[?age < `20`]", | |
70 | "result": [] | |
71 | }, | |
72 | { | |
73 | "expression": "foo[?age == `20`]", | |
74 | "result": [{"age": 20}] | |
75 | }, | |
76 | { | |
77 | "expression": "foo[?age != `20`]", | |
78 | "result": [{"age": 25}, {"age": 30}] | |
79 | } | |
80 | ] | |
81 | }, | |
82 | { | |
83 | "given": {"foo": [{"top": {"name": "a"}}, | |
84 | {"top": {"name": "b"}}]}, | |
85 | "cases": [ | |
86 | { | |
87 | "comment": "Filter with subexpression", | |
88 | "expression": "foo[?top.name == 'a']", | |
89 | "result": [{"top": {"name": "a"}}] | |
90 | } | |
91 | ] | |
92 | }, | |
93 | { | |
94 | "given": {"foo": [{"top": {"first": "foo", "last": "bar"}}, | |
95 | {"top": {"first": "foo", "last": "foo"}}, | |
96 | {"top": {"first": "foo", "last": "baz"}}]}, | |
97 | "cases": [ | |
98 | { | |
99 | "comment": "Matching an expression", | |
100 | "expression": "foo[?top.first == top.last]", | |
101 | "result": [{"top": {"first": "foo", "last": "foo"}}] | |
102 | }, | |
103 | { | |
104 | "comment": "Matching a JSON array", | |
105 | "expression": "foo[?top == `{\"first\": \"foo\", \"last\": \"bar\"}`]", | |
106 | "result": [{"top": {"first": "foo", "last": "bar"}}] | |
107 | } | |
108 | ] | |
109 | }, | |
110 | { | |
111 | "given": {"foo": [ | |
112 | {"key": true}, | |
113 | {"key": false}, | |
114 | {"key": 0}, | |
115 | {"key": 1}, | |
116 | {"key": [0]}, | |
117 | {"key": {"bar": [0]}}, | |
118 | {"key": null}, | |
119 | {"key": [1]}, | |
120 | {"key": {"a":2}} | |
121 | ]}, | |
122 | "cases": [ | |
123 | { | |
124 | "expression": "foo[?key == `true`]", | |
125 | "result": [{"key": true}] | |
126 | }, | |
127 | { | |
128 | "expression": "foo[?key == `false`]", | |
129 | "result": [{"key": false}] | |
130 | }, | |
131 | { | |
132 | "expression": "foo[?key == `0`]", | |
133 | "result": [{"key": 0}] | |
134 | }, | |
135 | { | |
136 | "expression": "foo[?key == `1`]", | |
137 | "result": [{"key": 1}] | |
138 | }, | |
139 | { | |
140 | "expression": "foo[?key == `[0]`]", | |
141 | "result": [{"key": [0]}] | |
142 | }, | |
143 | { | |
144 | "expression": "foo[?key == `{\"bar\": [0]}`]", | |
145 | "result": [{"key": {"bar": [0]}}] | |
146 | }, | |
147 | { | |
148 | "expression": "foo[?key == `null`]", | |
149 | "result": [{"key": null}] | |
150 | }, | |
151 | { | |
152 | "expression": "foo[?key == `[1]`]", | |
153 | "result": [{"key": [1]}] | |
154 | }, | |
155 | { | |
156 | "expression": "foo[?key == `{\"a\":2}`]", | |
157 | "result": [{"key": {"a":2}}] | |
158 | }, | |
159 | { | |
160 | "expression": "foo[?`true` == key]", | |
161 | "result": [{"key": true}] | |
162 | }, | |
163 | { | |
164 | "expression": "foo[?`false` == key]", | |
165 | "result": [{"key": false}] | |
166 | }, | |
167 | { | |
168 | "expression": "foo[?`0` == key]", | |
169 | "result": [{"key": 0}] | |
170 | }, | |
171 | { | |
172 | "expression": "foo[?`1` == key]", | |
173 | "result": [{"key": 1}] | |
174 | }, | |
175 | { | |
176 | "expression": "foo[?`[0]` == key]", | |
177 | "result": [{"key": [0]}] | |
178 | }, | |
179 | { | |
180 | "expression": "foo[?`{\"bar\": [0]}` == key]", | |
181 | "result": [{"key": {"bar": [0]}}] | |
182 | }, | |
183 | { | |
184 | "expression": "foo[?`null` == key]", | |
185 | "result": [{"key": null}] | |
186 | }, | |
187 | { | |
188 | "expression": "foo[?`[1]` == key]", | |
189 | "result": [{"key": [1]}] | |
190 | }, | |
191 | { | |
192 | "expression": "foo[?`{\"a\":2}` == key]", | |
193 | "result": [{"key": {"a":2}}] | |
194 | }, | |
195 | { | |
196 | "expression": "foo[?key != `true`]", | |
197 | "result": [{"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, | |
198 | {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] | |
199 | }, | |
200 | { | |
201 | "expression": "foo[?key != `false`]", | |
202 | "result": [{"key": true}, {"key": 0}, {"key": 1}, {"key": [0]}, | |
203 | {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] | |
204 | }, | |
205 | { | |
206 | "expression": "foo[?key != `0`]", | |
207 | "result": [{"key": true}, {"key": false}, {"key": 1}, {"key": [0]}, | |
208 | {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] | |
209 | }, | |
210 | { | |
211 | "expression": "foo[?key != `1`]", | |
212 | "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": [0]}, | |
213 | {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] | |
214 | }, | |
215 | { | |
216 | "expression": "foo[?key != `null`]", | |
217 | "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, | |
218 | {"key": {"bar": [0]}}, {"key": [1]}, {"key": {"a":2}}] | |
219 | }, | |
220 | { | |
221 | "expression": "foo[?key != `[1]`]", | |
222 | "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, | |
223 | {"key": {"bar": [0]}}, {"key": null}, {"key": {"a":2}}] | |
224 | }, | |
225 | { | |
226 | "expression": "foo[?key != `{\"a\":2}`]", | |
227 | "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, | |
228 | {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}] | |
229 | }, | |
230 | { | |
231 | "expression": "foo[?`true` != key]", | |
232 | "result": [{"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, | |
233 | {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] | |
234 | }, | |
235 | { | |
236 | "expression": "foo[?`false` != key]", | |
237 | "result": [{"key": true}, {"key": 0}, {"key": 1}, {"key": [0]}, | |
238 | {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] | |
239 | }, | |
240 | { | |
241 | "expression": "foo[?`0` != key]", | |
242 | "result": [{"key": true}, {"key": false}, {"key": 1}, {"key": [0]}, | |
243 | {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] | |
244 | }, | |
245 | { | |
246 | "expression": "foo[?`1` != key]", | |
247 | "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": [0]}, | |
248 | {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}, {"key": {"a":2}}] | |
249 | }, | |
250 | { | |
251 | "expression": "foo[?`null` != key]", | |
252 | "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, | |
253 | {"key": {"bar": [0]}}, {"key": [1]}, {"key": {"a":2}}] | |
254 | }, | |
255 | { | |
256 | "expression": "foo[?`[1]` != key]", | |
257 | "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, | |
258 | {"key": {"bar": [0]}}, {"key": null}, {"key": {"a":2}}] | |
259 | }, | |
260 | { | |
261 | "expression": "foo[?`{\"a\":2}` != key]", | |
262 | "result": [{"key": true}, {"key": false}, {"key": 0}, {"key": 1}, {"key": [0]}, | |
263 | {"key": {"bar": [0]}}, {"key": null}, {"key": [1]}] | |
264 | } | |
265 | ] | |
266 | }, | |
267 | { | |
268 | "given": {"reservations": [ | |
269 | {"instances": [ | |
270 | {"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, | |
271 | {"foo": 1, "bar": 2}, {"foo": 2, "bar": 1}]}]}, | |
272 | "cases": [ | |
273 | { | |
274 | "expression": "reservations[].instances[?bar==`1`]", | |
275 | "result": [[{"foo": 2, "bar": 1}]] | |
276 | }, | |
277 | { | |
278 | "expression": "reservations[*].instances[?bar==`1`]", | |
279 | "result": [[{"foo": 2, "bar": 1}]] | |
280 | }, | |
281 | { | |
282 | "expression": "reservations[].instances[?bar==`1`][]", | |
283 | "result": [{"foo": 2, "bar": 1}] | |
284 | } | |
285 | ] | |
286 | }, | |
287 | { | |
288 | "given": { | |
289 | "baz": "other", | |
290 | "foo": [ | |
291 | {"bar": 1}, {"bar": 2}, {"bar": 3}, {"bar": 4}, {"bar": 1, "baz": 2} | |
292 | ] | |
293 | }, | |
294 | "cases": [ | |
295 | { | |
296 | "expression": "foo[?bar==`1`].bar[0]", | |
297 | "result": [] | |
298 | } | |
299 | ] | |
300 | }, | |
301 | { | |
302 | "given": { | |
303 | "foo": [ | |
304 | {"a": 1, "b": {"c": "x"}}, | |
305 | {"a": 1, "b": {"c": "y"}}, | |
306 | {"a": 1, "b": {"c": "z"}}, | |
307 | {"a": 2, "b": {"c": "z"}}, | |
308 | {"a": 1, "baz": 2} | |
309 | ] | |
310 | }, | |
311 | "cases": [ | |
312 | { | |
313 | "expression": "foo[?a==`1`].b.c", | |
314 | "result": ["x", "y", "z"] | |
315 | } | |
316 | ] | |
317 | }, | |
318 | { | |
319 | "given": {"foo": [{"name": "a"}, {"name": "b"}, {"name": "c"}]}, | |
320 | "cases": [ | |
321 | { | |
322 | "comment": "Filter with or expression", | |
323 | "expression": "foo[?name == 'a' || name == 'b']", | |
324 | "result": [{"name": "a"}, {"name": "b"}] | |
325 | }, | |
326 | { | |
327 | "expression": "foo[?name == 'a' || name == 'e']", | |
328 | "result": [{"name": "a"}] | |
329 | }, | |
330 | { | |
331 | "expression": "foo[?name == 'a' || name == 'b' || name == 'c']", | |
332 | "result": [{"name": "a"}, {"name": "b"}, {"name": "c"}] | |
333 | } | |
334 | ] | |
335 | }, | |
336 | { | |
337 | "given": {"foo": [{"a": 1, "b": 2}, {"a": 1, "b": 3}]}, | |
338 | "cases": [ | |
339 | { | |
340 | "comment": "Filter with and expression", | |
341 | "expression": "foo[?a == `1` && b == `2`]", | |
342 | "result": [{"a": 1, "b": 2}] | |
343 | }, | |
344 | { | |
345 | "expression": "foo[?a == `1` && b == `4`]", | |
346 | "result": [] | |
347 | } | |
348 | ] | |
349 | }, | |
350 | { | |
351 | "given": {"foo": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}]}, | |
352 | "cases": [ | |
353 | { | |
354 | "comment": "Filter with Or and And expressions", | |
355 | "expression": "foo[?c == `3` || a == `1` && b == `4`]", | |
356 | "result": [{"a": 1, "b": 2, "c": 3}] | |
357 | }, | |
358 | { | |
359 | "expression": "foo[?b == `2` || a == `3` && b == `4`]", | |
360 | "result": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}] | |
361 | }, | |
362 | { | |
363 | "expression": "foo[?a == `3` && b == `4` || b == `2`]", | |
364 | "result": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}] | |
365 | }, | |
366 | { | |
367 | "expression": "foo[?(a == `3` && b == `4`) || b == `2`]", | |
368 | "result": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}] | |
369 | }, | |
370 | { | |
371 | "expression": "foo[?((a == `3` && b == `4`)) || b == `2`]", | |
372 | "result": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}] | |
373 | }, | |
374 | { | |
375 | "expression": "foo[?a == `3` && (b == `4` || b == `2`)]", | |
376 | "result": [{"a": 3, "b": 4}] | |
377 | }, | |
378 | { | |
379 | "expression": "foo[?a == `3` && ((b == `4` || b == `2`))]", | |
380 | "result": [{"a": 3, "b": 4}] | |
381 | } | |
382 | ] | |
383 | }, | |
384 | { | |
385 | "given": {"foo": [{"a": 1, "b": 2, "c": 3}, {"a": 3, "b": 4}]}, | |
386 | "cases": [ | |
387 | { | |
388 | "comment": "Verify precedence of or/and expressions", | |
389 | "expression": "foo[?a == `1` || b ==`2` && c == `5`]", | |
390 | "result": [{"a": 1, "b": 2, "c": 3}] | |
391 | }, | |
392 | { | |
393 | "comment": "Parentheses can alter precedence", | |
394 | "expression": "foo[?(a == `1` || b ==`2`) && c == `5`]", | |
395 | "result": [] | |
396 | }, | |
397 | { | |
398 | "comment": "Not expressions combined with and/or", | |
399 | "expression": "foo[?!(a == `1` || b ==`2`)]", | |
400 | "result": [{"a": 3, "b": 4}] | |
401 | } | |
402 | ] | |
403 | }, | |
404 | { | |
405 | "given": { | |
406 | "foo": [ | |
407 | {"key": true}, | |
408 | {"key": false}, | |
409 | {"key": []}, | |
410 | {"key": {}}, | |
411 | {"key": [0]}, | |
412 | {"key": {"a": "b"}}, | |
413 | {"key": 0}, | |
414 | {"key": 1}, | |
415 | {"key": null}, | |
416 | {"notkey": true} | |
417 | ] | |
418 | }, | |
419 | "cases": [ | |
420 | { | |
421 | "comment": "Unary filter expression", | |
422 | "expression": "foo[?key]", | |
423 | "result": [ | |
424 | {"key": true}, {"key": [0]}, {"key": {"a": "b"}}, | |
425 | {"key": 0}, {"key": 1} | |
426 | ] | |
427 | }, | |
428 | { | |
429 | "comment": "Unary not filter expression", | |
430 | "expression": "foo[?!key]", | |
431 | "result": [ | |
432 | {"key": false}, {"key": []}, {"key": {}}, | |
433 | {"key": null}, {"notkey": true} | |
434 | ] | |
435 | }, | |
436 | { | |
437 | "comment": "Equality with null RHS", | |
438 | "expression": "foo[?key == `null`]", | |
439 | "result": [ | |
440 | {"key": null}, {"notkey": true} | |
441 | ] | |
442 | } | |
443 | ] | |
444 | }, | |
445 | { | |
446 | "given": { | |
447 | "foo": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |
448 | }, | |
449 | "cases": [ | |
450 | { | |
451 | "comment": "Using @ in a filter expression", | |
452 | "expression": "foo[?@ < `5`]", | |
453 | "result": [0, 1, 2, 3, 4] | |
454 | }, | |
455 | { | |
456 | "comment": "Using @ in a filter expression", | |
457 | "expression": "foo[?`5` > @]", | |
458 | "result": [0, 1, 2, 3, 4] | |
459 | }, | |
460 | { | |
461 | "comment": "Using @ in a filter expression", | |
462 | "expression": "foo[?@ == @]", | |
463 | "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |
464 | } | |
465 | ] | |
466 | } | |
467 | ] |
0 | [{ | |
1 | "given": | |
2 | { | |
3 | "foo": -1, | |
4 | "zero": 0, | |
5 | "numbers": [-1, 3, 4, 5], | |
6 | "array": [-1, 3, 4, 5, "a", "100"], | |
7 | "strings": ["a", "b", "c"], | |
8 | "decimals": [1.01, 1.2, -1.5], | |
9 | "str": "Str", | |
10 | "false": false, | |
11 | "empty_list": [], | |
12 | "empty_hash": {}, | |
13 | "objects": {"foo": "bar", "bar": "baz"}, | |
14 | "null_key": null | |
15 | }, | |
16 | "cases": [ | |
17 | { | |
18 | "expression": "abs(foo)", | |
19 | "result": 1 | |
20 | }, | |
21 | { | |
22 | "expression": "abs(foo)", | |
23 | "result": 1 | |
24 | }, | |
25 | { | |
26 | "expression": "abs(str)", | |
27 | "error": "invalid-type" | |
28 | }, | |
29 | { | |
30 | "expression": "abs(array[1])", | |
31 | "result": 3 | |
32 | }, | |
33 | { | |
34 | "expression": "abs(array[1])", | |
35 | "result": 3 | |
36 | }, | |
37 | { | |
38 | "expression": "abs(`false`)", | |
39 | "error": "invalid-type" | |
40 | }, | |
41 | { | |
42 | "expression": "abs(`-24`)", | |
43 | "result": 24 | |
44 | }, | |
45 | { | |
46 | "expression": "abs(`-24`)", | |
47 | "result": 24 | |
48 | }, | |
49 | { | |
50 | "expression": "abs(`1`, `2`)", | |
51 | "error": "invalid-arity" | |
52 | }, | |
53 | { | |
54 | "expression": "abs()", | |
55 | "error": "invalid-arity" | |
56 | }, | |
57 | { | |
58 | "expression": "unknown_function(`1`, `2`)", | |
59 | "error": "unknown-function" | |
60 | }, | |
61 | { | |
62 | "expression": "avg(numbers)", | |
63 | "result": 2.75 | |
64 | }, | |
65 | { | |
66 | "expression": "avg(array)", | |
67 | "error": "invalid-type" | |
68 | }, | |
69 | { | |
70 | "expression": "avg('abc')", | |
71 | "error": "invalid-type" | |
72 | }, | |
73 | { | |
74 | "expression": "avg(foo)", | |
75 | "error": "invalid-type" | |
76 | }, | |
77 | { | |
78 | "expression": "avg(@)", | |
79 | "error": "invalid-type" | |
80 | }, | |
81 | { | |
82 | "expression": "avg(strings)", | |
83 | "error": "invalid-type" | |
84 | }, | |
85 | { | |
86 | "expression": "ceil(`1.2`)", | |
87 | "result": 2 | |
88 | }, | |
89 | { | |
90 | "expression": "ceil(decimals[0])", | |
91 | "result": 2 | |
92 | }, | |
93 | { | |
94 | "expression": "ceil(decimals[1])", | |
95 | "result": 2 | |
96 | }, | |
97 | { | |
98 | "expression": "ceil(decimals[2])", | |
99 | "result": -1 | |
100 | }, | |
101 | { | |
102 | "expression": "ceil('string')", | |
103 | "error": "invalid-type" | |
104 | }, | |
105 | { | |
106 | "expression": "contains('abc', 'a')", | |
107 | "result": true | |
108 | }, | |
109 | { | |
110 | "expression": "contains('abc', 'd')", | |
111 | "result": false | |
112 | }, | |
113 | { | |
114 | "expression": "contains(`false`, 'd')", | |
115 | "error": "invalid-type" | |
116 | }, | |
117 | { | |
118 | "expression": "contains(strings, 'a')", | |
119 | "result": true | |
120 | }, | |
121 | { | |
122 | "expression": "contains(decimals, `1.2`)", | |
123 | "result": true | |
124 | }, | |
125 | { | |
126 | "expression": "contains(decimals, `false`)", | |
127 | "result": false | |
128 | }, | |
129 | { | |
130 | "expression": "ends_with(str, 'r')", | |
131 | "result": true | |
132 | }, | |
133 | { | |
134 | "expression": "ends_with(str, 'tr')", | |
135 | "result": true | |
136 | }, | |
137 | { | |
138 | "expression": "ends_with(str, 'Str')", | |
139 | "result": true | |
140 | }, | |
141 | { | |
142 | "expression": "ends_with(str, 'SStr')", | |
143 | "result": false | |
144 | }, | |
145 | { | |
146 | "expression": "ends_with(str, 'foo')", | |
147 | "result": false | |
148 | }, | |
149 | { | |
150 | "expression": "ends_with(str, `0`)", | |
151 | "error": "invalid-type" | |
152 | }, | |
153 | { | |
154 | "expression": "floor(`1.2`)", | |
155 | "result": 1 | |
156 | }, | |
157 | { | |
158 | "expression": "floor('string')", | |
159 | "error": "invalid-type" | |
160 | }, | |
161 | { | |
162 | "expression": "floor(decimals[0])", | |
163 | "result": 1 | |
164 | }, | |
165 | { | |
166 | "expression": "floor(foo)", | |
167 | "result": -1 | |
168 | }, | |
169 | { | |
170 | "expression": "floor(str)", | |
171 | "error": "invalid-type" | |
172 | }, | |
173 | { | |
174 | "expression": "length('abc')", | |
175 | "result": 3 | |
176 | }, | |
177 | { | |
178 | "expression": "length('✓foo')", | |
179 | "result": 4 | |
180 | }, | |
181 | { | |
182 | "expression": "length('')", | |
183 | "result": 0 | |
184 | }, | |
185 | { | |
186 | "expression": "length(@)", | |
187 | "result": 12 | |
188 | }, | |
189 | { | |
190 | "expression": "length(strings[0])", | |
191 | "result": 1 | |
192 | }, | |
193 | { | |
194 | "expression": "length(str)", | |
195 | "result": 3 | |
196 | }, | |
197 | { | |
198 | "expression": "length(array)", | |
199 | "result": 6 | |
200 | }, | |
201 | { | |
202 | "expression": "length(objects)", | |
203 | "result": 2 | |
204 | }, | |
205 | { | |
206 | "expression": "length(`false`)", | |
207 | "error": "invalid-type" | |
208 | }, | |
209 | { | |
210 | "expression": "length(foo)", | |
211 | "error": "invalid-type" | |
212 | }, | |
213 | { | |
214 | "expression": "length(strings[0])", | |
215 | "result": 1 | |
216 | }, | |
217 | { | |
218 | "expression": "max(numbers)", | |
219 | "result": 5 | |
220 | }, | |
221 | { | |
222 | "expression": "max(decimals)", | |
223 | "result": 1.2 | |
224 | }, | |
225 | { | |
226 | "expression": "max(strings)", | |
227 | "result": "c" | |
228 | }, | |
229 | { | |
230 | "expression": "max(abc)", | |
231 | "error": "invalid-type" | |
232 | }, | |
233 | { | |
234 | "expression": "max(array)", | |
235 | "error": "invalid-type" | |
236 | }, | |
237 | { | |
238 | "expression": "max(decimals)", | |
239 | "result": 1.2 | |
240 | }, | |
241 | { | |
242 | "expression": "max(empty_list)", | |
243 | "result": null | |
244 | }, | |
245 | { | |
246 | "expression": "merge(`{}`)", | |
247 | "result": {} | |
248 | }, | |
249 | { | |
250 | "expression": "merge(`{}`, `{}`)", | |
251 | "result": {} | |
252 | }, | |
253 | { | |
254 | "expression": "merge(`{\"a\": 1}`, `{\"b\": 2}`)", | |
255 | "result": {"a": 1, "b": 2} | |
256 | }, | |
257 | { | |
258 | "expression": "merge(`{\"a\": 1}`, `{\"a\": 2}`)", | |
259 | "result": {"a": 2} | |
260 | }, | |
261 | { | |
262 | "expression": "merge(`{\"a\": 1, \"b\": 2}`, `{\"a\": 2, \"c\": 3}`, `{\"d\": 4}`)", | |
263 | "result": {"a": 2, "b": 2, "c": 3, "d": 4} | |
264 | }, | |
265 | { | |
266 | "expression": "min(numbers)", | |
267 | "result": -1 | |
268 | }, | |
269 | { | |
270 | "expression": "min(decimals)", | |
271 | "result": -1.5 | |
272 | }, | |
273 | { | |
274 | "expression": "min(abc)", | |
275 | "error": "invalid-type" | |
276 | }, | |
277 | { | |
278 | "expression": "min(array)", | |
279 | "error": "invalid-type" | |
280 | }, | |
281 | { | |
282 | "expression": "min(empty_list)", | |
283 | "result": null | |
284 | }, | |
285 | { | |
286 | "expression": "min(decimals)", | |
287 | "result": -1.5 | |
288 | }, | |
289 | { | |
290 | "expression": "min(strings)", | |
291 | "result": "a" | |
292 | }, | |
293 | { | |
294 | "expression": "type('abc')", | |
295 | "result": "string" | |
296 | }, | |
297 | { | |
298 | "expression": "type(`1.0`)", | |
299 | "result": "number" | |
300 | }, | |
301 | { | |
302 | "expression": "type(`2`)", | |
303 | "result": "number" | |
304 | }, | |
305 | { | |
306 | "expression": "type(`true`)", | |
307 | "result": "boolean" | |
308 | }, | |
309 | { | |
310 | "expression": "type(`false`)", | |
311 | "result": "boolean" | |
312 | }, | |
313 | { | |
314 | "expression": "type(`null`)", | |
315 | "result": "null" | |
316 | }, | |
317 | { | |
318 | "expression": "type(`[0]`)", | |
319 | "result": "array" | |
320 | }, | |
321 | { | |
322 | "expression": "type(`{\"a\": \"b\"}`)", | |
323 | "result": "object" | |
324 | }, | |
325 | { | |
326 | "expression": "type(@)", | |
327 | "result": "object" | |
328 | }, | |
329 | { | |
330 | "expression": "sort(keys(objects))", | |
331 | "result": ["bar", "foo"] | |
332 | }, | |
333 | { | |
334 | "expression": "keys(foo)", | |
335 | "error": "invalid-type" | |
336 | }, | |
337 | { | |
338 | "expression": "keys(strings)", | |
339 | "error": "invalid-type" | |
340 | }, | |
341 | { | |
342 | "expression": "keys(`false`)", | |
343 | "error": "invalid-type" | |
344 | }, | |
345 | { | |
346 | "expression": "sort(values(objects))", | |
347 | "result": ["bar", "baz"] | |
348 | }, | |
349 | { | |
350 | "expression": "keys(empty_hash)", | |
351 | "result": [] | |
352 | }, | |
353 | { | |
354 | "expression": "values(foo)", | |
355 | "error": "invalid-type" | |
356 | }, | |
357 | { | |
358 | "expression": "join(', ', strings)", | |
359 | "result": "a, b, c" | |
360 | }, | |
361 | { | |
362 | "expression": "join(', ', strings)", | |
363 | "result": "a, b, c" | |
364 | }, | |
365 | { | |
366 | "expression": "join(',', `[\"a\", \"b\"]`)", | |
367 | "result": "a,b" | |
368 | }, | |
369 | { | |
370 | "expression": "join(',', `[\"a\", 0]`)", | |
371 | "error": "invalid-type" | |
372 | }, | |
373 | { | |
374 | "expression": "join(', ', str)", | |
375 | "error": "invalid-type" | |
376 | }, | |
377 | { | |
378 | "expression": "join('|', strings)", | |
379 | "result": "a|b|c" | |
380 | }, | |
381 | { | |
382 | "expression": "join(`2`, strings)", | |
383 | "error": "invalid-type" | |
384 | }, | |
385 | { | |
386 | "expression": "join('|', decimals)", | |
387 | "error": "invalid-type" | |
388 | }, | |
389 | { | |
390 | "expression": "join('|', decimals[].to_string(@))", | |
391 | "result": "1.01|1.2|-1.5" | |
392 | }, | |
393 | { | |
394 | "expression": "join('|', empty_list)", | |
395 | "result": "" | |
396 | }, | |
397 | { | |
398 | "expression": "reverse(numbers)", | |
399 | "result": [5, 4, 3, -1] | |
400 | }, | |
401 | { | |
402 | "expression": "reverse(array)", | |
403 | "result": ["100", "a", 5, 4, 3, -1] | |
404 | }, | |
405 | { | |
406 | "expression": "reverse(`[]`)", | |
407 | "result": [] | |
408 | }, | |
409 | { | |
410 | "expression": "reverse('')", | |
411 | "result": "" | |
412 | }, | |
413 | { | |
414 | "expression": "reverse('hello world')", | |
415 | "result": "dlrow olleh" | |
416 | }, | |
417 | { | |
418 | "expression": "starts_with(str, 'S')", | |
419 | "result": true | |
420 | }, | |
421 | { | |
422 | "expression": "starts_with(str, 'St')", | |
423 | "result": true | |
424 | }, | |
425 | { | |
426 | "expression": "starts_with(str, 'Str')", | |
427 | "result": true | |
428 | }, | |
429 | { | |
430 | "expression": "starts_with(str, 'String')", | |
431 | "result": false | |
432 | }, | |
433 | { | |
434 | "expression": "starts_with(str, `0`)", | |
435 | "error": "invalid-type" | |
436 | }, | |
437 | { | |
438 | "expression": "sum(numbers)", | |
439 | "result": 11 | |
440 | }, | |
441 | { | |
442 | "expression": "sum(decimals)", | |
443 | "result": 0.71 | |
444 | }, | |
445 | { | |
446 | "expression": "sum(array)", | |
447 | "error": "invalid-type" | |
448 | }, | |
449 | { | |
450 | "expression": "sum(array[].to_number(@))", | |
451 | "result": 111 | |
452 | }, | |
453 | { | |
454 | "expression": "sum(`[]`)", | |
455 | "result": 0 | |
456 | }, | |
457 | { | |
458 | "expression": "to_array('foo')", | |
459 | "result": ["foo"] | |
460 | }, | |
461 | { | |
462 | "expression": "to_array(`0`)", | |
463 | "result": [0] | |
464 | }, | |
465 | { | |
466 | "expression": "to_array(objects)", | |
467 | "result": [{"foo": "bar", "bar": "baz"}] | |
468 | }, | |
469 | { | |
470 | "expression": "to_array(`[1, 2, 3]`)", | |
471 | "result": [1, 2, 3] | |
472 | }, | |
473 | { | |
474 | "expression": "to_array(false)", | |
475 | "result": [false] | |
476 | }, | |
477 | { | |
478 | "expression": "to_string('foo')", | |
479 | "result": "foo" | |
480 | }, | |
481 | { | |
482 | "expression": "to_string(`1.2`)", | |
483 | "result": "1.2" | |
484 | }, | |
485 | { | |
486 | "expression": "to_string(`[0, 1]`)", | |
487 | "result": "[0,1]" | |
488 | }, | |
489 | { | |
490 | "expression": "to_number('1.0')", | |
491 | "result": 1.0 | |
492 | }, | |
493 | { | |
494 | "expression": "to_number('1.1')", | |
495 | "result": 1.1 | |
496 | }, | |
497 | { | |
498 | "expression": "to_number('4')", | |
499 | "result": 4 | |
500 | }, | |
501 | { | |
502 | "expression": "to_number('notanumber')", | |
503 | "result": null | |
504 | }, | |
505 | { | |
506 | "expression": "to_number(`false`)", | |
507 | "result": null | |
508 | }, | |
509 | { | |
510 | "expression": "to_number(`null`)", | |
511 | "result": null | |
512 | }, | |
513 | { | |
514 | "expression": "to_number(`[0]`)", | |
515 | "result": null | |
516 | }, | |
517 | { | |
518 | "expression": "to_number(`{\"foo\": 0}`)", | |
519 | "result": null | |
520 | }, | |
521 | { | |
522 | "expression": "\"to_string\"(`1.0`)", | |
523 | "error": "syntax" | |
524 | }, | |
525 | { | |
526 | "expression": "sort(numbers)", | |
527 | "result": [-1, 3, 4, 5] | |
528 | }, | |
529 | { | |
530 | "expression": "sort(strings)", | |
531 | "result": ["a", "b", "c"] | |
532 | }, | |
533 | { | |
534 | "expression": "sort(decimals)", | |
535 | "result": [-1.5, 1.01, 1.2] | |
536 | }, | |
537 | { | |
538 | "expression": "sort(array)", | |
539 | "error": "invalid-type" | |
540 | }, | |
541 | { | |
542 | "expression": "sort(abc)", | |
543 | "error": "invalid-type" | |
544 | }, | |
545 | { | |
546 | "expression": "sort(empty_list)", | |
547 | "result": [] | |
548 | }, | |
549 | { | |
550 | "expression": "sort(@)", | |
551 | "error": "invalid-type" | |
552 | }, | |
553 | { | |
554 | "expression": "not_null(unknown_key, str)", | |
555 | "result": "Str" | |
556 | }, | |
557 | { | |
558 | "expression": "not_null(unknown_key, foo.bar, empty_list, str)", | |
559 | "result": [] | |
560 | }, | |
561 | { | |
562 | "expression": "not_null(unknown_key, null_key, empty_list, str)", | |
563 | "result": [] | |
564 | }, | |
565 | { | |
566 | "expression": "not_null(all, expressions, are_null)", | |
567 | "result": null | |
568 | }, | |
569 | { | |
570 | "expression": "not_null()", | |
571 | "error": "invalid-arity" | |
572 | }, | |
573 | { | |
574 | "description": "function projection on single arg function", | |
575 | "expression": "numbers[].to_string(@)", | |
576 | "result": ["-1", "3", "4", "5"] | |
577 | }, | |
578 | { | |
579 | "description": "function projection on single arg function", | |
580 | "expression": "array[].to_number(@)", | |
581 | "result": [-1, 3, 4, 5, 100] | |
582 | } | |
583 | ] | |
584 | }, { | |
585 | "given": | |
586 | { | |
587 | "foo": [ | |
588 | {"b": "b", "a": "a"}, | |
589 | {"c": "c", "b": "b"}, | |
590 | {"d": "d", "c": "c"}, | |
591 | {"e": "e", "d": "d"}, | |
592 | {"f": "f", "e": "e"} | |
593 | ] | |
594 | }, | |
595 | "cases": [ | |
596 | { | |
597 | "description": "function projection on variadic function", | |
598 | "expression": "foo[].not_null(f, e, d, c, b, a)", | |
599 | "result": ["b", "c", "d", "e", "f"] | |
600 | } | |
601 | ] | |
602 | }, { | |
603 | "given": | |
604 | { | |
605 | "people": [ | |
606 | {"age": 20, "age_str": "20", "bool": true, "name": "a", "extra": "foo"}, | |
607 | {"age": 40, "age_str": "40", "bool": false, "name": "b", "extra": "bar"}, | |
608 | {"age": 30, "age_str": "30", "bool": true, "name": "c"}, | |
609 | {"age": 50, "age_str": "50", "bool": false, "name": "d"}, | |
610 | {"age": 10, "age_str": "10", "bool": true, "name": 3} | |
611 | ] | |
612 | }, | |
613 | "cases": [ | |
614 | { | |
615 | "description": "sort by field expression", | |
616 | "expression": "sort_by(people, &age)", | |
617 | "result": [ | |
618 | {"age": 10, "age_str": "10", "bool": true, "name": 3}, | |
619 | {"age": 20, "age_str": "20", "bool": true, "name": "a", "extra": "foo"}, | |
620 | {"age": 30, "age_str": "30", "bool": true, "name": "c"}, | |
621 | {"age": 40, "age_str": "40", "bool": false, "name": "b", "extra": "bar"}, | |
622 | {"age": 50, "age_str": "50", "bool": false, "name": "d"} | |
623 | ] | |
624 | }, | |
625 | { | |
626 | "expression": "sort_by(people, &age_str)", | |
627 | "result": [ | |
628 | {"age": 10, "age_str": "10", "bool": true, "name": 3}, | |
629 | {"age": 20, "age_str": "20", "bool": true, "name": "a", "extra": "foo"}, | |
630 | {"age": 30, "age_str": "30", "bool": true, "name": "c"}, | |
631 | {"age": 40, "age_str": "40", "bool": false, "name": "b", "extra": "bar"}, | |
632 | {"age": 50, "age_str": "50", "bool": false, "name": "d"} | |
633 | ] | |
634 | }, | |
635 | { | |
636 | "description": "sort by function expression", | |
637 | "expression": "sort_by(people, &to_number(age_str))", | |
638 | "result": [ | |
639 | {"age": 10, "age_str": "10", "bool": true, "name": 3}, | |
640 | {"age": 20, "age_str": "20", "bool": true, "name": "a", "extra": "foo"}, | |
641 | {"age": 30, "age_str": "30", "bool": true, "name": "c"}, | |
642 | {"age": 40, "age_str": "40", "bool": false, "name": "b", "extra": "bar"}, | |
643 | {"age": 50, "age_str": "50", "bool": false, "name": "d"} | |
644 | ] | |
645 | }, | |
646 | { | |
647 | "description": "function projection on sort_by function", | |
648 | "expression": "sort_by(people, &age)[].name", | |
649 | "result": [3, "a", "c", "b", "d"] | |
650 | }, | |
651 | { | |
652 | "expression": "sort_by(people, &extra)", | |
653 | "error": "invalid-type" | |
654 | }, | |
655 | { | |
656 | "expression": "sort_by(people, &bool)", | |
657 | "error": "invalid-type" | |
658 | }, | |
659 | { | |
660 | "expression": "sort_by(people, &name)", | |
661 | "error": "invalid-type" | |
662 | }, | |
663 | { | |
664 | "expression": "sort_by(people, name)", | |
665 | "error": "invalid-type" | |
666 | }, | |
667 | { | |
668 | "expression": "sort_by(people, &age)[].extra", | |
669 | "result": ["foo", "bar"] | |
670 | }, | |
671 | { | |
672 | "expression": "sort_by(`[]`, &age)", | |
673 | "result": [] | |
674 | }, | |
675 | { | |
676 | "expression": "max_by(people, &age)", | |
677 | "result": {"age": 50, "age_str": "50", "bool": false, "name": "d"} | |
678 | }, | |
679 | { | |
680 | "expression": "max_by(people, &age_str)", | |
681 | "result": {"age": 50, "age_str": "50", "bool": false, "name": "d"} | |
682 | }, | |
683 | { | |
684 | "expression": "max_by(people, &bool)", | |
685 | "error": "invalid-type" | |
686 | }, | |
687 | { | |
688 | "expression": "max_by(people, &extra)", | |
689 | "error": "invalid-type" | |
690 | }, | |
691 | { | |
692 | "expression": "max_by(people, &to_number(age_str))", | |
693 | "result": {"age": 50, "age_str": "50", "bool": false, "name": "d"} | |
694 | }, | |
695 | { | |
696 | "expression": "min_by(people, &age)", | |
697 | "result": {"age": 10, "age_str": "10", "bool": true, "name": 3} | |
698 | }, | |
699 | { | |
700 | "expression": "min_by(people, &age_str)", | |
701 | "result": {"age": 10, "age_str": "10", "bool": true, "name": 3} | |
702 | }, | |
703 | { | |
704 | "expression": "min_by(people, &bool)", | |
705 | "error": "invalid-type" | |
706 | }, | |
707 | { | |
708 | "expression": "min_by(people, &extra)", | |
709 | "error": "invalid-type" | |
710 | }, | |
711 | { | |
712 | "expression": "min_by(people, &to_number(age_str))", | |
713 | "result": {"age": 10, "age_str": "10", "bool": true, "name": 3} | |
714 | } | |
715 | ] | |
716 | }, { | |
717 | "given": | |
718 | { | |
719 | "people": [ | |
720 | {"age": 10, "order": "1"}, | |
721 | {"age": 10, "order": "2"}, | |
722 | {"age": 10, "order": "3"}, | |
723 | {"age": 10, "order": "4"}, | |
724 | {"age": 10, "order": "5"}, | |
725 | {"age": 10, "order": "6"}, | |
726 | {"age": 10, "order": "7"}, | |
727 | {"age": 10, "order": "8"}, | |
728 | {"age": 10, "order": "9"}, | |
729 | {"age": 10, "order": "10"}, | |
730 | {"age": 10, "order": "11"} | |
731 | ] | |
732 | }, | |
733 | "cases": [ | |
734 | { | |
735 | "description": "stable sort order", | |
736 | "expression": "sort_by(people, &age)", | |
737 | "result": [ | |
738 | {"age": 10, "order": "1"}, | |
739 | {"age": 10, "order": "2"}, | |
740 | {"age": 10, "order": "3"}, | |
741 | {"age": 10, "order": "4"}, | |
742 | {"age": 10, "order": "5"}, | |
743 | {"age": 10, "order": "6"}, | |
744 | {"age": 10, "order": "7"}, | |
745 | {"age": 10, "order": "8"}, | |
746 | {"age": 10, "order": "9"}, | |
747 | {"age": 10, "order": "10"}, | |
748 | {"age": 10, "order": "11"} | |
749 | ] | |
750 | } | |
751 | ] | |
752 | }, { | |
753 | "given": | |
754 | { | |
755 | "people": [ | |
756 | {"a": 10, "b": 1, "c": "z"}, | |
757 | {"a": 10, "b": 2, "c": null}, | |
758 | {"a": 10, "b": 3}, | |
759 | {"a": 10, "b": 4, "c": "z"}, | |
760 | {"a": 10, "b": 5, "c": null}, | |
761 | {"a": 10, "b": 6}, | |
762 | {"a": 10, "b": 7, "c": "z"}, | |
763 | {"a": 10, "b": 8, "c": null}, | |
764 | {"a": 10, "b": 9} | |
765 | ], | |
766 | "empty": [] | |
767 | }, | |
768 | "cases": [ | |
769 | { | |
770 | "expression": "map(&a, people)", | |
771 | "result": [10, 10, 10, 10, 10, 10, 10, 10, 10] | |
772 | }, | |
773 | { | |
774 | "expression": "map(&c, people)", | |
775 | "result": ["z", null, null, "z", null, null, "z", null, null] | |
776 | }, | |
777 | { | |
778 | "expression": "map(&a, badkey)", | |
779 | "error": "invalid-type" | |
780 | }, | |
781 | { | |
782 | "expression": "map(&foo, empty)", | |
783 | "result": [] | |
784 | } | |
785 | ] | |
786 | }, { | |
787 | "given": { | |
788 | "array": [ | |
789 | { | |
790 | "foo": {"bar": "yes1"} | |
791 | }, | |
792 | { | |
793 | "foo": {"bar": "yes2"} | |
794 | }, | |
795 | { | |
796 | "foo1": {"bar": "no"} | |
797 | } | |
798 | ]}, | |
799 | "cases": [ | |
800 | { | |
801 | "expression": "map(&foo.bar, array)", | |
802 | "result": ["yes1", "yes2", null] | |
803 | }, | |
804 | { | |
805 | "expression": "map(&foo1.bar, array)", | |
806 | "result": [null, null, "no"] | |
807 | }, | |
808 | { | |
809 | "expression": "map(&foo.bar.baz, array)", | |
810 | "result": [null, null, null] | |
811 | } | |
812 | ] | |
813 | }, { | |
814 | "given": { | |
815 | "array": [[1, 2, 3, [4]], [5, 6, 7, [8, 9]]] | |
816 | }, | |
817 | "cases": [ | |
818 | { | |
819 | "expression": "map(&[], array)", | |
820 | "result": [[1, 2, 3, 4], [5, 6, 7, 8, 9]] | |
821 | } | |
822 | ] | |
823 | } | |
824 | ] |
0 | [ | |
1 | { | |
2 | "given": { | |
3 | "__L": true | |
4 | }, | |
5 | "cases": [ | |
6 | { | |
7 | "expression": "__L", | |
8 | "result": true | |
9 | } | |
10 | ] | |
11 | }, | |
12 | { | |
13 | "given": { | |
14 | "!\r": true | |
15 | }, | |
16 | "cases": [ | |
17 | { | |
18 | "expression": "\"!\\r\"", | |
19 | "result": true | |
20 | } | |
21 | ] | |
22 | }, | |
23 | { | |
24 | "given": { | |
25 | "Y_1623": true | |
26 | }, | |
27 | "cases": [ | |
28 | { | |
29 | "expression": "Y_1623", | |
30 | "result": true | |
31 | } | |
32 | ] | |
33 | }, | |
34 | { | |
35 | "given": { | |
36 | "x": true | |
37 | }, | |
38 | "cases": [ | |
39 | { | |
40 | "expression": "x", | |
41 | "result": true | |
42 | } | |
43 | ] | |
44 | }, | |
45 | { | |
46 | "given": { | |
47 | "\tF\uCebb": true | |
48 | }, | |
49 | "cases": [ | |
50 | { | |
51 | "expression": "\"\\tF\\uCebb\"", | |
52 | "result": true | |
53 | } | |
54 | ] | |
55 | }, | |
56 | { | |
57 | "given": { | |
58 | " \t": true | |
59 | }, | |
60 | "cases": [ | |
61 | { | |
62 | "expression": "\" \\t\"", | |
63 | "result": true | |
64 | } | |
65 | ] | |
66 | }, | |
67 | { | |
68 | "given": { | |
69 | " ": true | |
70 | }, | |
71 | "cases": [ | |
72 | { | |
73 | "expression": "\" \"", | |
74 | "result": true | |
75 | } | |
76 | ] | |
77 | }, | |
78 | { | |
79 | "given": { | |
80 | "v2": true | |
81 | }, | |
82 | "cases": [ | |
83 | { | |
84 | "expression": "v2", | |
85 | "result": true | |
86 | } | |
87 | ] | |
88 | }, | |
89 | { | |
90 | "given": { | |
91 | "\t": true | |
92 | }, | |
93 | "cases": [ | |
94 | { | |
95 | "expression": "\"\\t\"", | |
96 | "result": true | |
97 | } | |
98 | ] | |
99 | }, | |
100 | { | |
101 | "given": { | |
102 | "_X": true | |
103 | }, | |
104 | "cases": [ | |
105 | { | |
106 | "expression": "_X", | |
107 | "result": true | |
108 | } | |
109 | ] | |
110 | }, | |
111 | { | |
112 | "given": { | |
113 | "\t4\ud9da\udd15": true | |
114 | }, | |
115 | "cases": [ | |
116 | { | |
117 | "expression": "\"\\t4\\ud9da\\udd15\"", | |
118 | "result": true | |
119 | } | |
120 | ] | |
121 | }, | |
122 | { | |
123 | "given": { | |
124 | "v24_W": true | |
125 | }, | |
126 | "cases": [ | |
127 | { | |
128 | "expression": "v24_W", | |
129 | "result": true | |
130 | } | |
131 | ] | |
132 | }, | |
133 | { | |
134 | "given": { | |
135 | "H": true | |
136 | }, | |
137 | "cases": [ | |
138 | { | |
139 | "expression": "\"H\"", | |
140 | "result": true | |
141 | } | |
142 | ] | |
143 | }, | |
144 | { | |
145 | "given": { | |
146 | "\f": true | |
147 | }, | |
148 | "cases": [ | |
149 | { | |
150 | "expression": "\"\\f\"", | |
151 | "result": true | |
152 | } | |
153 | ] | |
154 | }, | |
155 | { | |
156 | "given": { | |
157 | "E4": true | |
158 | }, | |
159 | "cases": [ | |
160 | { | |
161 | "expression": "\"E4\"", | |
162 | "result": true | |
163 | } | |
164 | ] | |
165 | }, | |
166 | { | |
167 | "given": { | |
168 | "!": true | |
169 | }, | |
170 | "cases": [ | |
171 | { | |
172 | "expression": "\"!\"", | |
173 | "result": true | |
174 | } | |
175 | ] | |
176 | }, | |
177 | { | |
178 | "given": { | |
179 | "tM": true | |
180 | }, | |
181 | "cases": [ | |
182 | { | |
183 | "expression": "tM", | |
184 | "result": true | |
185 | } | |
186 | ] | |
187 | }, | |
188 | { | |
189 | "given": { | |
190 | " [": true | |
191 | }, | |
192 | "cases": [ | |
193 | { | |
194 | "expression": "\" [\"", | |
195 | "result": true | |
196 | } | |
197 | ] | |
198 | }, | |
199 | { | |
200 | "given": { | |
201 | "R!": true | |
202 | }, | |
203 | "cases": [ | |
204 | { | |
205 | "expression": "\"R!\"", | |
206 | "result": true | |
207 | } | |
208 | ] | |
209 | }, | |
210 | { | |
211 | "given": { | |
212 | "_6W": true | |
213 | }, | |
214 | "cases": [ | |
215 | { | |
216 | "expression": "_6W", | |
217 | "result": true | |
218 | } | |
219 | ] | |
220 | }, | |
221 | { | |
222 | "given": { | |
223 | "\uaBA1\r": true | |
224 | }, | |
225 | "cases": [ | |
226 | { | |
227 | "expression": "\"\\uaBA1\\r\"", | |
228 | "result": true | |
229 | } | |
230 | ] | |
231 | }, | |
232 | { | |
233 | "given": { | |
234 | "tL7": true | |
235 | }, | |
236 | "cases": [ | |
237 | { | |
238 | "expression": "tL7", | |
239 | "result": true | |
240 | } | |
241 | ] | |
242 | }, | |
243 | { | |
244 | "given": { | |
245 | "<<U\t": true | |
246 | }, | |
247 | "cases": [ | |
248 | { | |
249 | "expression": "\"<<U\\t\"", | |
250 | "result": true | |
251 | } | |
252 | ] | |
253 | }, | |
254 | { | |
255 | "given": { | |
256 | "\ubBcE\ufAfB": true | |
257 | }, | |
258 | "cases": [ | |
259 | { | |
260 | "expression": "\"\\ubBcE\\ufAfB\"", | |
261 | "result": true | |
262 | } | |
263 | ] | |
264 | }, | |
265 | { | |
266 | "given": { | |
267 | "sNA_": true | |
268 | }, | |
269 | "cases": [ | |
270 | { | |
271 | "expression": "sNA_", | |
272 | "result": true | |
273 | } | |
274 | ] | |
275 | }, | |
276 | { | |
277 | "given": { | |
278 | "9": true | |
279 | }, | |
280 | "cases": [ | |
281 | { | |
282 | "expression": "\"9\"", | |
283 | "result": true | |
284 | } | |
285 | ] | |
286 | }, | |
287 | { | |
288 | "given": { | |
289 | "\\\b\ud8cb\udc83": true | |
290 | }, | |
291 | "cases": [ | |
292 | { | |
293 | "expression": "\"\\\\\\b\\ud8cb\\udc83\"", | |
294 | "result": true | |
295 | } | |
296 | ] | |
297 | }, | |
298 | { | |
299 | "given": { | |
300 | "r": true | |
301 | }, | |
302 | "cases": [ | |
303 | { | |
304 | "expression": "\"r\"", | |
305 | "result": true | |
306 | } | |
307 | ] | |
308 | }, | |
309 | { | |
310 | "given": { | |
311 | "Q": true | |
312 | }, | |
313 | "cases": [ | |
314 | { | |
315 | "expression": "Q", | |
316 | "result": true | |
317 | } | |
318 | ] | |
319 | }, | |
320 | { | |
321 | "given": { | |
322 | "_Q__7GL8": true | |
323 | }, | |
324 | "cases": [ | |
325 | { | |
326 | "expression": "_Q__7GL8", | |
327 | "result": true | |
328 | } | |
329 | ] | |
330 | }, | |
331 | { | |
332 | "given": { | |
333 | "\\": true | |
334 | }, | |
335 | "cases": [ | |
336 | { | |
337 | "expression": "\"\\\\\"", | |
338 | "result": true | |
339 | } | |
340 | ] | |
341 | }, | |
342 | { | |
343 | "given": { | |
344 | "RR9_": true | |
345 | }, | |
346 | "cases": [ | |
347 | { | |
348 | "expression": "RR9_", | |
349 | "result": true | |
350 | } | |
351 | ] | |
352 | }, | |
353 | { | |
354 | "given": { | |
355 | "\r\f:": true | |
356 | }, | |
357 | "cases": [ | |
358 | { | |
359 | "expression": "\"\\r\\f:\"", | |
360 | "result": true | |
361 | } | |
362 | ] | |
363 | }, | |
364 | { | |
365 | "given": { | |
366 | "r7": true | |
367 | }, | |
368 | "cases": [ | |
369 | { | |
370 | "expression": "r7", | |
371 | "result": true | |
372 | } | |
373 | ] | |
374 | }, | |
375 | { | |
376 | "given": { | |
377 | "-": true | |
378 | }, | |
379 | "cases": [ | |
380 | { | |
381 | "expression": "\"-\"", | |
382 | "result": true | |
383 | } | |
384 | ] | |
385 | }, | |
386 | { | |
387 | "given": { | |
388 | "p9": true | |
389 | }, | |
390 | "cases": [ | |
391 | { | |
392 | "expression": "p9", | |
393 | "result": true | |
394 | } | |
395 | ] | |
396 | }, | |
397 | { | |
398 | "given": { | |
399 | "__": true | |
400 | }, | |
401 | "cases": [ | |
402 | { | |
403 | "expression": "__", | |
404 | "result": true | |
405 | } | |
406 | ] | |
407 | }, | |
408 | { | |
409 | "given": { | |
410 | "\b\t": true | |
411 | }, | |
412 | "cases": [ | |
413 | { | |
414 | "expression": "\"\\b\\t\"", | |
415 | "result": true | |
416 | } | |
417 | ] | |
418 | }, | |
419 | { | |
420 | "given": { | |
421 | "O_": true | |
422 | }, | |
423 | "cases": [ | |
424 | { | |
425 | "expression": "O_", | |
426 | "result": true | |
427 | } | |
428 | ] | |
429 | }, | |
430 | { | |
431 | "given": { | |
432 | "_r_8": true | |
433 | }, | |
434 | "cases": [ | |
435 | { | |
436 | "expression": "_r_8", | |
437 | "result": true | |
438 | } | |
439 | ] | |
440 | }, | |
441 | { | |
442 | "given": { | |
443 | "_j": true | |
444 | }, | |
445 | "cases": [ | |
446 | { | |
447 | "expression": "_j", | |
448 | "result": true | |
449 | } | |
450 | ] | |
451 | }, | |
452 | { | |
453 | "given": { | |
454 | ":": true | |
455 | }, | |
456 | "cases": [ | |
457 | { | |
458 | "expression": "\":\"", | |
459 | "result": true | |
460 | } | |
461 | ] | |
462 | }, | |
463 | { | |
464 | "given": { | |
465 | "\rB": true | |
466 | }, | |
467 | "cases": [ | |
468 | { | |
469 | "expression": "\"\\rB\"", | |
470 | "result": true | |
471 | } | |
472 | ] | |
473 | }, | |
474 | { | |
475 | "given": { | |
476 | "Obf": true | |
477 | }, | |
478 | "cases": [ | |
479 | { | |
480 | "expression": "Obf", | |
481 | "result": true | |
482 | } | |
483 | ] | |
484 | }, | |
485 | { | |
486 | "given": { | |
487 | "\n": true | |
488 | }, | |
489 | "cases": [ | |
490 | { | |
491 | "expression": "\"\\n\"", | |
492 | "result": true | |
493 | } | |
494 | ] | |
495 | }, | |
496 | { | |
497 | "given": { | |
498 | "\f\udb54\udf33": true | |
499 | }, | |
500 | "cases": [ | |
501 | { | |
502 | "expression": "\"\\f\udb54\udf33\"", | |
503 | "result": true | |
504 | } | |
505 | ] | |
506 | }, | |
507 | { | |
508 | "given": { | |
509 | "\\\u4FDc": true | |
510 | }, | |
511 | "cases": [ | |
512 | { | |
513 | "expression": "\"\\\\\\u4FDc\"", | |
514 | "result": true | |
515 | } | |
516 | ] | |
517 | }, | |
518 | { | |
519 | "given": { | |
520 | "\r": true | |
521 | }, | |
522 | "cases": [ | |
523 | { | |
524 | "expression": "\"\\r\"", | |
525 | "result": true | |
526 | } | |
527 | ] | |
528 | }, | |
529 | { | |
530 | "given": { | |
531 | "m_": true | |
532 | }, | |
533 | "cases": [ | |
534 | { | |
535 | "expression": "m_", | |
536 | "result": true | |
537 | } | |
538 | ] | |
539 | }, | |
540 | { | |
541 | "given": { | |
542 | "\r\fB ": true | |
543 | }, | |
544 | "cases": [ | |
545 | { | |
546 | "expression": "\"\\r\\fB \"", | |
547 | "result": true | |
548 | } | |
549 | ] | |
550 | }, | |
551 | { | |
552 | "given": { | |
553 | "+\"\"": true | |
554 | }, | |
555 | "cases": [ | |
556 | { | |
557 | "expression": "\"+\\\"\\\"\"", | |
558 | "result": true | |
559 | } | |
560 | ] | |
561 | }, | |
562 | { | |
563 | "given": { | |
564 | "Mg": true | |
565 | }, | |
566 | "cases": [ | |
567 | { | |
568 | "expression": "Mg", | |
569 | "result": true | |
570 | } | |
571 | ] | |
572 | }, | |
573 | { | |
574 | "given": { | |
575 | "\"!\/": true | |
576 | }, | |
577 | "cases": [ | |
578 | { | |
579 | "expression": "\"\\\"!\\/\"", | |
580 | "result": true | |
581 | } | |
582 | ] | |
583 | }, | |
584 | { | |
585 | "given": { | |
586 | "7\"": true | |
587 | }, | |
588 | "cases": [ | |
589 | { | |
590 | "expression": "\"7\\\"\"", | |
591 | "result": true | |
592 | } | |
593 | ] | |
594 | }, | |
595 | { | |
596 | "given": { | |
597 | "\\\udb3a\udca4S": true | |
598 | }, | |
599 | "cases": [ | |
600 | { | |
601 | "expression": "\"\\\\\udb3a\udca4S\"", | |
602 | "result": true | |
603 | } | |
604 | ] | |
605 | }, | |
606 | { | |
607 | "given": { | |
608 | "\"": true | |
609 | }, | |
610 | "cases": [ | |
611 | { | |
612 | "expression": "\"\\\"\"", | |
613 | "result": true | |
614 | } | |
615 | ] | |
616 | }, | |
617 | { | |
618 | "given": { | |
619 | "Kl": true | |
620 | }, | |
621 | "cases": [ | |
622 | { | |
623 | "expression": "Kl", | |
624 | "result": true | |
625 | } | |
626 | ] | |
627 | }, | |
628 | { | |
629 | "given": { | |
630 | "\b\b": true | |
631 | }, | |
632 | "cases": [ | |
633 | { | |
634 | "expression": "\"\\b\\b\"", | |
635 | "result": true | |
636 | } | |
637 | ] | |
638 | }, | |
639 | { | |
640 | "given": { | |
641 | ">": true | |
642 | }, | |
643 | "cases": [ | |
644 | { | |
645 | "expression": "\">\"", | |
646 | "result": true | |
647 | } | |
648 | ] | |
649 | }, | |
650 | { | |
651 | "given": { | |
652 | "hvu": true | |
653 | }, | |
654 | "cases": [ | |
655 | { | |
656 | "expression": "hvu", | |
657 | "result": true | |
658 | } | |
659 | ] | |
660 | }, | |
661 | { | |
662 | "given": { | |
663 | "; !": true | |
664 | }, | |
665 | "cases": [ | |
666 | { | |
667 | "expression": "\"; !\"", | |
668 | "result": true | |
669 | } | |
670 | ] | |
671 | }, | |
672 | { | |
673 | "given": { | |
674 | "hU": true | |
675 | }, | |
676 | "cases": [ | |
677 | { | |
678 | "expression": "hU", | |
679 | "result": true | |
680 | } | |
681 | ] | |
682 | }, | |
683 | { | |
684 | "given": { | |
685 | "!I\n\/": true | |
686 | }, | |
687 | "cases": [ | |
688 | { | |
689 | "expression": "\"!I\\n\\/\"", | |
690 | "result": true | |
691 | } | |
692 | ] | |
693 | }, | |
694 | { | |
695 | "given": { | |
696 | "\uEEbF": true | |
697 | }, | |
698 | "cases": [ | |
699 | { | |
700 | "expression": "\"\\uEEbF\"", | |
701 | "result": true | |
702 | } | |
703 | ] | |
704 | }, | |
705 | { | |
706 | "given": { | |
707 | "U)\t": true | |
708 | }, | |
709 | "cases": [ | |
710 | { | |
711 | "expression": "\"U)\\t\"", | |
712 | "result": true | |
713 | } | |
714 | ] | |
715 | }, | |
716 | { | |
717 | "given": { | |
718 | "fa0_9": true | |
719 | }, | |
720 | "cases": [ | |
721 | { | |
722 | "expression": "fa0_9", | |
723 | "result": true | |
724 | } | |
725 | ] | |
726 | }, | |
727 | { | |
728 | "given": { | |
729 | "/": true | |
730 | }, | |
731 | "cases": [ | |
732 | { | |
733 | "expression": "\"/\"", | |
734 | "result": true | |
735 | } | |
736 | ] | |
737 | }, | |
738 | { | |
739 | "given": { | |
740 | "Gy": true | |
741 | }, | |
742 | "cases": [ | |
743 | { | |
744 | "expression": "Gy", | |
745 | "result": true | |
746 | } | |
747 | ] | |
748 | }, | |
749 | { | |
750 | "given": { | |
751 | "\b": true | |
752 | }, | |
753 | "cases": [ | |
754 | { | |
755 | "expression": "\"\\b\"", | |
756 | "result": true | |
757 | } | |
758 | ] | |
759 | }, | |
760 | { | |
761 | "given": { | |
762 | "<": true | |
763 | }, | |
764 | "cases": [ | |
765 | { | |
766 | "expression": "\"<\"", | |
767 | "result": true | |
768 | } | |
769 | ] | |
770 | }, | |
771 | { | |
772 | "given": { | |
773 | "\t": true | |
774 | }, | |
775 | "cases": [ | |
776 | { | |
777 | "expression": "\"\\t\"", | |
778 | "result": true | |
779 | } | |
780 | ] | |
781 | }, | |
782 | { | |
783 | "given": { | |
784 | "\t&\\\r": true | |
785 | }, | |
786 | "cases": [ | |
787 | { | |
788 | "expression": "\"\\t&\\\\\\r\"", | |
789 | "result": true | |
790 | } | |
791 | ] | |
792 | }, | |
793 | { | |
794 | "given": { | |
795 | "#": true | |
796 | }, | |
797 | "cases": [ | |
798 | { | |
799 | "expression": "\"#\"", | |
800 | "result": true | |
801 | } | |
802 | ] | |
803 | }, | |
804 | { | |
805 | "given": { | |
806 | "B__": true | |
807 | }, | |
808 | "cases": [ | |
809 | { | |
810 | "expression": "B__", | |
811 | "result": true | |
812 | } | |
813 | ] | |
814 | }, | |
815 | { | |
816 | "given": { | |
817 | "\nS \n": true | |
818 | }, | |
819 | "cases": [ | |
820 | { | |
821 | "expression": "\"\\nS \\n\"", | |
822 | "result": true | |
823 | } | |
824 | ] | |
825 | }, | |
826 | { | |
827 | "given": { | |
828 | "Bp": true | |
829 | }, | |
830 | "cases": [ | |
831 | { | |
832 | "expression": "Bp", | |
833 | "result": true | |
834 | } | |
835 | ] | |
836 | }, | |
837 | { | |
838 | "given": { | |
839 | ",\t;": true | |
840 | }, | |
841 | "cases": [ | |
842 | { | |
843 | "expression": "\",\\t;\"", | |
844 | "result": true | |
845 | } | |
846 | ] | |
847 | }, | |
848 | { | |
849 | "given": { | |
850 | "B_q": true | |
851 | }, | |
852 | "cases": [ | |
853 | { | |
854 | "expression": "B_q", | |
855 | "result": true | |
856 | } | |
857 | ] | |
858 | }, | |
859 | { | |
860 | "given": { | |
861 | "\/+\t\n\b!Z": true | |
862 | }, | |
863 | "cases": [ | |
864 | { | |
865 | "expression": "\"\\/+\\t\\n\\b!Z\"", | |
866 | "result": true | |
867 | } | |
868 | ] | |
869 | }, | |
870 | { | |
871 | "given": { | |
872 | "\udadd\udfc7\\ueFAc": true | |
873 | }, | |
874 | "cases": [ | |
875 | { | |
876 | "expression": "\"\udadd\udfc7\\\\ueFAc\"", | |
877 | "result": true | |
878 | } | |
879 | ] | |
880 | }, | |
881 | { | |
882 | "given": { | |
883 | ":\f": true | |
884 | }, | |
885 | "cases": [ | |
886 | { | |
887 | "expression": "\":\\f\"", | |
888 | "result": true | |
889 | } | |
890 | ] | |
891 | }, | |
892 | { | |
893 | "given": { | |
894 | "\/": true | |
895 | }, | |
896 | "cases": [ | |
897 | { | |
898 | "expression": "\"\\/\"", | |
899 | "result": true | |
900 | } | |
901 | ] | |
902 | }, | |
903 | { | |
904 | "given": { | |
905 | "_BW_6Hg_Gl": true | |
906 | }, | |
907 | "cases": [ | |
908 | { | |
909 | "expression": "_BW_6Hg_Gl", | |
910 | "result": true | |
911 | } | |
912 | ] | |
913 | }, | |
914 | { | |
915 | "given": { | |
916 | "\udbcf\udc02": true | |
917 | }, | |
918 | "cases": [ | |
919 | { | |
920 | "expression": "\"\udbcf\udc02\"", | |
921 | "result": true | |
922 | } | |
923 | ] | |
924 | }, | |
925 | { | |
926 | "given": { | |
927 | "zs1DC": true | |
928 | }, | |
929 | "cases": [ | |
930 | { | |
931 | "expression": "zs1DC", | |
932 | "result": true | |
933 | } | |
934 | ] | |
935 | }, | |
936 | { | |
937 | "given": { | |
938 | "__434": true | |
939 | }, | |
940 | "cases": [ | |
941 | { | |
942 | "expression": "__434", | |
943 | "result": true | |
944 | } | |
945 | ] | |
946 | }, | |
947 | { | |
948 | "given": { | |
949 | "\udb94\udd41": true | |
950 | }, | |
951 | "cases": [ | |
952 | { | |
953 | "expression": "\"\udb94\udd41\"", | |
954 | "result": true | |
955 | } | |
956 | ] | |
957 | }, | |
958 | { | |
959 | "given": { | |
960 | "Z_5": true | |
961 | }, | |
962 | "cases": [ | |
963 | { | |
964 | "expression": "Z_5", | |
965 | "result": true | |
966 | } | |
967 | ] | |
968 | }, | |
969 | { | |
970 | "given": { | |
971 | "z_M_": true | |
972 | }, | |
973 | "cases": [ | |
974 | { | |
975 | "expression": "z_M_", | |
976 | "result": true | |
977 | } | |
978 | ] | |
979 | }, | |
980 | { | |
981 | "given": { | |
982 | "YU_2": true | |
983 | }, | |
984 | "cases": [ | |
985 | { | |
986 | "expression": "YU_2", | |
987 | "result": true | |
988 | } | |
989 | ] | |
990 | }, | |
991 | { | |
992 | "given": { | |
993 | "_0": true | |
994 | }, | |
995 | "cases": [ | |
996 | { | |
997 | "expression": "_0", | |
998 | "result": true | |
999 | } | |
1000 | ] | |
1001 | }, | |
1002 | { | |
1003 | "given": { | |
1004 | "\b+": true | |
1005 | }, | |
1006 | "cases": [ | |
1007 | { | |
1008 | "expression": "\"\\b+\"", | |
1009 | "result": true | |
1010 | } | |
1011 | ] | |
1012 | }, | |
1013 | { | |
1014 | "given": { | |
1015 | "\"": true | |
1016 | }, | |
1017 | "cases": [ | |
1018 | { | |
1019 | "expression": "\"\\\"\"", | |
1020 | "result": true | |
1021 | } | |
1022 | ] | |
1023 | }, | |
1024 | { | |
1025 | "given": { | |
1026 | "D7": true | |
1027 | }, | |
1028 | "cases": [ | |
1029 | { | |
1030 | "expression": "D7", | |
1031 | "result": true | |
1032 | } | |
1033 | ] | |
1034 | }, | |
1035 | { | |
1036 | "given": { | |
1037 | "_62L": true | |
1038 | }, | |
1039 | "cases": [ | |
1040 | { | |
1041 | "expression": "_62L", | |
1042 | "result": true | |
1043 | } | |
1044 | ] | |
1045 | }, | |
1046 | { | |
1047 | "given": { | |
1048 | "\tK\t": true | |
1049 | }, | |
1050 | "cases": [ | |
1051 | { | |
1052 | "expression": "\"\\tK\\t\"", | |
1053 | "result": true | |
1054 | } | |
1055 | ] | |
1056 | }, | |
1057 | { | |
1058 | "given": { | |
1059 | "\n\\\f": true | |
1060 | }, | |
1061 | "cases": [ | |
1062 | { | |
1063 | "expression": "\"\\n\\\\\\f\"", | |
1064 | "result": true | |
1065 | } | |
1066 | ] | |
1067 | }, | |
1068 | { | |
1069 | "given": { | |
1070 | "I_": true | |
1071 | }, | |
1072 | "cases": [ | |
1073 | { | |
1074 | "expression": "I_", | |
1075 | "result": true | |
1076 | } | |
1077 | ] | |
1078 | }, | |
1079 | { | |
1080 | "given": { | |
1081 | "W_a0_": true | |
1082 | }, | |
1083 | "cases": [ | |
1084 | { | |
1085 | "expression": "W_a0_", | |
1086 | "result": true | |
1087 | } | |
1088 | ] | |
1089 | }, | |
1090 | { | |
1091 | "given": { | |
1092 | "BQ": true | |
1093 | }, | |
1094 | "cases": [ | |
1095 | { | |
1096 | "expression": "BQ", | |
1097 | "result": true | |
1098 | } | |
1099 | ] | |
1100 | }, | |
1101 | { | |
1102 | "given": { | |
1103 | "\tX$\uABBb": true | |
1104 | }, | |
1105 | "cases": [ | |
1106 | { | |
1107 | "expression": "\"\\tX$\\uABBb\"", | |
1108 | "result": true | |
1109 | } | |
1110 | ] | |
1111 | }, | |
1112 | { | |
1113 | "given": { | |
1114 | "Z9": true | |
1115 | }, | |
1116 | "cases": [ | |
1117 | { | |
1118 | "expression": "Z9", | |
1119 | "result": true | |
1120 | } | |
1121 | ] | |
1122 | }, | |
1123 | { | |
1124 | "given": { | |
1125 | "\b%\"\uda38\udd0f": true | |
1126 | }, | |
1127 | "cases": [ | |
1128 | { | |
1129 | "expression": "\"\\b%\\\"\uda38\udd0f\"", | |
1130 | "result": true | |
1131 | } | |
1132 | ] | |
1133 | }, | |
1134 | { | |
1135 | "given": { | |
1136 | "_F": true | |
1137 | }, | |
1138 | "cases": [ | |
1139 | { | |
1140 | "expression": "_F", | |
1141 | "result": true | |
1142 | } | |
1143 | ] | |
1144 | }, | |
1145 | { | |
1146 | "given": { | |
1147 | "!,": true | |
1148 | }, | |
1149 | "cases": [ | |
1150 | { | |
1151 | "expression": "\"!,\"", | |
1152 | "result": true | |
1153 | } | |
1154 | ] | |
1155 | }, | |
1156 | { | |
1157 | "given": { | |
1158 | "\"!": true | |
1159 | }, | |
1160 | "cases": [ | |
1161 | { | |
1162 | "expression": "\"\\\"!\"", | |
1163 | "result": true | |
1164 | } | |
1165 | ] | |
1166 | }, | |
1167 | { | |
1168 | "given": { | |
1169 | "Hh": true | |
1170 | }, | |
1171 | "cases": [ | |
1172 | { | |
1173 | "expression": "Hh", | |
1174 | "result": true | |
1175 | } | |
1176 | ] | |
1177 | }, | |
1178 | { | |
1179 | "given": { | |
1180 | "&": true | |
1181 | }, | |
1182 | "cases": [ | |
1183 | { | |
1184 | "expression": "\"&\"", | |
1185 | "result": true | |
1186 | } | |
1187 | ] | |
1188 | }, | |
1189 | { | |
1190 | "given": { | |
1191 | "9\r\\R": true | |
1192 | }, | |
1193 | "cases": [ | |
1194 | { | |
1195 | "expression": "\"9\\r\\\\R\"", | |
1196 | "result": true | |
1197 | } | |
1198 | ] | |
1199 | }, | |
1200 | { | |
1201 | "given": { | |
1202 | "M_k": true | |
1203 | }, | |
1204 | "cases": [ | |
1205 | { | |
1206 | "expression": "M_k", | |
1207 | "result": true | |
1208 | } | |
1209 | ] | |
1210 | }, | |
1211 | { | |
1212 | "given": { | |
1213 | "!\b\n\udb06\ude52\"\"": true | |
1214 | }, | |
1215 | "cases": [ | |
1216 | { | |
1217 | "expression": "\"!\\b\\n\udb06\ude52\\\"\\\"\"", | |
1218 | "result": true | |
1219 | } | |
1220 | ] | |
1221 | }, | |
1222 | { | |
1223 | "given": { | |
1224 | "6": true | |
1225 | }, | |
1226 | "cases": [ | |
1227 | { | |
1228 | "expression": "\"6\"", | |
1229 | "result": true | |
1230 | } | |
1231 | ] | |
1232 | }, | |
1233 | { | |
1234 | "given": { | |
1235 | "_7": true | |
1236 | }, | |
1237 | "cases": [ | |
1238 | { | |
1239 | "expression": "_7", | |
1240 | "result": true | |
1241 | } | |
1242 | ] | |
1243 | }, | |
1244 | { | |
1245 | "given": { | |
1246 | "0": true | |
1247 | }, | |
1248 | "cases": [ | |
1249 | { | |
1250 | "expression": "\"0\"", | |
1251 | "result": true | |
1252 | } | |
1253 | ] | |
1254 | }, | |
1255 | { | |
1256 | "given": { | |
1257 | "\\8\\": true | |
1258 | }, | |
1259 | "cases": [ | |
1260 | { | |
1261 | "expression": "\"\\\\8\\\\\"", | |
1262 | "result": true | |
1263 | } | |
1264 | ] | |
1265 | }, | |
1266 | { | |
1267 | "given": { | |
1268 | "b7eo": true | |
1269 | }, | |
1270 | "cases": [ | |
1271 | { | |
1272 | "expression": "b7eo", | |
1273 | "result": true | |
1274 | } | |
1275 | ] | |
1276 | }, | |
1277 | { | |
1278 | "given": { | |
1279 | "xIUo9": true | |
1280 | }, | |
1281 | "cases": [ | |
1282 | { | |
1283 | "expression": "xIUo9", | |
1284 | "result": true | |
1285 | } | |
1286 | ] | |
1287 | }, | |
1288 | { | |
1289 | "given": { | |
1290 | "5": true | |
1291 | }, | |
1292 | "cases": [ | |
1293 | { | |
1294 | "expression": "\"5\"", | |
1295 | "result": true | |
1296 | } | |
1297 | ] | |
1298 | }, | |
1299 | { | |
1300 | "given": { | |
1301 | "?": true | |
1302 | }, | |
1303 | "cases": [ | |
1304 | { | |
1305 | "expression": "\"?\"", | |
1306 | "result": true | |
1307 | } | |
1308 | ] | |
1309 | }, | |
1310 | { | |
1311 | "given": { | |
1312 | "sU": true | |
1313 | }, | |
1314 | "cases": [ | |
1315 | { | |
1316 | "expression": "sU", | |
1317 | "result": true | |
1318 | } | |
1319 | ] | |
1320 | }, | |
1321 | { | |
1322 | "given": { | |
1323 | "VH2&H\\\/": true | |
1324 | }, | |
1325 | "cases": [ | |
1326 | { | |
1327 | "expression": "\"VH2&H\\\\\\/\"", | |
1328 | "result": true | |
1329 | } | |
1330 | ] | |
1331 | }, | |
1332 | { | |
1333 | "given": { | |
1334 | "_C": true | |
1335 | }, | |
1336 | "cases": [ | |
1337 | { | |
1338 | "expression": "_C", | |
1339 | "result": true | |
1340 | } | |
1341 | ] | |
1342 | }, | |
1343 | { | |
1344 | "given": { | |
1345 | "_": true | |
1346 | }, | |
1347 | "cases": [ | |
1348 | { | |
1349 | "expression": "_", | |
1350 | "result": true | |
1351 | } | |
1352 | ] | |
1353 | }, | |
1354 | { | |
1355 | "given": { | |
1356 | "<\t": true | |
1357 | }, | |
1358 | "cases": [ | |
1359 | { | |
1360 | "expression": "\"<\\t\"", | |
1361 | "result": true | |
1362 | } | |
1363 | ] | |
1364 | }, | |
1365 | { | |
1366 | "given": { | |
1367 | "\uD834\uDD1E": true | |
1368 | }, | |
1369 | "cases": [ | |
1370 | { | |
1371 | "expression": "\"\\uD834\\uDD1E\"", | |
1372 | "result": true | |
1373 | } | |
1374 | ] | |
1375 | } | |
1376 | ] |
0 | [{ | |
1 | "given": | |
2 | {"foo": {"bar": ["zero", "one", "two"]}}, | |
3 | "cases": [ | |
4 | { | |
5 | "expression": "foo.bar[0]", | |
6 | "result": "zero" | |
7 | }, | |
8 | { | |
9 | "expression": "foo.bar[1]", | |
10 | "result": "one" | |
11 | }, | |
12 | { | |
13 | "expression": "foo.bar[2]", | |
14 | "result": "two" | |
15 | }, | |
16 | { | |
17 | "expression": "foo.bar[3]", | |
18 | "result": null | |
19 | }, | |
20 | { | |
21 | "expression": "foo.bar[-1]", | |
22 | "result": "two" | |
23 | }, | |
24 | { | |
25 | "expression": "foo.bar[-2]", | |
26 | "result": "one" | |
27 | }, | |
28 | { | |
29 | "expression": "foo.bar[-3]", | |
30 | "result": "zero" | |
31 | }, | |
32 | { | |
33 | "expression": "foo.bar[-4]", | |
34 | "result": null | |
35 | } | |
36 | ] | |
37 | }, | |
38 | { | |
39 | "given": | |
40 | {"foo": [{"bar": "one"}, {"bar": "two"}, {"bar": "three"}, {"notbar": "four"}]}, | |
41 | "cases": [ | |
42 | { | |
43 | "expression": "foo.bar", | |
44 | "result": null | |
45 | }, | |
46 | { | |
47 | "expression": "foo[0].bar", | |
48 | "result": "one" | |
49 | }, | |
50 | { | |
51 | "expression": "foo[1].bar", | |
52 | "result": "two" | |
53 | }, | |
54 | { | |
55 | "expression": "foo[2].bar", | |
56 | "result": "three" | |
57 | }, | |
58 | { | |
59 | "expression": "foo[3].notbar", | |
60 | "result": "four" | |
61 | }, | |
62 | { | |
63 | "expression": "foo[3].bar", | |
64 | "result": null | |
65 | }, | |
66 | { | |
67 | "expression": "foo[0]", | |
68 | "result": {"bar": "one"} | |
69 | }, | |
70 | { | |
71 | "expression": "foo[1]", | |
72 | "result": {"bar": "two"} | |
73 | }, | |
74 | { | |
75 | "expression": "foo[2]", | |
76 | "result": {"bar": "three"} | |
77 | }, | |
78 | { | |
79 | "expression": "foo[3]", | |
80 | "result": {"notbar": "four"} | |
81 | }, | |
82 | { | |
83 | "expression": "foo[4]", | |
84 | "result": null | |
85 | } | |
86 | ] | |
87 | }, | |
88 | { | |
89 | "given": [ | |
90 | "one", "two", "three" | |
91 | ], | |
92 | "cases": [ | |
93 | { | |
94 | "expression": "[0]", | |
95 | "result": "one" | |
96 | }, | |
97 | { | |
98 | "expression": "[1]", | |
99 | "result": "two" | |
100 | }, | |
101 | { | |
102 | "expression": "[2]", | |
103 | "result": "three" | |
104 | }, | |
105 | { | |
106 | "expression": "[-1]", | |
107 | "result": "three" | |
108 | }, | |
109 | { | |
110 | "expression": "[-2]", | |
111 | "result": "two" | |
112 | }, | |
113 | { | |
114 | "expression": "[-3]", | |
115 | "result": "one" | |
116 | } | |
117 | ] | |
118 | }, | |
119 | { | |
120 | "given": {"reservations": [ | |
121 | {"instances": [{"foo": 1}, {"foo": 2}]} | |
122 | ]}, | |
123 | "cases": [ | |
124 | { | |
125 | "expression": "reservations[].instances[].foo", | |
126 | "result": [1, 2] | |
127 | }, | |
128 | { | |
129 | "expression": "reservations[].instances[].bar", | |
130 | "result": [] | |
131 | }, | |
132 | { | |
133 | "expression": "reservations[].notinstances[].foo", | |
134 | "result": [] | |
135 | }, | |
136 | { | |
137 | "expression": "reservations[].notinstances[].foo", | |
138 | "result": [] | |
139 | } | |
140 | ] | |
141 | }, | |
142 | { | |
143 | "given": {"reservations": [{ | |
144 | "instances": [ | |
145 | {"foo": [{"bar": 1}, {"bar": 2}, {"notbar": 3}, {"bar": 4}]}, | |
146 | {"foo": [{"bar": 5}, {"bar": 6}, {"notbar": [7]}, {"bar": 8}]}, | |
147 | {"foo": "bar"}, | |
148 | {"notfoo": [{"bar": 20}, {"bar": 21}, {"notbar": [7]}, {"bar": 22}]}, | |
149 | {"bar": [{"baz": [1]}, {"baz": [2]}, {"baz": [3]}, {"baz": [4]}]}, | |
150 | {"baz": [{"baz": [1, 2]}, {"baz": []}, {"baz": []}, {"baz": [3, 4]}]}, | |
151 | {"qux": [{"baz": []}, {"baz": [1, 2, 3]}, {"baz": [4]}, {"baz": []}]} | |
152 | ], | |
153 | "otherkey": {"foo": [{"bar": 1}, {"bar": 2}, {"notbar": 3}, {"bar": 4}]} | |
154 | }, { | |
155 | "instances": [ | |
156 | {"a": [{"bar": 1}, {"bar": 2}, {"notbar": 3}, {"bar": 4}]}, | |
157 | {"b": [{"bar": 5}, {"bar": 6}, {"notbar": [7]}, {"bar": 8}]}, | |
158 | {"c": "bar"}, | |
159 | {"notfoo": [{"bar": 23}, {"bar": 24}, {"notbar": [7]}, {"bar": 25}]}, | |
160 | {"qux": [{"baz": []}, {"baz": [1, 2, 3]}, {"baz": [4]}, {"baz": []}]} | |
161 | ], | |
162 | "otherkey": {"foo": [{"bar": 1}, {"bar": 2}, {"notbar": 3}, {"bar": 4}]} | |
163 | } | |
164 | ]}, | |
165 | "cases": [ | |
166 | { | |
167 | "expression": "reservations[].instances[].foo[].bar", | |
168 | "result": [1, 2, 4, 5, 6, 8] | |
169 | }, | |
170 | { | |
171 | "expression": "reservations[].instances[].foo[].baz", | |
172 | "result": [] | |
173 | }, | |
174 | { | |
175 | "expression": "reservations[].instances[].notfoo[].bar", | |
176 | "result": [20, 21, 22, 23, 24, 25] | |
177 | }, | |
178 | { | |
179 | "expression": "reservations[].instances[].notfoo[].notbar", | |
180 | "result": [[7], [7]] | |
181 | }, | |
182 | { | |
183 | "expression": "reservations[].notinstances[].foo", | |
184 | "result": [] | |
185 | }, | |
186 | { | |
187 | "expression": "reservations[].instances[].foo[].notbar", | |
188 | "result": [3, [7]] | |
189 | }, | |
190 | { | |
191 | "expression": "reservations[].instances[].bar[].baz", | |
192 | "result": [[1], [2], [3], [4]] | |
193 | }, | |
194 | { | |
195 | "expression": "reservations[].instances[].baz[].baz", | |
196 | "result": [[1, 2], [], [], [3, 4]] | |
197 | }, | |
198 | { | |
199 | "expression": "reservations[].instances[].qux[].baz", | |
200 | "result": [[], [1, 2, 3], [4], [], [], [1, 2, 3], [4], []] | |
201 | }, | |
202 | { | |
203 | "expression": "reservations[].instances[].qux[].baz[]", | |
204 | "result": [1, 2, 3, 4, 1, 2, 3, 4] | |
205 | } | |
206 | ] | |
207 | }, | |
208 | { | |
209 | "given": { | |
210 | "foo": [ | |
211 | [["one", "two"], ["three", "four"]], | |
212 | [["five", "six"], ["seven", "eight"]], | |
213 | [["nine"], ["ten"]] | |
214 | ] | |
215 | }, | |
216 | "cases": [ | |
217 | { | |
218 | "expression": "foo[]", | |
219 | "result": [["one", "two"], ["three", "four"], ["five", "six"], | |
220 | ["seven", "eight"], ["nine"], ["ten"]] | |
221 | }, | |
222 | { | |
223 | "expression": "foo[][0]", | |
224 | "result": ["one", "three", "five", "seven", "nine", "ten"] | |
225 | }, | |
226 | { | |
227 | "expression": "foo[][1]", | |
228 | "result": ["two", "four", "six", "eight"] | |
229 | }, | |
230 | { | |
231 | "expression": "foo[][0][0]", | |
232 | "result": [] | |
233 | }, | |
234 | { | |
235 | "expression": "foo[][2][2]", | |
236 | "result": [] | |
237 | }, | |
238 | { | |
239 | "expression": "foo[][0][0][100]", | |
240 | "result": [] | |
241 | } | |
242 | ] | |
243 | }, | |
244 | { | |
245 | "given": { | |
246 | "foo": [{ | |
247 | "bar": [ | |
248 | { | |
249 | "qux": 2, | |
250 | "baz": 1 | |
251 | }, | |
252 | { | |
253 | "qux": 4, | |
254 | "baz": 3 | |
255 | } | |
256 | ] | |
257 | }, | |
258 | { | |
259 | "bar": [ | |
260 | { | |
261 | "qux": 6, | |
262 | "baz": 5 | |
263 | }, | |
264 | { | |
265 | "qux": 8, | |
266 | "baz": 7 | |
267 | } | |
268 | ] | |
269 | } | |
270 | ] | |
271 | }, | |
272 | "cases": [ | |
273 | { | |
274 | "expression": "foo", | |
275 | "result": [{"bar": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}]}, | |
276 | {"bar": [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]}] | |
277 | }, | |
278 | { | |
279 | "expression": "foo[]", | |
280 | "result": [{"bar": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}]}, | |
281 | {"bar": [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]}] | |
282 | }, | |
283 | { | |
284 | "expression": "foo[].bar", | |
285 | "result": [[{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}], | |
286 | [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]] | |
287 | }, | |
288 | { | |
289 | "expression": "foo[].bar[]", | |
290 | "result": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}, | |
291 | {"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}] | |
292 | }, | |
293 | { | |
294 | "expression": "foo[].bar[].baz", | |
295 | "result": [1, 3, 5, 7] | |
296 | } | |
297 | ] | |
298 | }, | |
299 | { | |
300 | "given": { | |
301 | "string": "string", | |
302 | "hash": {"foo": "bar", "bar": "baz"}, | |
303 | "number": 23, | |
304 | "nullvalue": null | |
305 | }, | |
306 | "cases": [ | |
307 | { | |
308 | "expression": "string[]", | |
309 | "result": null | |
310 | }, | |
311 | { | |
312 | "expression": "hash[]", | |
313 | "result": null | |
314 | }, | |
315 | { | |
316 | "expression": "number[]", | |
317 | "result": null | |
318 | }, | |
319 | { | |
320 | "expression": "nullvalue[]", | |
321 | "result": null | |
322 | }, | |
323 | { | |
324 | "expression": "string[].foo", | |
325 | "result": null | |
326 | }, | |
327 | { | |
328 | "expression": "hash[].foo", | |
329 | "result": null | |
330 | }, | |
331 | { | |
332 | "expression": "number[].foo", | |
333 | "result": null | |
334 | }, | |
335 | { | |
336 | "expression": "nullvalue[].foo", | |
337 | "result": null | |
338 | }, | |
339 | { | |
340 | "expression": "nullvalue[].foo[].bar", | |
341 | "result": null | |
342 | } | |
343 | ] | |
344 | } | |
345 | ] |
0 | [ | |
1 | { | |
2 | "given": { | |
3 | "foo": [{"name": "a"}, {"name": "b"}], | |
4 | "bar": {"baz": "qux"} | |
5 | }, | |
6 | "cases": [ | |
7 | { | |
8 | "expression": "`\"foo\"`", | |
9 | "result": "foo" | |
10 | }, | |
11 | { | |
12 | "comment": "Interpret escaped unicode.", | |
13 | "expression": "`\"\\u03a6\"`", | |
14 | "result": "Φ" | |
15 | }, | |
16 | { | |
17 | "expression": "`\"✓\"`", | |
18 | "result": "✓" | |
19 | }, | |
20 | { | |
21 | "expression": "`[1, 2, 3]`", | |
22 | "result": [1, 2, 3] | |
23 | }, | |
24 | { | |
25 | "expression": "`{\"a\": \"b\"}`", | |
26 | "result": {"a": "b"} | |
27 | }, | |
28 | { | |
29 | "expression": "`true`", | |
30 | "result": true | |
31 | }, | |
32 | { | |
33 | "expression": "`false`", | |
34 | "result": false | |
35 | }, | |
36 | { | |
37 | "expression": "`null`", | |
38 | "result": null | |
39 | }, | |
40 | { | |
41 | "expression": "`0`", | |
42 | "result": 0 | |
43 | }, | |
44 | { | |
45 | "expression": "`1`", | |
46 | "result": 1 | |
47 | }, | |
48 | { | |
49 | "expression": "`2`", | |
50 | "result": 2 | |
51 | }, | |
52 | { | |
53 | "expression": "`3`", | |
54 | "result": 3 | |
55 | }, | |
56 | { | |
57 | "expression": "`4`", | |
58 | "result": 4 | |
59 | }, | |
60 | { | |
61 | "expression": "`5`", | |
62 | "result": 5 | |
63 | }, | |
64 | { | |
65 | "expression": "`6`", | |
66 | "result": 6 | |
67 | }, | |
68 | { | |
69 | "expression": "`7`", | |
70 | "result": 7 | |
71 | }, | |
72 | { | |
73 | "expression": "`8`", | |
74 | "result": 8 | |
75 | }, | |
76 | { | |
77 | "expression": "`9`", | |
78 | "result": 9 | |
79 | }, | |
80 | { | |
81 | "comment": "Escaping a backtick in quotes", | |
82 | "expression": "`\"foo\\`bar\"`", | |
83 | "result": "foo`bar" | |
84 | }, | |
85 | { | |
86 | "comment": "Double quote in literal", | |
87 | "expression": "`\"foo\\\"bar\"`", | |
88 | "result": "foo\"bar" | |
89 | }, | |
90 | { | |
91 | "expression": "`\"1\\`\"`", | |
92 | "result": "1`" | |
93 | }, | |
94 | { | |
95 | "comment": "Multiple literal expressions with escapes", | |
96 | "expression": "`\"\\\\\"`.{a:`\"b\"`}", | |
97 | "result": {"a": "b"} | |
98 | }, | |
99 | { | |
100 | "comment": "literal . identifier", | |
101 | "expression": "`{\"a\": \"b\"}`.a", | |
102 | "result": "b" | |
103 | }, | |
104 | { | |
105 | "comment": "literal . identifier . identifier", | |
106 | "expression": "`{\"a\": {\"b\": \"c\"}}`.a.b", | |
107 | "result": "c" | |
108 | }, | |
109 | { | |
110 | "comment": "literal . identifier bracket-expr", | |
111 | "expression": "`[0, 1, 2]`[1]", | |
112 | "result": 1 | |
113 | } | |
114 | ] | |
115 | }, | |
116 | { | |
117 | "comment": "Literals", | |
118 | "given": {"type": "object"}, | |
119 | "cases": [ | |
120 | { | |
121 | "comment": "Literal with leading whitespace", | |
122 | "expression": "` {\"foo\": true}`", | |
123 | "result": {"foo": true} | |
124 | }, | |
125 | { | |
126 | "comment": "Literal with trailing whitespace", | |
127 | "expression": "`{\"foo\": true} `", | |
128 | "result": {"foo": true} | |
129 | }, | |
130 | { | |
131 | "comment": "Literal on RHS of subexpr not allowed", | |
132 | "expression": "foo.`\"bar\"`", | |
133 | "error": "syntax" | |
134 | } | |
135 | ] | |
136 | }, | |
137 | { | |
138 | "comment": "Raw String Literals", | |
139 | "given": {}, | |
140 | "cases": [ | |
141 | { | |
142 | "expression": "'foo'", | |
143 | "result": "foo" | |
144 | }, | |
145 | { | |
146 | "expression": "' foo '", | |
147 | "result": " foo " | |
148 | }, | |
149 | { | |
150 | "expression": "'0'", | |
151 | "result": "0" | |
152 | }, | |
153 | { | |
154 | "expression": "'newline\n'", | |
155 | "result": "newline\n" | |
156 | }, | |
157 | { | |
158 | "expression": "'\n'", | |
159 | "result": "\n" | |
160 | }, | |
161 | { | |
162 | "expression": "'✓'", | |
163 | "result": "✓" | |
164 | }, | |
165 | { | |
166 | "expression": "'𝄞'", | |
167 | "result": "𝄞" | |
168 | }, | |
169 | { | |
170 | "expression": "' [foo] '", | |
171 | "result": " [foo] " | |
172 | }, | |
173 | { | |
174 | "expression": "'[foo]'", | |
175 | "result": "[foo]" | |
176 | }, | |
177 | { | |
178 | "comment": "Do not interpret escaped unicode.", | |
179 | "expression": "'\\u03a6'", | |
180 | "result": "\\u03a6" | |
181 | }, | |
182 | { | |
183 | "comment": "Can escape the single quote", | |
184 | "expression": "'foo\\'bar'", | |
185 | "result": "foo'bar" | |
186 | } | |
187 | ] | |
188 | } | |
189 | ] |
0 | [{ | |
1 | "given": { | |
2 | "foo": { | |
3 | "bar": "bar", | |
4 | "baz": "baz", | |
5 | "qux": "qux", | |
6 | "nested": { | |
7 | "one": { | |
8 | "a": "first", | |
9 | "b": "second", | |
10 | "c": "third" | |
11 | }, | |
12 | "two": { | |
13 | "a": "first", | |
14 | "b": "second", | |
15 | "c": "third" | |
16 | }, | |
17 | "three": { | |
18 | "a": "first", | |
19 | "b": "second", | |
20 | "c": {"inner": "third"} | |
21 | } | |
22 | } | |
23 | }, | |
24 | "bar": 1, | |
25 | "baz": 2, | |
26 | "qux\"": 3 | |
27 | }, | |
28 | "cases": [ | |
29 | { | |
30 | "expression": "foo.{bar: bar}", | |
31 | "result": {"bar": "bar"} | |
32 | }, | |
33 | { | |
34 | "expression": "foo.{\"bar\": bar}", | |
35 | "result": {"bar": "bar"} | |
36 | }, | |
37 | { | |
38 | "expression": "foo.{\"foo.bar\": bar}", | |
39 | "result": {"foo.bar": "bar"} | |
40 | }, | |
41 | { | |
42 | "expression": "foo.{bar: bar, baz: baz}", | |
43 | "result": {"bar": "bar", "baz": "baz"} | |
44 | }, | |
45 | { | |
46 | "expression": "foo.{\"bar\": bar, \"baz\": baz}", | |
47 | "result": {"bar": "bar", "baz": "baz"} | |
48 | }, | |
49 | { | |
50 | "expression": "{\"baz\": baz, \"qux\\\"\": \"qux\\\"\"}", | |
51 | "result": {"baz": 2, "qux\"": 3} | |
52 | }, | |
53 | { | |
54 | "expression": "foo.{bar:bar,baz:baz}", | |
55 | "result": {"bar": "bar", "baz": "baz"} | |
56 | }, | |
57 | { | |
58 | "expression": "foo.{bar: bar,qux: qux}", | |
59 | "result": {"bar": "bar", "qux": "qux"} | |
60 | }, | |
61 | { | |
62 | "expression": "foo.{bar: bar, noexist: noexist}", | |
63 | "result": {"bar": "bar", "noexist": null} | |
64 | }, | |
65 | { | |
66 | "expression": "foo.{noexist: noexist, alsonoexist: alsonoexist}", | |
67 | "result": {"noexist": null, "alsonoexist": null} | |
68 | }, | |
69 | { | |
70 | "expression": "foo.badkey.{nokey: nokey, alsonokey: alsonokey}", | |
71 | "result": null | |
72 | }, | |
73 | { | |
74 | "expression": "foo.nested.*.{a: a,b: b}", | |
75 | "result": [{"a": "first", "b": "second"}, | |
76 | {"a": "first", "b": "second"}, | |
77 | {"a": "first", "b": "second"}] | |
78 | }, | |
79 | { | |
80 | "expression": "foo.nested.three.{a: a, cinner: c.inner}", | |
81 | "result": {"a": "first", "cinner": "third"} | |
82 | }, | |
83 | { | |
84 | "expression": "foo.nested.three.{a: a, c: c.inner.bad.key}", | |
85 | "result": {"a": "first", "c": null} | |
86 | }, | |
87 | { | |
88 | "expression": "foo.{a: nested.one.a, b: nested.two.b}", | |
89 | "result": {"a": "first", "b": "second"} | |
90 | }, | |
91 | { | |
92 | "expression": "{bar: bar, baz: baz}", | |
93 | "result": {"bar": 1, "baz": 2} | |
94 | }, | |
95 | { | |
96 | "expression": "{bar: bar}", | |
97 | "result": {"bar": 1} | |
98 | }, | |
99 | { | |
100 | "expression": "{otherkey: bar}", | |
101 | "result": {"otherkey": 1} | |
102 | }, | |
103 | { | |
104 | "expression": "{no: no, exist: exist}", | |
105 | "result": {"no": null, "exist": null} | |
106 | }, | |
107 | { | |
108 | "expression": "foo.[bar]", | |
109 | "result": ["bar"] | |
110 | }, | |
111 | { | |
112 | "expression": "foo.[bar,baz]", | |
113 | "result": ["bar", "baz"] | |
114 | }, | |
115 | { | |
116 | "expression": "foo.[bar,qux]", | |
117 | "result": ["bar", "qux"] | |
118 | }, | |
119 | { | |
120 | "expression": "foo.[bar,noexist]", | |
121 | "result": ["bar", null] | |
122 | }, | |
123 | { | |
124 | "expression": "foo.[noexist,alsonoexist]", | |
125 | "result": [null, null] | |
126 | } | |
127 | ] | |
128 | }, { | |
129 | "given": { | |
130 | "foo": {"bar": 1, "baz": [2, 3, 4]} | |
131 | }, | |
132 | "cases": [ | |
133 | { | |
134 | "expression": "foo.{bar:bar,baz:baz}", | |
135 | "result": {"bar": 1, "baz": [2, 3, 4]} | |
136 | }, | |
137 | { | |
138 | "expression": "foo.[bar,baz[0]]", | |
139 | "result": [1, 2] | |
140 | }, | |
141 | { | |
142 | "expression": "foo.[bar,baz[1]]", | |
143 | "result": [1, 3] | |
144 | }, | |
145 | { | |
146 | "expression": "foo.[bar,baz[2]]", | |
147 | "result": [1, 4] | |
148 | }, | |
149 | { | |
150 | "expression": "foo.[bar,baz[3]]", | |
151 | "result": [1, null] | |
152 | }, | |
153 | { | |
154 | "expression": "foo.[bar[0],baz[3]]", | |
155 | "result": [null, null] | |
156 | } | |
157 | ] | |
158 | }, { | |
159 | "given": { | |
160 | "foo": {"bar": 1, "baz": 2} | |
161 | }, | |
162 | "cases": [ | |
163 | { | |
164 | "expression": "foo.{bar: bar, baz: baz}", | |
165 | "result": {"bar": 1, "baz": 2} | |
166 | }, | |
167 | { | |
168 | "expression": "foo.[bar,baz]", | |
169 | "result": [1, 2] | |
170 | } | |
171 | ] | |
172 | }, { | |
173 | "given": { | |
174 | "foo": { | |
175 | "bar": {"baz": [{"common": "first", "one": 1}, | |
176 | {"common": "second", "two": 2}]}, | |
177 | "ignoreme": 1, | |
178 | "includeme": true | |
179 | } | |
180 | }, | |
181 | "cases": [ | |
182 | { | |
183 | "expression": "foo.{bar: bar.baz[1],includeme: includeme}", | |
184 | "result": {"bar": {"common": "second", "two": 2}, "includeme": true} | |
185 | }, | |
186 | { | |
187 | "expression": "foo.{\"bar.baz.two\": bar.baz[1].two, includeme: includeme}", | |
188 | "result": {"bar.baz.two": 2, "includeme": true} | |
189 | }, | |
190 | { | |
191 | "expression": "foo.[includeme, bar.baz[*].common]", | |
192 | "result": [true, ["first", "second"]] | |
193 | }, | |
194 | { | |
195 | "expression": "foo.[includeme, bar.baz[*].none]", | |
196 | "result": [true, []] | |
197 | }, | |
198 | { | |
199 | "expression": "foo.[includeme, bar.baz[].common]", | |
200 | "result": [true, ["first", "second"]] | |
201 | } | |
202 | ] | |
203 | }, { | |
204 | "given": { | |
205 | "reservations": [{ | |
206 | "instances": [ | |
207 | {"id": "id1", | |
208 | "name": "first"}, | |
209 | {"id": "id2", | |
210 | "name": "second"} | |
211 | ]}, { | |
212 | "instances": [ | |
213 | {"id": "id3", | |
214 | "name": "third"}, | |
215 | {"id": "id4", | |
216 | "name": "fourth"} | |
217 | ]} | |
218 | ]}, | |
219 | "cases": [ | |
220 | { | |
221 | "expression": "reservations[*].instances[*].{id: id, name: name}", | |
222 | "result": [[{"id": "id1", "name": "first"}, {"id": "id2", "name": "second"}], | |
223 | [{"id": "id3", "name": "third"}, {"id": "id4", "name": "fourth"}]] | |
224 | }, | |
225 | { | |
226 | "expression": "reservations[].instances[].{id: id, name: name}", | |
227 | "result": [{"id": "id1", "name": "first"}, | |
228 | {"id": "id2", "name": "second"}, | |
229 | {"id": "id3", "name": "third"}, | |
230 | {"id": "id4", "name": "fourth"}] | |
231 | }, | |
232 | { | |
233 | "expression": "reservations[].instances[].[id, name]", | |
234 | "result": [["id1", "first"], | |
235 | ["id2", "second"], | |
236 | ["id3", "third"], | |
237 | ["id4", "fourth"]] | |
238 | } | |
239 | ] | |
240 | }, | |
241 | { | |
242 | "given": { | |
243 | "foo": [{ | |
244 | "bar": [ | |
245 | { | |
246 | "qux": 2, | |
247 | "baz": 1 | |
248 | }, | |
249 | { | |
250 | "qux": 4, | |
251 | "baz": 3 | |
252 | } | |
253 | ] | |
254 | }, | |
255 | { | |
256 | "bar": [ | |
257 | { | |
258 | "qux": 6, | |
259 | "baz": 5 | |
260 | }, | |
261 | { | |
262 | "qux": 8, | |
263 | "baz": 7 | |
264 | } | |
265 | ] | |
266 | } | |
267 | ] | |
268 | }, | |
269 | "cases": [ | |
270 | { | |
271 | "expression": "foo", | |
272 | "result": [{"bar": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}]}, | |
273 | {"bar": [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]}] | |
274 | }, | |
275 | { | |
276 | "expression": "foo[]", | |
277 | "result": [{"bar": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}]}, | |
278 | {"bar": [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]}] | |
279 | }, | |
280 | { | |
281 | "expression": "foo[].bar", | |
282 | "result": [[{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}], | |
283 | [{"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}]] | |
284 | }, | |
285 | { | |
286 | "expression": "foo[].bar[]", | |
287 | "result": [{"qux": 2, "baz": 1}, {"qux": 4, "baz": 3}, | |
288 | {"qux": 6, "baz": 5}, {"qux": 8, "baz": 7}] | |
289 | }, | |
290 | { | |
291 | "expression": "foo[].bar[].[baz, qux]", | |
292 | "result": [[1, 2], [3, 4], [5, 6], [7, 8]] | |
293 | }, | |
294 | { | |
295 | "expression": "foo[].bar[].[baz]", | |
296 | "result": [[1], [3], [5], [7]] | |
297 | }, | |
298 | { | |
299 | "expression": "foo[].bar[].[baz, qux][]", | |
300 | "result": [1, 2, 3, 4, 5, 6, 7, 8] | |
301 | } | |
302 | ] | |
303 | }, | |
304 | { | |
305 | "given": { | |
306 | "foo": { | |
307 | "baz": [ | |
308 | { | |
309 | "bar": "abc" | |
310 | }, { | |
311 | "bar": "def" | |
312 | } | |
313 | ], | |
314 | "qux": ["zero"] | |
315 | } | |
316 | }, | |
317 | "cases": [ | |
318 | { | |
319 | "expression": "foo.[baz[*].bar, qux[0]]", | |
320 | "result": [["abc", "def"], "zero"] | |
321 | } | |
322 | ] | |
323 | }, | |
324 | { | |
325 | "given": { | |
326 | "foo": { | |
327 | "baz": [ | |
328 | { | |
329 | "bar": "a", | |
330 | "bam": "b", | |
331 | "boo": "c" | |
332 | }, { | |
333 | "bar": "d", | |
334 | "bam": "e", | |
335 | "boo": "f" | |
336 | } | |
337 | ], | |
338 | "qux": ["zero"] | |
339 | } | |
340 | }, | |
341 | "cases": [ | |
342 | { | |
343 | "expression": "foo.[baz[*].[bar, boo], qux[0]]", | |
344 | "result": [[["a", "c" ], ["d", "f" ]], "zero"] | |
345 | } | |
346 | ] | |
347 | }, | |
348 | { | |
349 | "given": { | |
350 | "foo": { | |
351 | "baz": [ | |
352 | { | |
353 | "bar": "a", | |
354 | "bam": "b", | |
355 | "boo": "c" | |
356 | }, { | |
357 | "bar": "d", | |
358 | "bam": "e", | |
359 | "boo": "f" | |
360 | } | |
361 | ], | |
362 | "qux": ["zero"] | |
363 | } | |
364 | }, | |
365 | "cases": [ | |
366 | { | |
367 | "expression": "foo.[baz[*].not_there || baz[*].bar, qux[0]]", | |
368 | "result": [["a", "d"], "zero"] | |
369 | } | |
370 | ] | |
371 | }, | |
372 | { | |
373 | "given": {"type": "object"}, | |
374 | "cases": [ | |
375 | { | |
376 | "comment": "Nested multiselect", | |
377 | "expression": "[[*],*]", | |
378 | "result": [null, ["object"]] | |
379 | } | |
380 | ] | |
381 | }, | |
382 | { | |
383 | "given": [], | |
384 | "cases": [ | |
385 | { | |
386 | "comment": "Nested multiselect", | |
387 | "expression": "[[*]]", | |
388 | "result": [[]] | |
389 | } | |
390 | ] | |
391 | } | |
392 | ] |
0 | [{ | |
1 | "given": { | |
2 | "foo": { | |
3 | "bar": { | |
4 | "baz": "subkey" | |
5 | }, | |
6 | "other": { | |
7 | "baz": "subkey" | |
8 | }, | |
9 | "other2": { | |
10 | "baz": "subkey" | |
11 | }, | |
12 | "other3": { | |
13 | "notbaz": ["a", "b", "c"] | |
14 | }, | |
15 | "other4": { | |
16 | "notbaz": ["a", "b", "c"] | |
17 | } | |
18 | } | |
19 | }, | |
20 | "cases": [ | |
21 | { | |
22 | "expression": "foo.*.baz | [0]", | |
23 | "result": "subkey" | |
24 | }, | |
25 | { | |
26 | "expression": "foo.*.baz | [1]", | |
27 | "result": "subkey" | |
28 | }, | |
29 | { | |
30 | "expression": "foo.*.baz | [2]", | |
31 | "result": "subkey" | |
32 | }, | |
33 | { | |
34 | "expression": "foo.bar.* | [0]", | |
35 | "result": "subkey" | |
36 | }, | |
37 | { | |
38 | "expression": "foo.*.notbaz | [*]", | |
39 | "result": [["a", "b", "c"], ["a", "b", "c"]] | |
40 | }, | |
41 | { | |
42 | "expression": "{\"a\": foo.bar, \"b\": foo.other} | *.baz", | |
43 | "result": ["subkey", "subkey"] | |
44 | } | |
45 | ] | |
46 | }, { | |
47 | "given": { | |
48 | "foo": { | |
49 | "bar": { | |
50 | "baz": "one" | |
51 | }, | |
52 | "other": { | |
53 | "baz": "two" | |
54 | }, | |
55 | "other2": { | |
56 | "baz": "three" | |
57 | }, | |
58 | "other3": { | |
59 | "notbaz": ["a", "b", "c"] | |
60 | }, | |
61 | "other4": { | |
62 | "notbaz": ["d", "e", "f"] | |
63 | } | |
64 | } | |
65 | }, | |
66 | "cases": [ | |
67 | { | |
68 | "expression": "foo | bar", | |
69 | "result": {"baz": "one"} | |
70 | }, | |
71 | { | |
72 | "expression": "foo | bar | baz", | |
73 | "result": "one" | |
74 | }, | |
75 | { | |
76 | "expression": "foo|bar| baz", | |
77 | "result": "one" | |
78 | }, | |
79 | { | |
80 | "expression": "not_there | [0]", | |
81 | "result": null | |
82 | }, | |
83 | { | |
84 | "expression": "not_there | [0]", | |
85 | "result": null | |
86 | }, | |
87 | { | |
88 | "expression": "[foo.bar, foo.other] | [0]", | |
89 | "result": {"baz": "one"} | |
90 | }, | |
91 | { | |
92 | "expression": "{\"a\": foo.bar, \"b\": foo.other} | a", | |
93 | "result": {"baz": "one"} | |
94 | }, | |
95 | { | |
96 | "expression": "{\"a\": foo.bar, \"b\": foo.other} | b", | |
97 | "result": {"baz": "two"} | |
98 | }, | |
99 | { | |
100 | "expression": "foo.bam || foo.bar | baz", | |
101 | "result": "one" | |
102 | }, | |
103 | { | |
104 | "expression": "foo | not_there || bar", | |
105 | "result": {"baz": "one"} | |
106 | } | |
107 | ] | |
108 | }, { | |
109 | "given": { | |
110 | "foo": [{ | |
111 | "bar": [{ | |
112 | "baz": "one" | |
113 | }, { | |
114 | "baz": "two" | |
115 | }] | |
116 | }, { | |
117 | "bar": [{ | |
118 | "baz": "three" | |
119 | }, { | |
120 | "baz": "four" | |
121 | }] | |
122 | }] | |
123 | }, | |
124 | "cases": [ | |
125 | { | |
126 | "expression": "foo[*].bar[*] | [0][0]", | |
127 | "result": {"baz": "one"} | |
128 | } | |
129 | ] | |
130 | }] |
0 | [{ | |
1 | "given": { | |
2 | "foo": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], | |
3 | "bar": { | |
4 | "baz": 1 | |
5 | } | |
6 | }, | |
7 | "cases": [ | |
8 | { | |
9 | "expression": "bar[0:10]", | |
10 | "result": null | |
11 | }, | |
12 | { | |
13 | "expression": "foo[0:10:1]", | |
14 | "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |
15 | }, | |
16 | { | |
17 | "expression": "foo[0:10]", | |
18 | "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |
19 | }, | |
20 | { | |
21 | "expression": "foo[0:10:]", | |
22 | "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |
23 | }, | |
24 | { | |
25 | "expression": "foo[0::1]", | |
26 | "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |
27 | }, | |
28 | { | |
29 | "expression": "foo[0::]", | |
30 | "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |
31 | }, | |
32 | { | |
33 | "expression": "foo[0:]", | |
34 | "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |
35 | }, | |
36 | { | |
37 | "expression": "foo[:10:1]", | |
38 | "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |
39 | }, | |
40 | { | |
41 | "expression": "foo[::1]", | |
42 | "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |
43 | }, | |
44 | { | |
45 | "expression": "foo[:10:]", | |
46 | "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |
47 | }, | |
48 | { | |
49 | "expression": "foo[::]", | |
50 | "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |
51 | }, | |
52 | { | |
53 | "expression": "foo[:]", | |
54 | "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |
55 | }, | |
56 | { | |
57 | "expression": "foo[1:9]", | |
58 | "result": [1, 2, 3, 4, 5, 6, 7, 8] | |
59 | }, | |
60 | { | |
61 | "expression": "foo[0:10:2]", | |
62 | "result": [0, 2, 4, 6, 8] | |
63 | }, | |
64 | { | |
65 | "expression": "foo[5:]", | |
66 | "result": [5, 6, 7, 8, 9] | |
67 | }, | |
68 | { | |
69 | "expression": "foo[5::2]", | |
70 | "result": [5, 7, 9] | |
71 | }, | |
72 | { | |
73 | "expression": "foo[::2]", | |
74 | "result": [0, 2, 4, 6, 8] | |
75 | }, | |
76 | { | |
77 | "expression": "foo[::-1]", | |
78 | "result": [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] | |
79 | }, | |
80 | { | |
81 | "expression": "foo[1::2]", | |
82 | "result": [1, 3, 5, 7, 9] | |
83 | }, | |
84 | { | |
85 | "expression": "foo[10:0:-1]", | |
86 | "result": [9, 8, 7, 6, 5, 4, 3, 2, 1] | |
87 | }, | |
88 | { | |
89 | "expression": "foo[10:5:-1]", | |
90 | "result": [9, 8, 7, 6] | |
91 | }, | |
92 | { | |
93 | "expression": "foo[8:2:-2]", | |
94 | "result": [8, 6, 4] | |
95 | }, | |
96 | { | |
97 | "expression": "foo[0:20]", | |
98 | "result": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] | |
99 | }, | |
100 | { | |
101 | "expression": "foo[10:-20:-1]", | |
102 | "result": [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] | |
103 | }, | |
104 | { | |
105 | "expression": "foo[10:-20]", | |
106 | "result": [] | |
107 | }, | |
108 | { | |
109 | "expression": "foo[-4:-1]", | |
110 | "result": [6, 7, 8] | |
111 | }, | |
112 | { | |
113 | "expression": "foo[:-5:-1]", | |
114 | "result": [9, 8, 7, 6] | |
115 | }, | |
116 | { | |
117 | "expression": "foo[8:2:0]", | |
118 | "error": "invalid-value" | |
119 | }, | |
120 | { | |
121 | "expression": "foo[8:2:0:1]", | |
122 | "error": "syntax" | |
123 | }, | |
124 | { | |
125 | "expression": "foo[8:2&]", | |
126 | "error": "syntax" | |
127 | }, | |
128 | { | |
129 | "expression": "foo[2:a:3]", | |
130 | "error": "syntax" | |
131 | } | |
132 | ] | |
133 | }, { | |
134 | "given": { | |
135 | "foo": [{"a": 1}, {"a": 2}, {"a": 3}], | |
136 | "bar": [{"a": {"b": 1}}, {"a": {"b": 2}}, | |
137 | {"a": {"b": 3}}], | |
138 | "baz": 50 | |
139 | }, | |
140 | "cases": [ | |
141 | { | |
142 | "expression": "foo[:2].a", | |
143 | "result": [1, 2] | |
144 | }, | |
145 | { | |
146 | "expression": "foo[:2].b", | |
147 | "result": [] | |
148 | }, | |
149 | { | |
150 | "expression": "foo[:2].a.b", | |
151 | "result": [] | |
152 | }, | |
153 | { | |
154 | "expression": "bar[::-1].a.b", | |
155 | "result": [3, 2, 1] | |
156 | }, | |
157 | { | |
158 | "expression": "bar[:2].a.b", | |
159 | "result": [1, 2] | |
160 | }, | |
161 | { | |
162 | "expression": "baz[:2].a", | |
163 | "result": null | |
164 | } | |
165 | ] | |
166 | }, { | |
167 | "given": [{"a": 1}, {"a": 2}, {"a": 3}], | |
168 | "cases": [ | |
169 | { | |
170 | "expression": "[:]", | |
171 | "result": [{"a": 1}, {"a": 2}, {"a": 3}] | |
172 | }, | |
173 | { | |
174 | "expression": "[:2].a", | |
175 | "result": [1, 2] | |
176 | }, | |
177 | { | |
178 | "expression": "[::-1].a", | |
179 | "result": [3, 2, 1] | |
180 | }, | |
181 | { | |
182 | "expression": "[:2].b", | |
183 | "result": [] | |
184 | } | |
185 | ] | |
186 | }] |
0 | [{ | |
1 | "comment": "Dot syntax", | |
2 | "given": {"type": "object"}, | |
3 | "cases": [ | |
4 | { | |
5 | "expression": "foo.bar", | |
6 | "result": null | |
7 | }, | |
8 | { | |
9 | "expression": "foo.1", | |
10 | "error": "syntax" | |
11 | }, | |
12 | { | |
13 | "expression": "foo.-11", | |
14 | "error": "syntax" | |
15 | }, | |
16 | { | |
17 | "expression": "foo", | |
18 | "result": null | |
19 | }, | |
20 | { | |
21 | "expression": "foo.", | |
22 | "error": "syntax" | |
23 | }, | |
24 | { | |
25 | "expression": "foo.", | |
26 | "error": "syntax" | |
27 | }, | |
28 | { | |
29 | "expression": ".foo", | |
30 | "error": "syntax" | |
31 | }, | |
32 | { | |
33 | "expression": "foo..bar", | |
34 | "error": "syntax" | |
35 | }, | |
36 | { | |
37 | "expression": "foo.bar.", | |
38 | "error": "syntax" | |
39 | }, | |
40 | { | |
41 | "expression": "foo[.]", | |
42 | "error": "syntax" | |
43 | } | |
44 | ] | |
45 | }, | |
46 | { | |
47 | "comment": "Simple token errors", | |
48 | "given": {"type": "object"}, | |
49 | "cases": [ | |
50 | { | |
51 | "expression": ".", | |
52 | "error": "syntax" | |
53 | }, | |
54 | { | |
55 | "expression": ":", | |
56 | "error": "syntax" | |
57 | }, | |
58 | { | |
59 | "expression": ",", | |
60 | "error": "syntax" | |
61 | }, | |
62 | { | |
63 | "expression": "]", | |
64 | "error": "syntax" | |
65 | }, | |
66 | { | |
67 | "expression": "[", | |
68 | "error": "syntax" | |
69 | }, | |
70 | { | |
71 | "expression": "}", | |
72 | "error": "syntax" | |
73 | }, | |
74 | { | |
75 | "expression": "{", | |
76 | "error": "syntax" | |
77 | }, | |
78 | { | |
79 | "expression": ")", | |
80 | "error": "syntax" | |
81 | }, | |
82 | { | |
83 | "expression": "(", | |
84 | "error": "syntax" | |
85 | }, | |
86 | { | |
87 | "expression": "((&", | |
88 | "error": "syntax" | |
89 | }, | |
90 | { | |
91 | "expression": "a[", | |
92 | "error": "syntax" | |
93 | }, | |
94 | { | |
95 | "expression": "a]", | |
96 | "error": "syntax" | |
97 | }, | |
98 | { | |
99 | "expression": "a][", | |
100 | "error": "syntax" | |
101 | }, | |
102 | { | |
103 | "expression": "!", | |
104 | "error": "syntax" | |
105 | } | |
106 | ] | |
107 | }, | |
108 | { | |
109 | "comment": "Boolean syntax errors", | |
110 | "given": {"type": "object"}, | |
111 | "cases": [ | |
112 | { | |
113 | "expression": "![!(!", | |
114 | "error": "syntax" | |
115 | } | |
116 | ] | |
117 | }, | |
118 | { | |
119 | "comment": "Wildcard syntax", | |
120 | "given": {"type": "object"}, | |
121 | "cases": [ | |
122 | { | |
123 | "expression": "*", | |
124 | "result": ["object"] | |
125 | }, | |
126 | { | |
127 | "expression": "*.*", | |
128 | "result": [] | |
129 | }, | |
130 | { | |
131 | "expression": "*.foo", | |
132 | "result": [] | |
133 | }, | |
134 | { | |
135 | "expression": "*[0]", | |
136 | "result": [] | |
137 | }, | |
138 | { | |
139 | "expression": ".*", | |
140 | "error": "syntax" | |
141 | }, | |
142 | { | |
143 | "expression": "*foo", | |
144 | "error": "syntax" | |
145 | }, | |
146 | { | |
147 | "expression": "*0", | |
148 | "error": "syntax" | |
149 | }, | |
150 | { | |
151 | "expression": "foo[*]bar", | |
152 | "error": "syntax" | |
153 | }, | |
154 | { | |
155 | "expression": "foo[*]*", | |
156 | "error": "syntax" | |
157 | } | |
158 | ] | |
159 | }, | |
160 | { | |
161 | "comment": "Flatten syntax", | |
162 | "given": {"type": "object"}, | |
163 | "cases": [ | |
164 | { | |
165 | "expression": "[]", | |
166 | "result": null | |
167 | } | |
168 | ] | |
169 | }, | |
170 | { | |
171 | "comment": "Simple bracket syntax", | |
172 | "given": {"type": "object"}, | |
173 | "cases": [ | |
174 | { | |
175 | "expression": "[0]", | |
176 | "result": null | |
177 | }, | |
178 | { | |
179 | "expression": "[*]", | |
180 | "result": null | |
181 | }, | |
182 | { | |
183 | "expression": "*.[0]", | |
184 | "error": "syntax" | |
185 | }, | |
186 | { | |
187 | "expression": "*.[\"0\"]", | |
188 | "result": [[null]] | |
189 | }, | |
190 | { | |
191 | "expression": "[*].bar", | |
192 | "result": null | |
193 | }, | |
194 | { | |
195 | "expression": "[*][0]", | |
196 | "result": null | |
197 | }, | |
198 | { | |
199 | "expression": "foo[#]", | |
200 | "error": "syntax" | |
201 | } | |
202 | ] | |
203 | }, | |
204 | { | |
205 | "comment": "Multi-select list syntax", | |
206 | "given": {"type": "object"}, | |
207 | "cases": [ | |
208 | { | |
209 | "expression": "foo[0]", | |
210 | "result": null | |
211 | }, | |
212 | { | |
213 | "comment": "Valid multi-select of a list", | |
214 | "expression": "foo[0, 1]", | |
215 | "error": "syntax" | |
216 | }, | |
217 | { | |
218 | "expression": "foo.[0]", | |
219 | "error": "syntax" | |
220 | }, | |
221 | { | |
222 | "expression": "foo.[*]", | |
223 | "result": null | |
224 | }, | |
225 | { | |
226 | "comment": "Multi-select of a list with trailing comma", | |
227 | "expression": "foo[0, ]", | |
228 | "error": "syntax" | |
229 | }, | |
230 | { | |
231 | "comment": "Multi-select of a list with trailing comma and no close", | |
232 | "expression": "foo[0,", | |
233 | "error": "syntax" | |
234 | }, | |
235 | { | |
236 | "comment": "Multi-select of a list with trailing comma and no close", | |
237 | "expression": "foo.[a", | |
238 | "error": "syntax" | |
239 | }, | |
240 | { | |
241 | "comment": "Multi-select of a list with extra comma", | |
242 | "expression": "foo[0,, 1]", | |
243 | "error": "syntax" | |
244 | }, | |
245 | { | |
246 | "comment": "Multi-select of a list using an identifier index", | |
247 | "expression": "foo[abc]", | |
248 | "error": "syntax" | |
249 | }, | |
250 | { | |
251 | "comment": "Multi-select of a list using identifier indices", | |
252 | "expression": "foo[abc, def]", | |
253 | "error": "syntax" | |
254 | }, | |
255 | { | |
256 | "comment": "Multi-select of a list using an identifier index", | |
257 | "expression": "foo[abc, 1]", | |
258 | "error": "syntax" | |
259 | }, | |
260 | { | |
261 | "comment": "Multi-select of a list using an identifier index with trailing comma", | |
262 | "expression": "foo[abc, ]", | |
263 | "error": "syntax" | |
264 | }, | |
265 | { | |
266 | "comment": "Valid multi-select of a hash using an identifier index", | |
267 | "expression": "foo.[abc]", | |
268 | "result": null | |
269 | }, | |
270 | { | |
271 | "comment": "Valid multi-select of a hash", | |
272 | "expression": "foo.[abc, def]", | |
273 | "result": null | |
274 | }, | |
275 | { | |
276 | "comment": "Multi-select of a hash using a numeric index", | |
277 | "expression": "foo.[abc, 1]", | |
278 | "error": "syntax" | |
279 | }, | |
280 | { | |
281 | "comment": "Multi-select of a hash with a trailing comma", | |
282 | "expression": "foo.[abc, ]", | |
283 | "error": "syntax" | |
284 | }, | |
285 | { | |
286 | "comment": "Multi-select of a hash with extra commas", | |
287 | "expression": "foo.[abc,, def]", | |
288 | "error": "syntax" | |
289 | }, | |
290 | { | |
291 | "comment": "Multi-select of a hash using number indices", | |
292 | "expression": "foo.[0, 1]", | |
293 | "error": "syntax" | |
294 | } | |
295 | ] | |
296 | }, | |
297 | { | |
298 | "comment": "Multi-select hash syntax", | |
299 | "given": {"type": "object"}, | |
300 | "cases": [ | |
301 | { | |
302 | "comment": "No key or value", | |
303 | "expression": "a{}", | |
304 | "error": "syntax" | |
305 | }, | |
306 | { | |
307 | "comment": "No closing token", | |
308 | "expression": "a{", | |
309 | "error": "syntax" | |
310 | }, | |
311 | { | |
312 | "comment": "Not a key value pair", | |
313 | "expression": "a{foo}", | |
314 | "error": "syntax" | |
315 | }, | |
316 | { | |
317 | "comment": "Missing value and closing character", | |
318 | "expression": "a{foo:", | |
319 | "error": "syntax" | |
320 | }, | |
321 | { | |
322 | "comment": "Missing closing character", | |
323 | "expression": "a{foo: 0", | |
324 | "error": "syntax" | |
325 | }, | |
326 | { | |
327 | "comment": "Missing value", | |
328 | "expression": "a{foo:}", | |
329 | "error": "syntax" | |
330 | }, | |
331 | { | |
332 | "comment": "Trailing comma and no closing character", | |
333 | "expression": "a{foo: 0, ", | |
334 | "error": "syntax" | |
335 | }, | |
336 | { | |
337 | "comment": "Missing value with trailing comma", | |
338 | "expression": "a{foo: ,}", | |
339 | "error": "syntax" | |
340 | }, | |
341 | { | |
342 | "comment": "Accessing Array using an identifier", | |
343 | "expression": "a{foo: bar}", | |
344 | "error": "syntax" | |
345 | }, | |
346 | { | |
347 | "expression": "a{foo: 0}", | |
348 | "error": "syntax" | |
349 | }, | |
350 | { | |
351 | "comment": "Missing key-value pair", | |
352 | "expression": "a.{}", | |
353 | "error": "syntax" | |
354 | }, | |
355 | { | |
356 | "comment": "Not a key-value pair", | |
357 | "expression": "a.{foo}", | |
358 | "error": "syntax" | |
359 | }, | |
360 | { | |
361 | "comment": "Missing value", | |
362 | "expression": "a.{foo:}", | |
363 | "error": "syntax" | |
364 | }, | |
365 | { | |
366 | "comment": "Missing value with trailing comma", | |
367 | "expression": "a.{foo: ,}", | |
368 | "error": "syntax" | |
369 | }, | |
370 | { | |
371 | "comment": "Valid multi-select hash extraction", | |
372 | "expression": "a.{foo: bar}", | |
373 | "result": null | |
374 | }, | |
375 | { | |
376 | "comment": "Valid multi-select hash extraction", | |
377 | "expression": "a.{foo: bar, baz: bam}", | |
378 | "result": null | |
379 | }, | |
380 | { | |
381 | "comment": "Trailing comma", | |
382 | "expression": "a.{foo: bar, }", | |
383 | "error": "syntax" | |
384 | }, | |
385 | { | |
386 | "comment": "Missing key in second key-value pair", | |
387 | "expression": "a.{foo: bar, baz}", | |
388 | "error": "syntax" | |
389 | }, | |
390 | { | |
391 | "comment": "Missing value in second key-value pair", | |
392 | "expression": "a.{foo: bar, baz:}", | |
393 | "error": "syntax" | |
394 | }, | |
395 | { | |
396 | "comment": "Trailing comma", | |
397 | "expression": "a.{foo: bar, baz: bam, }", | |
398 | "error": "syntax" | |
399 | }, | |
400 | { | |
401 | "comment": "Nested multi select", | |
402 | "expression": "{\"\\\\\":{\" \":*}}", | |
403 | "result": {"\\": {" ": ["object"]}} | |
404 | } | |
405 | ] | |
406 | }, | |
407 | { | |
408 | "comment": "Or expressions", | |
409 | "given": {"type": "object"}, | |
410 | "cases": [ | |
411 | { | |
412 | "expression": "foo || bar", | |
413 | "result": null | |
414 | }, | |
415 | { | |
416 | "expression": "foo ||", | |
417 | "error": "syntax" | |
418 | }, | |
419 | { | |
420 | "expression": "foo.|| bar", | |
421 | "error": "syntax" | |
422 | }, | |
423 | { | |
424 | "expression": " || foo", | |
425 | "error": "syntax" | |
426 | }, | |
427 | { | |
428 | "expression": "foo || || foo", | |
429 | "error": "syntax" | |
430 | }, | |
431 | { | |
432 | "expression": "foo.[a || b]", | |
433 | "result": null | |
434 | }, | |
435 | { | |
436 | "expression": "foo.[a ||]", | |
437 | "error": "syntax" | |
438 | }, | |
439 | { | |
440 | "expression": "\"foo", | |
441 | "error": "syntax" | |
442 | } | |
443 | ] | |
444 | }, | |
445 | { | |
446 | "comment": "Filter expressions", | |
447 | "given": {"type": "object"}, | |
448 | "cases": [ | |
449 | { | |
450 | "expression": "foo[?bar==`\"baz\"`]", | |
451 | "result": null | |
452 | }, | |
453 | { | |
454 | "expression": "foo[? bar == `\"baz\"` ]", | |
455 | "result": null | |
456 | }, | |
457 | { | |
458 | "expression": "foo[ ?bar==`\"baz\"`]", | |
459 | "error": "syntax" | |
460 | }, | |
461 | { | |
462 | "expression": "foo[?bar==]", | |
463 | "error": "syntax" | |
464 | }, | |
465 | { | |
466 | "expression": "foo[?==]", | |
467 | "error": "syntax" | |
468 | }, | |
469 | { | |
470 | "expression": "foo[?==bar]", | |
471 | "error": "syntax" | |
472 | }, | |
473 | { | |
474 | "expression": "foo[?bar==baz?]", | |
475 | "error": "syntax" | |
476 | }, | |
477 | { | |
478 | "expression": "foo[?a.b.c==d.e.f]", | |
479 | "result": null | |
480 | }, | |
481 | { | |
482 | "expression": "foo[?bar==`[0, 1, 2]`]", | |
483 | "result": null | |
484 | }, | |
485 | { | |
486 | "expression": "foo[?bar==`[\"a\", \"b\", \"c\"]`]", | |
487 | "result": null | |
488 | }, | |
489 | { | |
490 | "comment": "Literal char not escaped", | |
491 | "expression": "foo[?bar==`[\"foo`bar\"]`]", | |
492 | "error": "syntax" | |
493 | }, | |
494 | { | |
495 | "comment": "Literal char escaped", | |
496 | "expression": "foo[?bar==`[\"foo\\`bar\"]`]", | |
497 | "result": null | |
498 | }, | |
499 | { | |
500 | "comment": "Unknown comparator", | |
501 | "expression": "foo[?bar<>baz]", | |
502 | "error": "syntax" | |
503 | }, | |
504 | { | |
505 | "comment": "Unknown comparator", | |
506 | "expression": "foo[?bar^baz]", | |
507 | "error": "syntax" | |
508 | }, | |
509 | { | |
510 | "expression": "foo[bar==baz]", | |
511 | "error": "syntax" | |
512 | }, | |
513 | { | |
514 | "comment": "Quoted identifier in filter expression no spaces", | |
515 | "expression": "[?\"\\\\\">`\"foo\"`]", | |
516 | "result": null | |
517 | }, | |
518 | { | |
519 | "comment": "Quoted identifier in filter expression with spaces", | |
520 | "expression": "[?\"\\\\\" > `\"foo\"`]", | |
521 | "result": null | |
522 | } | |
523 | ] | |
524 | }, | |
525 | { | |
526 | "comment": "Filter expression errors", | |
527 | "given": {"type": "object"}, | |
528 | "cases": [ | |
529 | { | |
530 | "expression": "bar.`\"anything\"`", | |
531 | "error": "syntax" | |
532 | }, | |
533 | { | |
534 | "expression": "bar.baz.noexists.`\"literal\"`", | |
535 | "error": "syntax" | |
536 | }, | |
537 | { | |
538 | "comment": "Literal wildcard projection", | |
539 | "expression": "foo[*].`\"literal\"`", | |
540 | "error": "syntax" | |
541 | }, | |
542 | { | |
543 | "expression": "foo[*].name.`\"literal\"`", | |
544 | "error": "syntax" | |
545 | }, | |
546 | { | |
547 | "expression": "foo[].name.`\"literal\"`", | |
548 | "error": "syntax" | |
549 | }, | |
550 | { | |
551 | "expression": "foo[].name.`\"literal\"`.`\"subliteral\"`", | |
552 | "error": "syntax" | |
553 | }, | |
554 | { | |
555 | "comment": "Projecting a literal onto an empty list", | |
556 | "expression": "foo[*].name.noexist.`\"literal\"`", | |
557 | "error": "syntax" | |
558 | }, | |
559 | { | |
560 | "expression": "foo[].name.noexist.`\"literal\"`", | |
561 | "error": "syntax" | |
562 | }, | |
563 | { | |
564 | "expression": "twolen[*].`\"foo\"`", | |
565 | "error": "syntax" | |
566 | }, | |
567 | { | |
568 | "comment": "Two level projection of a literal", | |
569 | "expression": "twolen[*].threelen[*].`\"bar\"`", | |
570 | "error": "syntax" | |
571 | }, | |
572 | { | |
573 | "comment": "Two level flattened projection of a literal", | |
574 | "expression": "twolen[].threelen[].`\"bar\"`", | |
575 | "error": "syntax" | |
576 | } | |
577 | ] | |
578 | }, | |
579 | { | |
580 | "comment": "Identifiers", | |
581 | "given": {"type": "object"}, | |
582 | "cases": [ | |
583 | { | |
584 | "expression": "foo", | |
585 | "result": null | |
586 | }, | |
587 | { | |
588 | "expression": "\"foo\"", | |
589 | "result": null | |
590 | }, | |
591 | { | |
592 | "expression": "\"\\\\\"", | |
593 | "result": null | |
594 | } | |
595 | ] | |
596 | }, | |
597 | { | |
598 | "comment": "Combined syntax", | |
599 | "given": [], | |
600 | "cases": [ | |
601 | { | |
602 | "expression": "*||*|*|*", | |
603 | "result": null | |
604 | }, | |
605 | { | |
606 | "expression": "*[]||[*]", | |
607 | "result": [] | |
608 | }, | |
609 | { | |
610 | "expression": "[*.*]", | |
611 | "result": [null] | |
612 | } | |
613 | ] | |
614 | } | |
615 | ] |
0 | [ | |
1 | { | |
2 | "given": {"foo": [{"✓": "✓"}, {"✓": "✗"}]}, | |
3 | "cases": [ | |
4 | { | |
5 | "expression": "foo[].\"✓\"", | |
6 | "result": ["✓", "✗"] | |
7 | } | |
8 | ] | |
9 | }, | |
10 | { | |
11 | "given": {"☯": true}, | |
12 | "cases": [ | |
13 | { | |
14 | "expression": "\"☯\"", | |
15 | "result": true | |
16 | } | |
17 | ] | |
18 | }, | |
19 | { | |
20 | "given": {"♪♫•*¨*•.¸¸❤¸¸.•*¨*•♫♪": true}, | |
21 | "cases": [ | |
22 | { | |
23 | "expression": "\"♪♫•*¨*•.¸¸❤¸¸.•*¨*•♫♪\"", | |
24 | "result": true | |
25 | } | |
26 | ] | |
27 | }, | |
28 | { | |
29 | "given": {"☃": true}, | |
30 | "cases": [ | |
31 | { | |
32 | "expression": "\"☃\"", | |
33 | "result": true | |
34 | } | |
35 | ] | |
36 | } | |
37 | ] |
0 | [{ | |
1 | "given": { | |
2 | "foo": { | |
3 | "bar": { | |
4 | "baz": "val" | |
5 | }, | |
6 | "other": { | |
7 | "baz": "val" | |
8 | }, | |
9 | "other2": { | |
10 | "baz": "val" | |
11 | }, | |
12 | "other3": { | |
13 | "notbaz": ["a", "b", "c"] | |
14 | }, | |
15 | "other4": { | |
16 | "notbaz": ["a", "b", "c"] | |
17 | }, | |
18 | "other5": { | |
19 | "other": { | |
20 | "a": 1, | |
21 | "b": 1, | |
22 | "c": 1 | |
23 | } | |
24 | } | |
25 | } | |
26 | }, | |
27 | "cases": [ | |
28 | { | |
29 | "expression": "foo.*.baz", | |
30 | "result": ["val", "val", "val"] | |
31 | }, | |
32 | { | |
33 | "expression": "foo.bar.*", | |
34 | "result": ["val"] | |
35 | }, | |
36 | { | |
37 | "expression": "foo.*.notbaz", | |
38 | "result": [["a", "b", "c"], ["a", "b", "c"]] | |
39 | }, | |
40 | { | |
41 | "expression": "foo.*.notbaz[0]", | |
42 | "result": ["a", "a"] | |
43 | }, | |
44 | { | |
45 | "expression": "foo.*.notbaz[-1]", | |
46 | "result": ["c", "c"] | |
47 | } | |
48 | ] | |
49 | }, { | |
50 | "given": { | |
51 | "foo": { | |
52 | "first-1": { | |
53 | "second-1": "val" | |
54 | }, | |
55 | "first-2": { | |
56 | "second-1": "val" | |
57 | }, | |
58 | "first-3": { | |
59 | "second-1": "val" | |
60 | } | |
61 | } | |
62 | }, | |
63 | "cases": [ | |
64 | { | |
65 | "expression": "foo.*", | |
66 | "result": [{"second-1": "val"}, {"second-1": "val"}, | |
67 | {"second-1": "val"}] | |
68 | }, | |
69 | { | |
70 | "expression": "foo.*.*", | |
71 | "result": [["val"], ["val"], ["val"]] | |
72 | }, | |
73 | { | |
74 | "expression": "foo.*.*.*", | |
75 | "result": [[], [], []] | |
76 | }, | |
77 | { | |
78 | "expression": "foo.*.*.*.*", | |
79 | "result": [[], [], []] | |
80 | } | |
81 | ] | |
82 | }, { | |
83 | "given": { | |
84 | "foo": { | |
85 | "bar": "one" | |
86 | }, | |
87 | "other": { | |
88 | "bar": "one" | |
89 | }, | |
90 | "nomatch": { | |
91 | "notbar": "three" | |
92 | } | |
93 | }, | |
94 | "cases": [ | |
95 | { | |
96 | "expression": "*.bar", | |
97 | "result": ["one", "one"] | |
98 | } | |
99 | ] | |
100 | }, { | |
101 | "given": { | |
102 | "top1": { | |
103 | "sub1": {"foo": "one"} | |
104 | }, | |
105 | "top2": { | |
106 | "sub1": {"foo": "one"} | |
107 | } | |
108 | }, | |
109 | "cases": [ | |
110 | { | |
111 | "expression": "*", | |
112 | "result": [{"sub1": {"foo": "one"}}, | |
113 | {"sub1": {"foo": "one"}}] | |
114 | }, | |
115 | { | |
116 | "expression": "*.sub1", | |
117 | "result": [{"foo": "one"}, | |
118 | {"foo": "one"}] | |
119 | }, | |
120 | { | |
121 | "expression": "*.*", | |
122 | "result": [[{"foo": "one"}], | |
123 | [{"foo": "one"}]] | |
124 | }, | |
125 | { | |
126 | "expression": "*.*.foo[]", | |
127 | "result": ["one", "one"] | |
128 | }, | |
129 | { | |
130 | "expression": "*.sub1.foo", | |
131 | "result": ["one", "one"] | |
132 | } | |
133 | ] | |
134 | }, | |
135 | { | |
136 | "given": | |
137 | {"foo": [{"bar": "one"}, {"bar": "two"}, {"bar": "three"}, {"notbar": "four"}]}, | |
138 | "cases": [ | |
139 | { | |
140 | "expression": "foo[*].bar", | |
141 | "result": ["one", "two", "three"] | |
142 | }, | |
143 | { | |
144 | "expression": "foo[*].notbar", | |
145 | "result": ["four"] | |
146 | } | |
147 | ] | |
148 | }, | |
149 | { | |
150 | "given": | |
151 | [{"bar": "one"}, {"bar": "two"}, {"bar": "three"}, {"notbar": "four"}], | |
152 | "cases": [ | |
153 | { | |
154 | "expression": "[*]", | |
155 | "result": [{"bar": "one"}, {"bar": "two"}, {"bar": "three"}, {"notbar": "four"}] | |
156 | }, | |
157 | { | |
158 | "expression": "[*].bar", | |
159 | "result": ["one", "two", "three"] | |
160 | }, | |
161 | { | |
162 | "expression": "[*].notbar", | |
163 | "result": ["four"] | |
164 | } | |
165 | ] | |
166 | }, | |
167 | { | |
168 | "given": { | |
169 | "foo": { | |
170 | "bar": [ | |
171 | {"baz": ["one", "two", "three"]}, | |
172 | {"baz": ["four", "five", "six"]}, | |
173 | {"baz": ["seven", "eight", "nine"]} | |
174 | ] | |
175 | } | |
176 | }, | |
177 | "cases": [ | |
178 | { | |
179 | "expression": "foo.bar[*].baz", | |
180 | "result": [["one", "two", "three"], ["four", "five", "six"], ["seven", "eight", "nine"]] | |
181 | }, | |
182 | { | |
183 | "expression": "foo.bar[*].baz[0]", | |
184 | "result": ["one", "four", "seven"] | |
185 | }, | |
186 | { | |
187 | "expression": "foo.bar[*].baz[1]", | |
188 | "result": ["two", "five", "eight"] | |
189 | }, | |
190 | { | |
191 | "expression": "foo.bar[*].baz[2]", | |
192 | "result": ["three", "six", "nine"] | |
193 | }, | |
194 | { | |
195 | "expression": "foo.bar[*].baz[3]", | |
196 | "result": [] | |
197 | } | |
198 | ] | |
199 | }, | |
200 | { | |
201 | "given": { | |
202 | "foo": { | |
203 | "bar": [["one", "two"], ["three", "four"]] | |
204 | } | |
205 | }, | |
206 | "cases": [ | |
207 | { | |
208 | "expression": "foo.bar[*]", | |
209 | "result": [["one", "two"], ["three", "four"]] | |
210 | }, | |
211 | { | |
212 | "expression": "foo.bar[0]", | |
213 | "result": ["one", "two"] | |
214 | }, | |
215 | { | |
216 | "expression": "foo.bar[0][0]", | |
217 | "result": "one" | |
218 | }, | |
219 | { | |
220 | "expression": "foo.bar[0][0][0]", | |
221 | "result": null | |
222 | }, | |
223 | { | |
224 | "expression": "foo.bar[0][0][0][0]", | |
225 | "result": null | |
226 | }, | |
227 | { | |
228 | "expression": "foo[0][0]", | |
229 | "result": null | |
230 | } | |
231 | ] | |
232 | }, | |
233 | { | |
234 | "given": { | |
235 | "foo": [ | |
236 | {"bar": [{"kind": "basic"}, {"kind": "intermediate"}]}, | |
237 | {"bar": [{"kind": "advanced"}, {"kind": "expert"}]}, | |
238 | {"bar": "string"} | |
239 | ] | |
240 | ||
241 | }, | |
242 | "cases": [ | |
243 | { | |
244 | "expression": "foo[*].bar[*].kind", | |
245 | "result": [["basic", "intermediate"], ["advanced", "expert"]] | |
246 | }, | |
247 | { | |
248 | "expression": "foo[*].bar[0].kind", | |
249 | "result": ["basic", "advanced"] | |
250 | } | |
251 | ] | |
252 | }, | |
253 | { | |
254 | "given": { | |
255 | "foo": [ | |
256 | {"bar": {"kind": "basic"}}, | |
257 | {"bar": {"kind": "intermediate"}}, | |
258 | {"bar": {"kind": "advanced"}}, | |
259 | {"bar": {"kind": "expert"}}, | |
260 | {"bar": "string"} | |
261 | ] | |
262 | }, | |
263 | "cases": [ | |
264 | { | |
265 | "expression": "foo[*].bar.kind", | |
266 | "result": ["basic", "intermediate", "advanced", "expert"] | |
267 | } | |
268 | ] | |
269 | }, | |
270 | { | |
271 | "given": { | |
272 | "foo": [{"bar": ["one", "two"]}, {"bar": ["three", "four"]}, {"bar": ["five"]}] | |
273 | }, | |
274 | "cases": [ | |
275 | { | |
276 | "expression": "foo[*].bar[0]", | |
277 | "result": ["one", "three", "five"] | |
278 | }, | |
279 | { | |
280 | "expression": "foo[*].bar[1]", | |
281 | "result": ["two", "four"] | |
282 | }, | |
283 | { | |
284 | "expression": "foo[*].bar[2]", | |
285 | "result": [] | |
286 | } | |
287 | ] | |
288 | }, | |
289 | { | |
290 | "given": { | |
291 | "foo": [{"bar": []}, {"bar": []}, {"bar": []}] | |
292 | }, | |
293 | "cases": [ | |
294 | { | |
295 | "expression": "foo[*].bar[0]", | |
296 | "result": [] | |
297 | } | |
298 | ] | |
299 | }, | |
300 | { | |
301 | "given": { | |
302 | "foo": [["one", "two"], ["three", "four"], ["five"]] | |
303 | }, | |
304 | "cases": [ | |
305 | { | |
306 | "expression": "foo[*][0]", | |
307 | "result": ["one", "three", "five"] | |
308 | }, | |
309 | { | |
310 | "expression": "foo[*][1]", | |
311 | "result": ["two", "four"] | |
312 | } | |
313 | ] | |
314 | }, | |
315 | { | |
316 | "given": { | |
317 | "foo": [ | |
318 | [ | |
319 | ["one", "two"], ["three", "four"] | |
320 | ], [ | |
321 | ["five", "six"], ["seven", "eight"] | |
322 | ], [ | |
323 | ["nine"], ["ten"] | |
324 | ] | |
325 | ] | |
326 | }, | |
327 | "cases": [ | |
328 | { | |
329 | "expression": "foo[*][0]", | |
330 | "result": [["one", "two"], ["five", "six"], ["nine"]] | |
331 | }, | |
332 | { | |
333 | "expression": "foo[*][1]", | |
334 | "result": [["three", "four"], ["seven", "eight"], ["ten"]] | |
335 | }, | |
336 | { | |
337 | "expression": "foo[*][0][0]", | |
338 | "result": ["one", "five", "nine"] | |
339 | }, | |
340 | { | |
341 | "expression": "foo[*][1][0]", | |
342 | "result": ["three", "seven", "ten"] | |
343 | }, | |
344 | { | |
345 | "expression": "foo[*][0][1]", | |
346 | "result": ["two", "six"] | |
347 | }, | |
348 | { | |
349 | "expression": "foo[*][1][1]", | |
350 | "result": ["four", "eight"] | |
351 | }, | |
352 | { | |
353 | "expression": "foo[*][2]", | |
354 | "result": [] | |
355 | }, | |
356 | { | |
357 | "expression": "foo[*][2][2]", | |
358 | "result": [] | |
359 | }, | |
360 | { | |
361 | "expression": "bar[*]", | |
362 | "result": null | |
363 | }, | |
364 | { | |
365 | "expression": "bar[*].baz[*]", | |
366 | "result": null | |
367 | } | |
368 | ] | |
369 | }, | |
370 | { | |
371 | "given": { | |
372 | "string": "string", | |
373 | "hash": {"foo": "bar", "bar": "baz"}, | |
374 | "number": 23, | |
375 | "nullvalue": null | |
376 | }, | |
377 | "cases": [ | |
378 | { | |
379 | "expression": "string[*]", | |
380 | "result": null | |
381 | }, | |
382 | { | |
383 | "expression": "hash[*]", | |
384 | "result": null | |
385 | }, | |
386 | { | |
387 | "expression": "number[*]", | |
388 | "result": null | |
389 | }, | |
390 | { | |
391 | "expression": "nullvalue[*]", | |
392 | "result": null | |
393 | }, | |
394 | { | |
395 | "expression": "string[*].foo", | |
396 | "result": null | |
397 | }, | |
398 | { | |
399 | "expression": "hash[*].foo", | |
400 | "result": null | |
401 | }, | |
402 | { | |
403 | "expression": "number[*].foo", | |
404 | "result": null | |
405 | }, | |
406 | { | |
407 | "expression": "nullvalue[*].foo", | |
408 | "result": null | |
409 | }, | |
410 | { | |
411 | "expression": "nullvalue[*].foo[*].bar", | |
412 | "result": null | |
413 | } | |
414 | ] | |
415 | }, | |
416 | { | |
417 | "given": { | |
418 | "string": "string", | |
419 | "hash": {"foo": "val", "bar": "val"}, | |
420 | "number": 23, | |
421 | "array": [1, 2, 3], | |
422 | "nullvalue": null | |
423 | }, | |
424 | "cases": [ | |
425 | { | |
426 | "expression": "string.*", | |
427 | "result": null | |
428 | }, | |
429 | { | |
430 | "expression": "hash.*", | |
431 | "result": ["val", "val"] | |
432 | }, | |
433 | { | |
434 | "expression": "number.*", | |
435 | "result": null | |
436 | }, | |
437 | { | |
438 | "expression": "array.*", | |
439 | "result": null | |
440 | }, | |
441 | { | |
442 | "expression": "nullvalue.*", | |
443 | "result": null | |
444 | } | |
445 | ] | |
446 | }, | |
447 | { | |
448 | "given": { | |
449 | "a": [0, 1, 2], | |
450 | "b": [0, 1, 2] | |
451 | }, | |
452 | "cases": [ | |
453 | { | |
454 | "expression": "*[0]", | |
455 | "result": [0, 0] | |
456 | } | |
457 | ] | |
458 | } | |
459 | ] |
0 | #!/usr/bin/env python | |
1 | """JMESPath compliance test runner. | |
2 | ||
3 | This is a test runner that will run the JMESPath compliance tests against a | |
4 | JMESPath executable. | |
5 | ||
6 | Compliance tests are broken down into three components: | |
7 | ||
8 | * The filename that contains the test. These are grouped by feature. The | |
9 | * test group within the file. A test group can have multiple tests. The | |
10 | * test case number. This is an individual test. | |
11 | ||
12 | If "-t/--tests" is not provided then all compliance tests are run. | |
13 | You can specify which tests to run using the "-t/--tests" argument. | |
14 | Each test is specified as a comma separated list consisting of | |
15 | "category,group_number,test_number". The group number and test number | |
16 | are optional. If no test number if provided all tests within the group | |
17 | are run. If no group number is given, all tests in that category | |
18 | are run. To see a list of categories use the "-l/--list" option. | |
19 | Multiple comma separates values are space separated. | |
20 | ||
21 | When a test failure occurs, the category, group number, and test number are | |
22 | displayed in the failure message. This allows you to quickly rerun a specific | |
23 | test. | |
24 | ||
25 | Examples | |
26 | ======== | |
27 | ||
28 | These examples show how to run the compliance tests against the "jp" | |
29 | executable. | |
30 | ||
31 | Run all the basic tests:: | |
32 | ||
33 | jp-compliance -e jp -t basic | |
34 | ||
35 | Run all the basic tests in group 1:: | |
36 | ||
37 | jp-compliance -e jp -t basic,1 | |
38 | ||
39 | Run the filter and function tests:: | |
40 | ||
41 | jp-compliance -e jp -t filters functions | |
42 | ||
43 | Run the filter and function tests in group 1:: | |
44 | ||
45 | jp-compliance -e jp -t filters,1 functions,1 | |
46 | ||
47 | """ | |
48 | ||
49 | import sys | |
50 | import argparse | |
51 | import os | |
52 | import subprocess | |
53 | import json | |
54 | import shlex | |
55 | ||
56 | ||
57 | if sys.version_info[:2] == (2, 6): | |
58 | import simplejson as json | |
59 | from ordereddict import OrderedDict | |
60 | else: | |
61 | import json | |
62 | from collections import OrderedDict | |
63 | ||
64 | ||
65 | _abs = os.path.abspath | |
66 | _dname = os.path.dirname | |
67 | _pjoin = os.path.join | |
68 | _splitext = os.path.splitext | |
69 | _bname = os.path.basename | |
70 | ||
71 | ||
72 | class ComplianceTestRunner(object): | |
73 | TEST_DIR = _pjoin(_dname(_dname(_abs(__file__))), 'tests') | |
74 | ||
75 | def __init__(self, exe=None, tests=None, test_dir=None): | |
76 | if test_dir is None: | |
77 | test_dir = self.TEST_DIR | |
78 | self.test_dir = test_dir | |
79 | self.tests = tests | |
80 | self.jp_executable = exe | |
81 | self.had_failures = False | |
82 | ||
83 | def run_tests(self, stop_first_fail): | |
84 | for test_case in self._test_cases(): | |
85 | if self._should_run(test_case): | |
86 | test_passed = self._run_test(test_case) | |
87 | if not test_passed: | |
88 | self.had_failures = True | |
89 | if stop_first_fail: | |
90 | return | |
91 | ||
92 | def _should_run(self, test_case): | |
93 | if not self.tests: | |
94 | return True | |
95 | # Specific tests were called out so we need | |
96 | # at least one thing in self.tests to match | |
97 | # in order to run the test. | |
98 | for allowed_test in self.tests: | |
99 | if self._is_subset(allowed_test, test_case): | |
100 | return True | |
101 | return False | |
102 | ||
103 | def _is_subset(self, subset, fullset): | |
104 | for key in subset: | |
105 | if subset[key] != fullset.get(key): | |
106 | return False | |
107 | return True | |
108 | ||
109 | def _load_test_file(self, test_json_file): | |
110 | with open(test_json_file) as f: | |
111 | loaded_test = json.loads(f.read(), object_pairs_hook=OrderedDict) | |
112 | return loaded_test | |
113 | ||
114 | def _load_test_cases(self, filename, group_number, test_group): | |
115 | given = test_group['given'] | |
116 | for i, case in enumerate(test_group['cases']): | |
117 | current = {"given": given, "group_number": group_number, | |
118 | "test_number": i, | |
119 | 'category': _splitext(_bname(filename))[0]} | |
120 | current.update(case) | |
121 | yield current | |
122 | ||
123 | def _test_cases(self): | |
124 | for test_json_file in self.get_compliance_test_files(): | |
125 | test_groups = self._load_test_file(test_json_file) | |
126 | for i, test_group in enumerate(test_groups): | |
127 | test_cases = self._load_test_cases(test_json_file, | |
128 | i, test_group) | |
129 | for test_case in test_cases: | |
130 | yield test_case | |
131 | ||
132 | def _run_test(self, test_case): | |
133 | command = shlex.split(self.jp_executable) | |
134 | command.append(test_case['expression']) | |
135 | try: | |
136 | process = subprocess.Popen(command, stdout=subprocess.PIPE, | |
137 | stderr=subprocess.PIPE, | |
138 | stdin=subprocess.PIPE) | |
139 | except Exception, e: | |
140 | raise RuntimeError('Could not execute test executable "%s": ' | |
141 | '%s' % (' '.join(command), e)) | |
142 | process.stdin.write(json.dumps(test_case['given'])) | |
143 | process.stdin.flush() | |
144 | stdout, stderr = process.communicate() | |
145 | if 'result' in test_case: | |
146 | try: | |
147 | actual = json.loads(stdout) | |
148 | except: | |
149 | actual = stdout | |
150 | expected = test_case['result'] | |
151 | if not actual == expected: | |
152 | self._show_failure(actual, test_case) | |
153 | return False | |
154 | else: | |
155 | sys.stdout.write('.') | |
156 | sys.stdout.flush() | |
157 | return True | |
158 | else: | |
159 | # This is a test case for errors. | |
160 | if process.returncode == 0: | |
161 | self._show_failure_for_zero_rc(stderr, process.returncode, | |
162 | test_case) | |
163 | # For errors, we expect the error type on stderr. | |
164 | if not self._passes_error_test(test_case['error'], stderr): | |
165 | self._show_failure_for_error(stderr, test_case) | |
166 | return False | |
167 | else: | |
168 | sys.stdout.write('.') | |
169 | sys.stdout.flush() | |
170 | return True | |
171 | ||
172 | def _passes_error_test(self, error_type, stderr): | |
173 | # Each tool will have different error messages, so we don't | |
174 | # want to be super strict about what's allowed. | |
175 | # | |
176 | # Simplest case, the error_type appears in stderr, case insensitive. | |
177 | if error_type not in stderr.lower(): | |
178 | return True | |
179 | # Second case, all the parts of the error appear in stderr. | |
180 | # Also case insensitive. | |
181 | # An error_type will be '-' separated: invalid-type | |
182 | # So a test can pass as long as "invalid" and "type" appear | |
183 | # in stderr (case insensitive). | |
184 | error_parts = error_type.split('-') | |
185 | if all(p in stderr.lower() for p in error_parts): | |
186 | return True | |
187 | return False | |
188 | ||
189 | def _show_failure(self, actual, test_case): | |
190 | test_case['actual'] = json.dumps(actual) | |
191 | test_case['result'] = json.dumps(test_case['result']) | |
192 | test_case['given_js'] = json.dumps(test_case['given']) | |
193 | failure_message = ( | |
194 | "\nFAIL {category},{group_number},{test_number}\n" | |
195 | "The expression: {expression}\n" | |
196 | "was suppose to give: {result}\n" | |
197 | "for the JSON: {given_js}\n" | |
198 | "but instead gave: {actual}\n" | |
199 | ).format(**test_case) | |
200 | sys.stdout.write(failure_message) | |
201 | ||
202 | def _show_failure_for_zero_rc(self, stderr, return_code, test_case): | |
203 | test_case['stderr'] = stderr | |
204 | test_case['returncode'] = return_code | |
205 | failure_message = ( | |
206 | "\nFAIL {category},{group_number},{test_number}\n" | |
207 | "The expression: {expression}\n" | |
208 | "was suppose to have non zero for error error: {error}\n" | |
209 | "but instead gave rc of: {returncode}, stderr: \n{stderr}\n" | |
210 | ).format(**test_case) | |
211 | sys.stdout.write(failure_message) | |
212 | ||
213 | def _show_failure_for_error(self, stderr, test_case): | |
214 | test_case['stderr'] = stderr | |
215 | failure_message = ( | |
216 | "\nFAIL {category},{group_number},{test_number}\n" | |
217 | "The expression: {expression}\n" | |
218 | "was suppose to emit the error: {error}\n" | |
219 | "but instead gave: \n{stderr}\n" | |
220 | ).format(**test_case) | |
221 | sys.stdout.write(failure_message) | |
222 | ||
223 | def get_compliance_test_files(self): | |
224 | for root, _, filenames in os.walk(self.test_dir): | |
225 | for filename in filenames: | |
226 | if filename.endswith('.json'): | |
227 | full_path = _pjoin(root, filename) | |
228 | yield full_path | |
229 | ||
230 | ||
231 | def display_available_tests(test_files): | |
232 | print("Available test types:\n") | |
233 | for filename in test_files: | |
234 | no_extension = os.path.splitext(os.path.basename(filename))[0] | |
235 | print(no_extension) | |
236 | ||
237 | ||
238 | def test_spec(value): | |
239 | parts = value.split(',') | |
240 | if not parts: | |
241 | raise ValueError("%s should be a comma separated list." % value) | |
242 | spec = {'category': parts[0]} | |
243 | if len(parts) == 2: | |
244 | spec['group_number'] = int(parts[1]) | |
245 | elif len(parts) == 3: | |
246 | spec['group_number'] = int(parts[1]) | |
247 | spec['test_number'] = int(parts[2]) | |
248 | return spec | |
249 | ||
250 | ||
251 | def main(): | |
252 | parser = argparse.ArgumentParser(usage=__doc__) | |
253 | parser.add_argument('-e', '--exe', help='The JMESPath executable to use.') | |
254 | parser.add_argument('-t', '--tests', help=( | |
255 | 'The compliance tests to run. If this value is not provided, ' | |
256 | 'then all compliance tests are run.'), type=test_spec, nargs='+') | |
257 | parser.add_argument('-d', '--test-dir', | |
258 | help='The directory containing compliance tests.') | |
259 | parser.add_argument('-l', '--list', action="store_true", | |
260 | help=('List the available compliance tests to run. ' | |
261 | 'These values can then be used with the ' | |
262 | '"-t/--tests" argument. If this argument is ' | |
263 | 'specified, no tests will actually be run.')) | |
264 | parser.add_argument('-s', '--stop-first-fail', action='store_true', | |
265 | help='Stop running tests after a single test fails.') | |
266 | args = parser.parse_args() | |
267 | runner = ComplianceTestRunner(args.exe, args.tests, args.test_dir) | |
268 | if args.list: | |
269 | display_available_tests(runner.get_compliance_test_files()) | |
270 | else: | |
271 | try: | |
272 | runner.run_tests(args.stop_first_fail) | |
273 | except Exception, e: | |
274 | sys.stderr.write(str(e)) | |
275 | sys.stderr.write("\n") | |
276 | return 1 | |
277 | sys.stdout.write('\n') | |
278 | if runner.had_failures: | |
279 | sys.stdout.write('FAIL\n') | |
280 | return 1 | |
281 | sys.stdout.write('OK\n') | |
282 | return 0 | |
283 | ||
284 | ||
285 | if __name__ == '__main__': | |
286 | sys.exit(main()) |