]> git.cworth.org Git - notmuch/blob - test/json_check_nodes.py
lib/message-property: sync removed properties to the database
[notmuch] / test / json_check_nodes.py
1 #!/usr/bin/env python3
2 import re
3 import sys
4 import json
5
6
7 EXPR_RE = re.compile('(?P<label>[a-zA-Z0-9_-]+):(?P<address>[^=!]+)(?:(?P<type>[=!])(?P<val>.*))?', re.DOTALL|re.MULTILINE)
8
9
10 if len(sys.argv) < 2:
11     sys.exit('usage: '+ sys.argv[0] + """ EXPR [EXPR]
12
13 Takes json data on stdin and evaluates test expressions specified in
14 arguments.  Each test is evaluated, and output is printed only if the
15 test fails.  If any test fails the return value of execution will be
16 non-zero.
17
18 EXPR can be one of following types:
19
20 Value test: test that object in json data found at address is equal to
21 specified value:
22
23   label:address=value
24
25 Existence test: test that dict or list in json data found at address
26 does *not* contain the specified key:
27
28   label:address!key
29
30 Extract: extract object from json data found at address and print
31
32   label:address
33
34 Results are printed to stdout prefixed by expression label.  In all
35 cases the test will fail if object does not exist in data.
36
37 Example:
38
39 0 $ echo '["a", "b", {"c": 1}]' | python3 json_check_nodes.py 'second_d:[1]="d"' 'no_c:[2]!"c"'
40 second_d: value not equal: data[1] = 'b' != 'd'
41 no_c: dict contains key: data[2]["c"] = 1
42 1 $
43
44 """)
45
46
47 # parse expressions from arguments
48 exprs = []
49 for expr in sys.argv[1:]:
50     m = re.match(EXPR_RE, expr)
51     if not m:
52         sys.exit("Invalid expression: {}".format(expr))
53     exprs.append(m)
54
55 data = json.load(sys.stdin)
56
57 fail = False
58
59 for expr in exprs:
60     # print(expr.groups(),fail)
61
62     e = 'data{}'.format(expr.group('address'))
63     try:
64         val = eval(e)
65     except SyntaxError:
66         fail = True
67         print("{}: syntax error on evaluation of object: {}".format(
68             expr.group('label'), e))
69         continue
70     except:
71         fail = True
72         print("{}: object not found: data{}".format(
73             expr.group('label'), expr.group('address')))
74         continue
75
76     if expr.group('type') == '=':
77         try:
78             obj_val = json.loads(expr.group('val'))
79         except:
80             fail = True
81             print("{}: error evaluating value: {}".format(
82                 expr.group('label'), expr.group('address')))
83             continue
84         if val != obj_val:
85             fail = True
86             print("{}: value not equal: data{} = {} != {}".format(
87                 expr.group('label'), expr.group('address'), repr(val), repr(obj_val)))
88
89     elif expr.group('type') == '!':
90         if not isinstance(val, (dict, list)):
91             fail = True
92             print("{}: not a dict or a list: data{}".format(
93                 expr.group('label'), expr.group('address')))
94             continue
95         try:
96             idx = json.loads(expr.group('val'))
97             if idx in val:
98                 fail = True
99                 print("{}: {} contains key: {}[{}] = {}".format(
100                     expr.group('label'), type(val).__name__, e, expr.group('val'), val[idx]))
101         except SyntaxError:
102             fail = True
103             print("{}: syntax error on evaluation of value: {}".format(
104                 expr.group('label'), expr.group('val')))
105             continue
106
107
108     elif expr.group('type') is None:
109         print("{}: {}".format(expr.group('label'), val))
110
111
112 if fail:
113     sys.exit(1)
114 sys.exit(0)