Skip to content

Commit 5f31686

Browse files
Move function tests to function yaml (#56)
* Add tests * Configure test matrix * Limit test trigger on spec folders * Quote special characters in tests * Move function tests to function yaml * Add function_schema.yml and refactor test_schema.json * Clean up extra commas * Remove leading "$" for variadic function arguments * refer to jmespath.site domain name in schema
1 parent 4a84648 commit 5f31686

32 files changed

+1317
-1209
lines changed

.github/workflows/test_validate.yaml

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ name: Validate tests
22
on:
33
push:
44
branches: [ main ]
5+
paths:
6+
- grammar/**
7+
- test_data/**
8+
- functions/**
59
pull_request:
610
branches: [ main ]
711

@@ -14,8 +18,8 @@ jobs:
1418
steps:
1519
- uses: actions/checkout@v2
1620
- id: set-matrix
17-
run: echo "::set-output name=matrix::$(ls grammar/*.json functions/*.json | jq -R -s -c 'split("\n")[:-1]')"
18-
validate:
21+
run: echo "::set-output name=matrix::$(ls grammar/*.json | jq -R -s -c 'split("\n")[:-1]')"
22+
validate-tests:
1923
needs: list-tests
2024
runs-on: ubuntu-latest
2125
strategy:
@@ -28,5 +32,29 @@ jobs:
2832
cache: pip
2933
cache-dependency-path: .github/workflows/validate_requirements.txt
3034
- run: pip install -r .github/workflows/validate_requirements.txt
31-
- name: Validate tests
32-
run: "jsonschema test_schema.json -o pretty -i ${{ matrix.manifest }}"
35+
- name: Validate grammar tests
36+
run: "check-jsonschema --schemafile test_schema.yml ${{ matrix.manifest }}"
37+
38+
list-functions:
39+
runs-on: ubuntu-latest
40+
outputs:
41+
matrix: ${{ steps.set-matrix.outputs.matrix }}
42+
steps:
43+
- uses: actions/checkout@v2
44+
- id: set-matrix
45+
run: echo "::set-output name=matrix::$(ls functions/*.yml | jq -R -s -c 'split("\n")[:-1]')"
46+
validate-functions:
47+
needs: list-functions
48+
runs-on: ubuntu-latest
49+
strategy:
50+
matrix:
51+
manifest: ${{ fromJson(needs.list-functions.outputs.matrix) }}
52+
steps:
53+
- uses: actions/checkout@v2
54+
- uses: actions/setup-python@v3
55+
with:
56+
cache: pip
57+
cache-dependency-path: .github/workflows/validate_requirements.txt
58+
- run: pip install -r .github/workflows/validate_requirements.txt
59+
- name: Validate function spec
60+
run: "check-jsonschema --schemafile function_schema.yml ${{ matrix.manifest }}"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
jsonschema==4.4.0
1+
check-jsonschema

function_schema.yml

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
---
2+
$schema: https://json-schema.org/draft/2020-12/schema
3+
$id: https://jmespath.site/function_schema.yml
4+
title: JMESPath function
5+
description: JMESPath function definition and tests
6+
type: object
7+
required: [name, topic, args, returns, desc, examples]
8+
properties:
9+
name:
10+
type: string
11+
description: function identifier
12+
topic:
13+
enum: [math, strings, collections, conversion, misc]
14+
description: related function topic
15+
args:
16+
type: object
17+
additionalProperties: false
18+
properties:
19+
required: &arg
20+
type: array
21+
description: ""
22+
items:
23+
type: object
24+
description: ""
25+
additionalProperties: false
26+
properties:
27+
name:
28+
type: string
29+
description: ""
30+
type: &type
31+
description: ""
32+
oneOf:
33+
- enum: &types [any, number, string, boolean, array, object, "null", expression, "array[number]", "array[string]", "array[boolean]", "array[object]", "array[any]", "expression->number", "expression->string"]
34+
- type: array
35+
items:
36+
enum: *types
37+
desc:
38+
type: string
39+
description: ""
40+
optional: *arg
41+
returns:
42+
type: object
43+
description: ""
44+
required: [type, desc]
45+
additionalProperties: false
46+
properties:
47+
type:
48+
<<: *type
49+
description: ""
50+
desc:
51+
type: string
52+
description: ""
53+
desc:
54+
type: string
55+
description: ""
56+
examples:
57+
type: array
58+
description: ""
59+
minItems: 1
60+
uniqueItems: true
61+
items:
62+
description: ""
63+
oneOf:
64+
- type: object
65+
required: [context, args, returns]
66+
additionalProperties: false
67+
properties:
68+
context: &context
69+
type: &any ["number","string","boolean","object","array","null"]
70+
description: ""
71+
args: &args
72+
type: array
73+
description: ""
74+
items:
75+
type: *any
76+
description: ""
77+
returns:
78+
type: *any
79+
description: ""
80+
- type: object
81+
required: [context, args, error]
82+
additionalProperties: false
83+
properties:
84+
context: *context
85+
args: *args
86+
error:
87+
type: string
88+
description: ""

functions/abs.yml

Lines changed: 76 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,141 @@
11
name: abs
2-
topic:
2+
topic: math
33
args:
44
required:
55
- name: value
66
type: [number]
7-
desc:
7+
desc: positive or negative number
88
optional: []
99
returns:
1010
type: number
11-
desc:
11+
desc: positive magnitude of input value
1212
desc: |
1313
Returns the absolute value of the provided argument. The signature indicates
1414
that a number is returned, and that the input argument `$value` **must**
1515
resolve to a number, otherwise a `invalid-type` error is triggered.
16-
16+
1717
Below is a worked example. Given:
18-
18+
1919
```
2020
{"foo": -1, "bar": "2"}
2121
```
22-
22+
2323
Evaluating `abs(foo)` works as follows:
24-
25-
24+
25+
2626
1. Evaluate the input argument against the current data:
27-
27+
2828
```
2929
search(foo, {"foo": -1, "bar": "2"}) -> -1
3030
```
31-
32-
31+
32+
3333
2. Validate the type of the resolved argument. In this case
3434
`-1` is of type `number` so it passes the type check.
35-
36-
35+
36+
3737
3. Call the function with the resolved argument:
38-
38+
3939
```
4040
abs(-1) -> 1
4141
```
42-
43-
42+
43+
4444
4. The value of `1` is the resolved value of the function expression
4545
`abs(foo)`.
46-
46+
4747
Below is the same steps for evaluating `abs(bar)`:
48-
49-
48+
49+
5050
1. Evaluate the input argument against the current data:
51-
51+
5252
```
5353
search(bar, {"foo": -1, "bar": "2"}) -> "2"
5454
```
55-
56-
55+
56+
5757
2. Validate the type of the resolved argument. In this case
5858
`"2"` is of type `string` so we immediately indicate that
5959
an `invalid-type` error occurred.
60-
60+
6161
As a final example, here is the steps for evaluating `abs(to_number(bar))`:
62-
63-
62+
63+
6464
1. Evaluate the input argument against the current data:
65-
65+
6666
```
6767
search(to_number(bar), {"foo": -1, "bar": "2"})
6868
```
69-
70-
69+
70+
7171
2. In order to evaluate the above expression, we need to evaluate
7272
`to_number(bar)`:
73-
73+
7474
```
7575
search(bar, {"foo": -1, "bar": "2"}) -> "2"
7676
# Validate "2" passes the type check for to_number, which it does.
7777
to_number("2") -> 2
7878
```
79-
79+
8080
Note that to_number is defined below.
81-
82-
81+
82+
8383
3. Now we can evaluate the original expression:
84-
84+
8585
```
8686
search(to_number(bar), {"foo": -1, "bar": "2"}) -> 2
8787
```
88-
89-
88+
89+
9090
4. Call the function with the final resolved value:
91-
91+
9292
```
9393
abs(2) -> 2
9494
```
95-
96-
95+
96+
9797
5. The value of `2` is the resolved value of the function expression
9898
`abs(to_number(bar))`.
9999
examples:
100-
- context: None
100+
- context:
101101
args: [1]
102102
returns: 1
103-
- context: None
103+
- context:
104104
args: [-1]
105105
returns: 1
106-
- context: None
107-
args: ["abc"]
108-
returns: "<error: invalid-type>"
106+
- context:
107+
args: [abc]
108+
error: invalid-type
109+
- context: &data
110+
foo: -1
111+
zero: 0
112+
numbers: [-1, 3, 4, 5]
113+
array: [-1, 3, 4, 5, a, '100']
114+
strings: [a, b, c]
115+
decimals: [1.01, 1.2, -1.5]
116+
str: Str
117+
'false': false
118+
empty_list: []
119+
empty_hash: {}
120+
objects: {foo: bar, bar: baz}
121+
null_key:
122+
args: [foo]
123+
returns: 1
124+
- context: *data
125+
args: [str]
126+
error: invalid-type
127+
- context: *data
128+
args: ['array[1]']
129+
returns: 3
130+
- context: *data
131+
args: ['`false`']
132+
error: invalid-type
133+
- context: *data
134+
args: ['`-24`']
135+
returns: 24
136+
- context: *data
137+
args: ['`1`', '`2`']
138+
error: invalid-arity
139+
- context: *data
140+
args: ['']
141+
error: invalid-arity

0 commit comments

Comments
 (0)