1 #include "jqp.h"
2 #include "ejdb2_internal.h"
3 #include <ejdb2/iowow/iwxstr.h>
4 #include <ejdb2/iowow/iwutils.h>
5 #include <CUnit/Basic.h>
6 #include <stdlib.h>
7
init_suite(void)8 int init_suite(void) {
9 int rc = ejdb_init();
10 return rc;
11 }
12
clean_suite(void)13 int clean_suite(void) {
14 return 0;
15 }
16
_jql_test1_1(int num,iwrc expected)17 void _jql_test1_1(int num, iwrc expected) {
18 fprintf(stderr, "%03d.jql\n", num);
19
20 iwrc rc;
21 char path[64];
22 char path_expected[64];
23 JQP_AUX *aux;
24 char *data, *edata = 0;
25 IWXSTR *res = iwxstr_new();
26 CU_ASSERT_PTR_NOT_NULL_FATAL(res);
27
28 snprintf(path, sizeof(path), "data%c%03d.jql", IW_PATH_CHR, num);
29 snprintf(path_expected, sizeof(path_expected), "data%c%03d.expected.jql", IW_PATH_CHR, num);
30 data = iwu_file_read_as_buf(path);
31 CU_ASSERT_PTR_NOT_NULL_FATAL(data);
32
33 rc = jqp_aux_create(&aux, data);
34 CU_ASSERT_EQUAL_FATAL(rc, 0);
35
36 rc = jqp_parse(aux);
37 CU_ASSERT_EQUAL_FATAL(rc, expected);
38 if (expected) {
39 goto finish;
40 }
41
42 CU_ASSERT_PTR_NOT_NULL_FATAL(aux->query);
43
44 edata = iwu_file_read_as_buf(path_expected);
45 CU_ASSERT_PTR_NOT_NULL_FATAL(edata);
46 rc = jqp_print_query(aux->query, jbl_xstr_json_printer, res);
47 CU_ASSERT_EQUAL_FATAL(rc, 0);
48
49 // fprintf(stderr, "%s\n", iwxstr_ptr(res));
50 // fprintf(stderr, "%s\n", path_expected);
51 // fprintf(stderr, "%s\n", edata);
52
53 // fprintf(stderr, "%d\n", strcmp(edata, iwxstr_ptr(res)));
54 // FILE *out = fopen("out.txt", "w+");
55 // fprintf(out, "%s", iwxstr_ptr(res));
56 // fclose(out);
57
58 CU_ASSERT_EQUAL_FATAL(strcmp(edata, iwxstr_ptr(res)), 0);
59
60 finish:
61 if (edata) {
62 free(edata);
63 }
64 free(data);
65 iwxstr_destroy(res);
66 jqp_aux_destroy(&aux);
67 }
68
jql_test1_1()69 void jql_test1_1() {
70
71 _jql_test1_1(22, 0);
72
73 for (int i = 0; i <= 10; ++i) {
74 _jql_test1_1(i, 0);
75 }
76 for (int i = 11; i <= 13; ++i) {
77 _jql_test1_1(i, JQL_ERROR_QUERY_PARSE);
78 }
79 for (int i = 14; i <= 22; ++i) {
80 _jql_test1_1(i, 0);
81 }
82 }
83
_jql_test1_2(const char * jsondata,const char * q,bool match)84 static void _jql_test1_2(const char *jsondata, const char *q, bool match) {
85 JBL jbl;
86 JQL jql;
87 char *json = iwu_replace_char(strdup(jsondata), '\'', '"');
88 CU_ASSERT_PTR_NOT_NULL_FATAL(json);
89 iwrc rc = jql_create(&jql, "c1", q);
90 CU_ASSERT_EQUAL_FATAL(rc, 0);
91 rc = jbl_from_json(&jbl, json);
92 CU_ASSERT_EQUAL_FATAL(rc, 0);
93 bool m = false;
94 rc = jql_matched(jql, jbl, &m);
95 CU_ASSERT_EQUAL_FATAL(rc, 0);
96 CU_ASSERT_EQUAL_FATAL(m, match);
97
98 jql_destroy(&jql);
99 jbl_destroy(&jbl);
100 free(json);
101 }
102
jql_test1_2()103 void jql_test1_2() {
104 _jql_test1_2("{}", "/*", true);
105 _jql_test1_2("{}", "/**", true);
106 _jql_test1_2("{'foo':{'bar':22}}", "/*", true);
107 _jql_test1_2("{'foo':{'bar':22}}", "/**", true);
108 _jql_test1_2("{'foo':{'bar':22}}", "/foo/bar", true);
109 _jql_test1_2("{'foo':{'bar':22}}", "/foo/baz", false);
110 _jql_test1_2("{'foo':{'bar':22}}", "/foo/bar and /foo/bar or /foo", true);
111 _jql_test1_2("{'foo':{'bar':22}}", "/foo/baz or /foo", true);
112 _jql_test1_2("{'foo':{'bar':22}}", "/foo/baz and (/foo/daz or /foo/bar)", false);
113 _jql_test1_2("{'foo':{'bar':22}}", "(/boo or /foo) and (/foo/daz or /foo/bar)", true);
114 _jql_test1_2("{'foo':{'bar':22, 'bar2':'vvv2'}}", "/foo/bar2", true);
115
116 _jql_test1_2("{'foo':{'bar':22}}", "/foo/[bar = 22]", true);
117 _jql_test1_2("{'foo':{'bar':22}}", "/foo/[bar eq 22]", true);
118 _jql_test1_2("{'foo':{'bar':22}}", "/foo/[bar !eq 22]", false);
119 _jql_test1_2("{'foo':{'bar':22}}", "/foo/[bar != 22]", false);
120 _jql_test1_2("{'foo':{'bar':22}}", "/foo/[bar >= 22]", true);
121 _jql_test1_2("{'foo':{'bar':22}}", "/*/[bar >= 22]", true);
122 _jql_test1_2("{'foo':{'bar':22}}", "/foo/[bar > 21]", true);
123 _jql_test1_2("{'foo':{'bar':22}}", "/foo/[bar > 22]", false);
124 _jql_test1_2("{'foo':{'bar':22}}", "/foo/[bar < 23]", true);
125 _jql_test1_2("{'foo':{'bar':22}}", "/foo/[bar <= 22]", true);
126 _jql_test1_2("{'foo':{'bar':22}}", "/foo/[bar < 22]", false);
127 _jql_test1_2("{'foo':{'bar':22}}", "/*/[bar < 22]", false);
128 _jql_test1_2("{'foo':{'bar':22}}", "/*/[bar > 20 and bar <= 23]", true);
129 _jql_test1_2("{'foo':{'bar':22}}", "/*/[bar > 22 and bar <= 23]", false);
130 _jql_test1_2("{'foo':{'bar':22}}", "/*/[bar > 23 or bar < 23]", true);
131 _jql_test1_2("{'foo':{'bar':22}}", "/*/[bar < 23 or bar > 23]", true);
132 _jql_test1_2("{'foo':{'bar':22}}", "/foo/[[* = bar] = 22]", true);
133 _jql_test1_2("{'foo':{'bar':22}}", "/foo/[[* = bar] != 23]", true);
134 _jql_test1_2("{'foo':{'bar':22}}", "/[* = foo]/[[* = bar] != 23]", true);
135 _jql_test1_2("{'foo':{'bar':22}}", "/[* != foo]/[[* = bar] != 23]", false);
136
137 // regexp
138 _jql_test1_2("{'foo':{'bar':22}}", "/[* re \"foo\"]", true);
139 _jql_test1_2("{'foo':{'bar':22}}", "/[* re fo]", true);
140 _jql_test1_2("{'foo':{'bar':22}}", "/[* re ^foo$]", true);
141 _jql_test1_2("{'foo':{'bar':22}}", "/[* re ^fo$]", false);
142 _jql_test1_2("{'foo':{'bar':22}}", "/[* not re ^fo$]", true);
143 _jql_test1_2("{'foo':{'bar':22}}", "/foo/[bar re 22]", true);
144 _jql_test1_2("{'foo':{'bar':22}}", "/foo/[bar re \"2+\"]", true);
145
146 // in
147 _jql_test1_2("{'foo':{'bar':22}}", "/foo/[bar in [21, \"22\"]]", true);
148 _jql_test1_2("{'foo':{'bar':22}}", "/foo/[bar in [21, 23]]", false);
149 _jql_test1_2("{'foo':{'bar':22}}", "/[* in [\"foo\"]]/[bar in [21, 22]]", true);
150 _jql_test1_2("{'foo':{'bar':22}}", "/[* not in [\"foo\"]]/[bar in [21, 22]]", false);
151
152 // Array element
153 _jql_test1_2("{'tags':['bar', 'foo']}", "/tags/[** in [\"bar\", \"baz\"]]", true);
154 _jql_test1_2("{'tags':['bar', 'foo']}", "/tags/[** in [\"zaz\", \"gaz\"]]", false);
155
156 // /**
157 _jql_test1_2("{'foo':{'bar':22}}", "/**", true);
158 _jql_test1_2("{'foo':{'bar':22}}", "/**/bar", true);
159 _jql_test1_2("{'foo':{'bar':22}}", "/**/baz", false);
160 _jql_test1_2("{'foo':{'bar':22}}", "/**/**/bar", true);
161 _jql_test1_2("{'foo':{'bar':22, 'baz':{'zaz':33}}}", "/foo/**/zaz", true);
162 _jql_test1_2("{'foo':{'bar':22, 'baz':{'zaz':33}}}", "/foo/**/[zaz > 30]", true);
163 _jql_test1_2("{'foo':{'bar':22, 'baz':{'zaz':33}}}", "/foo/**/[zaz < 30]", false);
164
165 // arr/obj
166 _jql_test1_2("{'foo':[1,2]}", "/[foo = [1,2]]", true);
167 _jql_test1_2("{'foo':[1,2]}", "/[foo ni 2]", true);
168 _jql_test1_2("{'foo':[1,2]}", "/[foo in [[1,2]]]", true);
169 _jql_test1_2("{'foo':{'arr':[1,2,3,4]}}", "/foo/[arr = [1,2,3,4]]", true);
170 _jql_test1_2("{'foo':{'arr':[1,2,3,4]}}", "/foo/**/[arr = [1,2,3,4]]", true);
171 _jql_test1_2("{'foo':{'arr':[1,2,3,4]}}", "/foo/*/[arr = [1,2,3,4]]", false);
172 _jql_test1_2("{'foo':{'arr':[1,2,3,4]}}", "/foo/[arr = [1,2,3]]", false);
173 _jql_test1_2("{'foo':{'arr':[1,2,3,4]}}", "/foo/[arr = [1,12,3,4]]", false);
174 _jql_test1_2("{'foo':{'obj':{'f':'d','e':'j'}}}", "/foo/[obj = {\"e\":\"j\",\"f\":\"d\"}]", true);
175 _jql_test1_2("{'foo':{'obj':{'f':'d','e':'j'}}}", "/foo/[obj = {\"e\":\"j\",\"f\":\"dd\"}]", false);
176
177 _jql_test1_2("{'f':22}", "/f", true);
178 _jql_test1_2("{'a':'bar'}", "/f | asc /f", false);
179
180 // PK
181 _jql_test1_2("{'f':22}", "/=22", true);
182 _jql_test1_2("{'f':22}", "@mycoll/=22", true);
183
184 //
185 const char *doc
186 = "{"
187 " 'foo':{"
188 " 'bar': {'baz':{'zaz':33}},"
189 " 'sas': {'gaz':{'zaz':44, 'zarr':[42]}},"
190 " 'arr': [1,2,3,4]"
191 " }"
192 "}";
193 _jql_test1_2(doc, "/foo/sas/gaz/zaz", true);
194 _jql_test1_2(doc, "/foo/sas/gaz/[zaz = 44]", true);
195 _jql_test1_2(doc, "/**/[zaz = 44]", true);
196 _jql_test1_2(doc, "/foo/**/[zaz = 44]", true);
197 _jql_test1_2(doc, "/foo/*/*/[zaz = 44]", true);
198 _jql_test1_2(doc, "/foo/[arr ni 3]", true);
199 _jql_test1_2(doc, "/**/[zarr ni 42]", true);
200 _jql_test1_2(doc, "/**/[[* in [\"zarr\"]] in [[42]]]", true);
201 }
202
_jql_test1_3(bool has_apply_or_project,const char * jsondata,const char * q,const char * eq)203 static void _jql_test1_3(bool has_apply_or_project, const char *jsondata, const char *q, const char *eq) {
204 JBL jbl;
205 JQL jql;
206 JBL_NODE out = 0, eqn = 0;
207 IWPOOL *pool = iwpool_create(512);
208
209 char *json = iwu_replace_char(strdup(jsondata), '\'', '"');
210 CU_ASSERT_PTR_NOT_NULL_FATAL(json);
211 char *eqjson = iwu_replace_char(strdup(eq), '\'', '"');
212 CU_ASSERT_PTR_NOT_NULL_FATAL(eqjson);
213 char *qstr = iwu_replace_char(strdup(q), '\'', '"');
214 CU_ASSERT_PTR_NOT_NULL_FATAL(qstr);
215
216 iwrc rc = jql_create(&jql, "c1", qstr);
217 CU_ASSERT_EQUAL_FATAL(rc, 0);
218 rc = jbl_from_json(&jbl, json);
219 CU_ASSERT_EQUAL_FATAL(rc, 0);
220 bool m = false;
221 rc = jql_matched(jql, jbl, &m);
222 CU_ASSERT_EQUAL_FATAL(rc, 0);
223 CU_ASSERT_EQUAL_FATAL(m, true);
224
225 bool hapl = jql_has_apply(jql) || jql_has_projection(jql);
226 CU_ASSERT_EQUAL_FATAL(hapl, has_apply_or_project);
227 if (!hapl) {
228 goto finish;
229 }
230
231 CU_ASSERT_PTR_NOT_NULL_FATAL(pool);
232 rc = jql_apply_and_project(jql, jbl, &out, 0, pool);
233 CU_ASSERT_EQUAL_FATAL(rc, 0);
234 CU_ASSERT_PTR_NOT_NULL_FATAL(out);
235
236 rc = jbn_from_json(eqjson, &eqn, pool);
237 CU_ASSERT_EQUAL_FATAL(rc, 0);
238
239 int cmp = jbn_compare_nodes(out, eqn, &rc);
240 CU_ASSERT_EQUAL_FATAL(rc, 0);
241 CU_ASSERT_EQUAL_FATAL(cmp, 0);
242
243 finish:
244 jql_destroy(&jql);
245 jbl_destroy(&jbl);
246 free(json);
247 free(eqjson);
248 free(qstr);
249 iwpool_destroy(pool);
250 }
251
jql_test1_3()252 void jql_test1_3() {
253
254 _jql_test1_3(true, "{'foo':{'bar':22}}",
255 "/foo/bar | apply [{'op':'add', 'path':'/baz', 'value':'qux'}]",
256 "{'foo':{'bar':22},'baz':'qux'}");
257
258 _jql_test1_3(true, "{'foo':{'bar':22}}",
259 "/foo/bar | apply {'baz':'qux'}",
260 "{'foo':{'bar':22},'baz':'qux'}");
261 }
262
263 // Test projections
jql_test_1_4()264 void jql_test_1_4() {
265
266 _jql_test1_3(false, "{'foo':{'bar':22}}", "/** | all", "{'foo':{'bar':22}}");
267 _jql_test1_3(false, "{'foo':{'bar':22}}", "/** | all+all + all", "{'foo':{'bar':22}}");
268 _jql_test1_3(true, "{'foo':{'bar':22}}", "/** | all - all", "{}");
269 _jql_test1_3(true, "{'foo':{'bar':22}}", "/** | all-all +all", "{}");
270 _jql_test1_3(true, "{'foo':{'bar':22}}", "/** | /foo/bar", "{'foo':{'bar':22}}");
271 _jql_test1_3(true, "{'foo':{'bar':22, 'baz':'gaz'}}", "/** | /foo/bar", "{'foo':{'bar':22}}");
272 _jql_test1_3(true, "{'foo':{'bar':22, 'baz':'gaz'}}", "/** | /foo/{daz,bar}", "{'foo':{'bar':22}}");
273 _jql_test1_3(true, "{'foo':{'bar':22, 'baz':{'gaz':444, 'zaz':555}}}", "/** | /foo/bar + /foo/baz/zaz",
274 "{'foo':{'bar':22, 'baz':{'zaz':555}}}");
275 _jql_test1_3(true, "{'foo':{'bar':22, 'baz':{'gaz':444, 'zaz':555}}}", "/** | /foo/bar + /foo/baz/zaz - /*/bar",
276 "{'foo':{'baz':{'zaz':555}}}");
277 _jql_test1_3(true, "{'foo':{'bar':22, 'baz':{'gaz':444, 'zaz':555}}}", "/** | all + /foo/bar + /foo/baz/zaz - /*/bar",
278 "{'foo':{'baz':{'zaz':555}}}");
279 _jql_test1_3(true, "{'foo':{'bar':22}}", "/** | /zzz", "{}");
280 _jql_test1_3(true, "{'foo':{'bar':22}}", "/** | /fooo", "{}");
281 _jql_test1_3(true, "{'foo':{'bar':22},'name':'test'}", "/** | all - /name", "{'foo':{'bar':22}}");
282 }
283
main()284 int main() {
285 CU_pSuite pSuite = NULL;
286 if (CUE_SUCCESS != CU_initialize_registry()) {
287 return CU_get_error();
288 }
289 pSuite = CU_add_suite("jql_test1", init_suite, clean_suite);
290 if (NULL == pSuite) {
291 CU_cleanup_registry();
292 return CU_get_error();
293 }
294 if ( (NULL == CU_add_test(pSuite, "jql_test1_1", jql_test1_1))
295 || (NULL == CU_add_test(pSuite, "jql_test1_2", jql_test1_2))
296 || (NULL == CU_add_test(pSuite, "jql_test1_3", jql_test1_3))
297 || (NULL == CU_add_test(pSuite, "jql_test1_4", jql_test_1_4))) {
298 CU_cleanup_registry();
299 return CU_get_error();
300 }
301 CU_basic_set_mode(CU_BRM_VERBOSE);
302 CU_basic_run_tests();
303 int ret = CU_get_error() || CU_get_number_of_failures();
304 CU_cleanup_registry();
305 return ret;
306 }
307