d11452ae72dc072e0c5fac7330fd4b29b18e4969
1 /*
2 * SysDB - t/unit/core/store_expr_test.c
3 * Copyright (C) 2015 Sebastian 'tokkee' Harl <sh@tokkee.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
28 #if HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include "core/plugin.h"
33 #include "core/store.h"
34 #include "core/store-private.h"
35 #include "parser/parser.h"
36 #include "testutils.h"
38 #include <check.h>
40 static sdb_store_t *store;
42 static void
43 populate(void)
44 {
45 const char *hosts[] = { "a", "b", "c" };
47 struct {
48 const char *host;
49 const char *metric;
50 } metrics[] = {
51 { "a", "m1" },
52 { "b", "m1" },
53 { "b", "m2" },
54 };
56 struct {
57 const char *host;
58 const char *service;
59 } services[] = {
60 { "a", "s1" },
61 { "a", "s2" },
62 { "b", "s1" },
63 { "b", "s3" },
64 };
66 struct {
67 const char *host;
68 const char *name;
69 sdb_data_t value;
70 } attrs[] = {
71 { "a", "k1", { SDB_TYPE_STRING, { .string = "v1" } } },
72 { "a", "k2", { SDB_TYPE_INTEGER, { .integer = 123 } } },
73 { "b", "k1", { SDB_TYPE_STRING, { .string = "v2" } } },
74 };
76 struct {
77 const char *host;
78 const char *service;
79 const char *name;
80 sdb_data_t value;
81 } svc_attrs[] = {
82 { "a", "s1", "k1", { SDB_TYPE_STRING, { .string = "v1" } } },
83 { "a", "s2", "k2", { SDB_TYPE_INTEGER, { .integer = 123 } } },
84 };
86 struct {
87 const char *host;
88 const char *metric;
89 const char *name;
90 sdb_data_t value;
91 } metric_attrs[] = {
92 { "b", "m2", "k1", { SDB_TYPE_STRING, { .string = "v1" } } },
93 { "b", "m2", "k2", { SDB_TYPE_INTEGER, { .integer = 123 } } },
94 };
96 size_t i;
98 store = sdb_store_create();
99 ck_assert(store != NULL);
101 for (i = 0; i < SDB_STATIC_ARRAY_LEN(hosts); ++i) {
102 int status = sdb_store_host(store, hosts[i], 1);
103 ck_assert(status == 0);
104 }
106 for (i = 0; i < SDB_STATIC_ARRAY_LEN(metrics); ++i) {
107 int status = sdb_store_metric(store, metrics[i].host,
108 metrics[i].metric, /* store */ NULL, 1);
109 ck_assert(status == 0);
110 }
112 for (i = 0; i < SDB_STATIC_ARRAY_LEN(services); ++i) {
113 int status = sdb_store_service(store, services[i].host,
114 services[i].service, 1);
115 ck_assert(status == 0);
116 }
118 for (i = 0; i < SDB_STATIC_ARRAY_LEN(attrs); ++i) {
119 int status = sdb_store_attribute(store, attrs[i].host,
120 attrs[i].name, &attrs[i].value, 1);
121 ck_assert(status == 0);
122 }
124 for (i = 0; i < SDB_STATIC_ARRAY_LEN(svc_attrs); ++i) {
125 int status = sdb_store_service_attr(store, svc_attrs[i].host,
126 svc_attrs[i].service, svc_attrs[i].name,
127 &svc_attrs[i].value, 1);
128 ck_assert(status == 0);
129 }
131 for (i = 0; i < SDB_STATIC_ARRAY_LEN(metric_attrs); ++i) {
132 int status = sdb_store_metric_attr(store, metric_attrs[i].host,
133 metric_attrs[i].metric, metric_attrs[i].name,
134 &metric_attrs[i].value, 1);
135 ck_assert(status == 0);
136 }
137 } /* populate */
139 static void
140 turndown(void)
141 {
142 sdb_object_deref(SDB_OBJ(store));
143 store = NULL;
144 } /* turndown */
146 #define NAME { SDB_TYPE_INTEGER, { .integer = SDB_FIELD_NAME } }
147 #define LAST_UPDATE { SDB_TYPE_INTEGER, { .integer = SDB_FIELD_LAST_UPDATE } }
148 #define AGE { SDB_TYPE_INTEGER, { .integer = SDB_FIELD_AGE } }
149 #define INTERVAL { SDB_TYPE_INTEGER, { .integer = SDB_FIELD_INTERVAL } }
150 #define BACKENDS { SDB_TYPE_INTEGER, { .integer = SDB_FIELD_BACKEND } }
151 #define HOSTS { SDB_TYPE_INTEGER, { .integer = SDB_HOST } }
152 #define SERVICES { SDB_TYPE_INTEGER, { .integer = SDB_SERVICE } }
153 #define METRICS { SDB_TYPE_INTEGER, { .integer = SDB_METRIC } }
154 #define ATTRS { SDB_TYPE_INTEGER, { .integer = SDB_ATTRIBUTE } }
155 static sdb_store_expr_t namer = {
156 SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, NAME,
157 };
158 static int64_t int_values[] = { 1, 2, 3, 4, 5 };
159 static double dec_values[] = { 47.0, 11.0, 32.0, 64.0 };
160 static char *str_values[] = { "foo", "bar", "qux" };
161 static sdb_time_t dt_values[] = { 4711L, 1234567890L };
162 static struct {
163 size_t length;
164 unsigned char *datum;
165 } bin_values[] = { { 4, (unsigned char *)"\3\2\0\1" } };
166 struct {
167 sdb_store_expr_t expr;
168 bool iterable;
170 char *host;
171 int child_type;
172 char *child; /* optional */
173 char *filter; /* optional */
175 sdb_data_t expected[5];
176 size_t expected_len;
177 } expr_iter_data[] = {
178 /* iterate host children */
179 {
180 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, SERVICES }, true,
181 "a", -1, NULL, NULL,
182 {
183 { SDB_TYPE_STRING, { .string = "s1" } },
184 { SDB_TYPE_STRING, { .string = "s2" } },
185 { 0 },
186 { 0 },
187 { 0 },
188 }, 2,
189 },
190 {
191 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, SERVICES }, true,
192 "b", -1, NULL, NULL,
193 {
194 { SDB_TYPE_STRING, { .string = "s1" } },
195 { SDB_TYPE_STRING, { .string = "s3" } },
196 { 0 },
197 { 0 },
198 { 0 },
199 }, 2,
200 },
201 {
202 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, SERVICES }, true,
203 "a", -1, NULL, "name = 'a' OR name = 's1'",
204 {
205 { SDB_TYPE_STRING, { .string = "s1" } },
206 { 0 },
207 { 0 },
208 { 0 },
209 { 0 },
210 }, 1,
211 },
212 {
213 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, SERVICES }, true,
214 "a", -1, NULL, "name = 'a' OR name = 's2'",
215 {
216 { SDB_TYPE_STRING, { .string = "s2" } },
217 { 0 },
218 { 0 },
219 { 0 },
220 { 0 },
221 }, 1,
222 },
223 {
224 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, SERVICES }, true,
225 "a", -1, NULL, "name = 'a'",
226 {
227 { 0 },
228 { 0 },
229 { 0 },
230 { 0 },
231 { 0 },
232 }, 0,
233 },
234 {
235 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, METRICS }, true,
236 "a", -1, NULL, NULL,
237 {
238 { SDB_TYPE_STRING, { .string = "m1" } },
239 { 0 },
240 { 0 },
241 { 0 },
242 { 0 },
243 }, 1,
244 },
245 {
246 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, METRICS }, true,
247 "a", -1, NULL, "name = 'a' OR name = 'm1'",
248 {
249 { SDB_TYPE_STRING, { .string = "m1" } },
250 { 0 },
251 { 0 },
252 { 0 },
253 { 0 },
254 }, 1,
255 },
256 {
257 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, METRICS }, true,
258 "a", -1, NULL, "name = 'a' OR name = 'm2'",
259 {
260 { 0 },
261 { 0 },
262 { 0 },
263 { 0 },
264 { 0 },
265 }, 0,
266 },
267 {
268 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, METRICS }, true,
269 "a", -1, NULL, "name = 'a'",
270 {
271 { 0 },
272 { 0 },
273 { 0 },
274 { 0 },
275 { 0 },
276 }, 0,
277 },
278 {
279 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, ATTRS }, true,
280 "a", -1, NULL, NULL,
281 {
282 { SDB_TYPE_STRING, { .string = "k1" } },
283 { SDB_TYPE_STRING, { .string = "k2" } },
284 { 0 },
285 { 0 },
286 { 0 },
287 }, 2,
288 },
289 {
290 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, HOSTS }, false,
291 "a", -1, NULL, NULL,
292 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
293 },
294 /* host fields */
295 {
296 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, BACKENDS }, true,
297 "a", -1, NULL, NULL,
298 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
299 },
300 {
301 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, NAME }, false,
302 "a", -1, NULL, NULL,
303 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
304 },
305 {
306 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, LAST_UPDATE }, false,
307 "a", -1, NULL, NULL,
308 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
309 },
310 {
311 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, AGE }, false,
312 "a", -1, NULL, NULL,
313 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
314 },
315 {
316 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, INTERVAL }, false,
317 "a", -1, NULL, NULL,
318 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
319 },
320 /* service children */
321 {
322 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, ATTRS }, true,
323 "a", SDB_SERVICE, "s1", NULL,
324 {
325 { SDB_TYPE_STRING, { .string = "hostname" } },
326 { SDB_TYPE_STRING, { .string = "k1" } },
327 { 0 },
328 { 0 },
329 { 0 },
330 }, 2,
331 },
332 {
333 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, ATTRS }, true,
334 "a", SDB_SERVICE, "s1", "age >= 0s",
335 {
336 { SDB_TYPE_STRING, { .string = "hostname" } },
337 { SDB_TYPE_STRING, { .string = "k1" } },
338 { 0 },
339 { 0 },
340 { 0 },
341 }, 2,
342 },
343 {
344 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, ATTRS }, true,
345 "a", SDB_SERVICE, "s1", "age < 0s",
346 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }, 0,
347 },
348 {
349 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, HOSTS }, false,
350 "a", SDB_SERVICE, "s1", NULL,
351 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }, 0,
352 },
353 {
354 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, SERVICES }, false,
355 "a", SDB_SERVICE, "s1", NULL,
356 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }, 0,
357 },
358 {
359 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, METRICS }, false,
360 "a", SDB_SERVICE, "s1", NULL,
361 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }, 0,
362 },
363 /* service fields */
364 {
365 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, BACKENDS }, true,
366 "a", SDB_SERVICE, "s1", NULL,
367 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
368 },
369 {
370 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, NAME }, false,
371 "a", SDB_SERVICE, "s1", NULL,
372 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
373 },
374 {
375 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, LAST_UPDATE }, false,
376 "a", SDB_SERVICE, "s1", NULL,
377 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
378 },
379 {
380 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, AGE }, false,
381 "a", SDB_SERVICE, "s1", NULL,
382 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
383 },
384 {
385 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, INTERVAL }, false,
386 "a", SDB_SERVICE, "s1", NULL,
387 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
388 },
389 /* metric children */
390 {
391 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, ATTRS }, true,
392 "b", SDB_METRIC, "m2", NULL,
393 {
394 { SDB_TYPE_STRING, { .string = "hostname" } },
395 { SDB_TYPE_STRING, { .string = "k1" } },
396 { SDB_TYPE_STRING, { .string = "k2" } },
397 { 0 },
398 { 0 },
399 }, 3,
400 },
401 {
402 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, ATTRS }, true,
403 "b", SDB_METRIC, "m2", "age >= 0s",
404 {
405 { SDB_TYPE_STRING, { .string = "hostname" } },
406 { SDB_TYPE_STRING, { .string = "k1" } },
407 { SDB_TYPE_STRING, { .string = "k2" } },
408 { 0 },
409 { 0 },
410 }, 3,
411 },
412 {
413 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, ATTRS }, true,
414 "b", SDB_METRIC, "m2", "name = 'b' OR name = 'm2' OR name = 'k2'",
415 {
416 { SDB_TYPE_STRING, { .string = "k2" } },
417 { 0 },
418 { 0 },
419 { 0 },
420 { 0 },
421 }, 1,
422 },
423 {
424 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, ATTRS }, true,
425 "b", SDB_METRIC, "m2", "age < 0s",
426 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }, 0,
427 },
428 {
429 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, HOSTS }, false,
430 "b", SDB_METRIC, "m2", NULL,
431 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }, 0,
432 },
433 {
434 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, SERVICES }, false,
435 "b", SDB_METRIC, "m2", NULL,
436 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }, 0,
437 },
438 {
439 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, METRICS }, false,
440 "b", SDB_METRIC, "m2", NULL,
441 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }, 0,
442 },
443 /* metric fields */
444 {
445 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, BACKENDS }, true,
446 "b", SDB_METRIC, "m2", NULL,
447 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
448 },
449 {
450 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, NAME }, false,
451 "b", SDB_METRIC, "m2", NULL,
452 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
453 },
454 {
455 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, LAST_UPDATE }, false,
456 "b", SDB_METRIC, "m2", NULL,
457 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
458 },
459 {
460 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, AGE }, false,
461 "b", SDB_METRIC, "m2", NULL,
462 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
463 },
464 {
465 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, INTERVAL }, false,
466 "b", SDB_METRIC, "m2", NULL,
467 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
468 },
469 /* arrays */
470 {
471 {
472 SDB_OBJECT_INIT, 0, -1, NULL, NULL,
473 {
474 SDB_TYPE_INTEGER | SDB_TYPE_ARRAY,
475 { .array = { SDB_STATIC_ARRAY_LEN(int_values), int_values } },
476 },
477 }, true,
478 NULL, -1, NULL, NULL,
479 {
480 { SDB_TYPE_INTEGER, { .integer = 1 } },
481 { SDB_TYPE_INTEGER, { .integer = 2 } },
482 { SDB_TYPE_INTEGER, { .integer = 3 } },
483 { SDB_TYPE_INTEGER, { .integer = 4 } },
484 { SDB_TYPE_INTEGER, { .integer = 5 } },
485 }, 5,
486 },
487 {
488 {
489 SDB_OBJECT_INIT, 0, -1, NULL, NULL,
490 {
491 SDB_TYPE_DECIMAL | SDB_TYPE_ARRAY,
492 { .array = { SDB_STATIC_ARRAY_LEN(dec_values), dec_values } },
493 },
494 }, true,
495 NULL, -1, NULL, NULL,
496 {
497 { SDB_TYPE_DECIMAL, { .decimal = 47.0 } },
498 { SDB_TYPE_DECIMAL, { .decimal = 11.0 } },
499 { SDB_TYPE_DECIMAL, { .decimal = 32.0 } },
500 { SDB_TYPE_DECIMAL, { .decimal = 64.0 } },
501 { 0 },
502 }, 4,
503 },
504 {
505 {
506 SDB_OBJECT_INIT, 0, -1, NULL, NULL,
507 {
508 SDB_TYPE_STRING | SDB_TYPE_ARRAY,
509 { .array = { SDB_STATIC_ARRAY_LEN(str_values), str_values } },
510 },
511 }, true,
512 NULL, -1, NULL, NULL,
513 {
514 { SDB_TYPE_STRING, { .string = "foo" } },
515 { SDB_TYPE_STRING, { .string = "bar" } },
516 { SDB_TYPE_STRING, { .string = "qux" } },
517 { 0 },
518 { 0 },
519 }, 3,
520 },
521 {
522 {
523 SDB_OBJECT_INIT, 0, -1, NULL, NULL,
524 {
525 SDB_TYPE_DATETIME | SDB_TYPE_ARRAY,
526 { .array = { SDB_STATIC_ARRAY_LEN(dt_values), dt_values } },
527 },
528 }, true,
529 NULL, -1, NULL, NULL,
530 {
531 { SDB_TYPE_DATETIME, { .datetime = 4711L } },
532 { SDB_TYPE_DATETIME, { .datetime = 1234567890L } },
533 { 0 },
534 { 0 },
535 { 0 },
536 }, 2,
537 },
538 {
539 {
540 SDB_OBJECT_INIT, 0, -1, NULL, NULL,
541 {
542 SDB_TYPE_BINARY | SDB_TYPE_ARRAY,
543 { .array = { SDB_STATIC_ARRAY_LEN(bin_values), bin_values } },
544 },
545 }, true,
546 NULL, -1, NULL, NULL,
547 {
548 { SDB_TYPE_BINARY, { .binary = { 4, (unsigned char *)"\3\2\0\1" } } },
549 { 0 },
550 { 0 },
551 { 0 },
552 { 0 },
553 }, 1,
554 },
555 };
557 START_TEST(test_expr_iter)
558 {
559 sdb_store_obj_t *obj = NULL;
560 sdb_store_matcher_t *filter = NULL;
561 int context = SDB_HOST;
563 sdb_store_expr_iter_t *iter;
564 size_t i;
566 if (expr_iter_data[_i].host) {
567 obj = sdb_store_get_host(store, expr_iter_data[_i].host);
568 ck_assert(obj != NULL);
570 if (expr_iter_data[_i].child) {
571 sdb_store_obj_t *child = sdb_store_get_child(obj,
572 expr_iter_data[_i].child_type, expr_iter_data[_i].child);
573 ck_assert(child != NULL);
574 sdb_object_deref(SDB_OBJ(obj));
575 obj = child;
576 context = expr_iter_data[_i].child_type;
577 }
578 ck_assert(obj->type == context);
579 }
581 if (expr_iter_data[_i].filter) {
582 sdb_ast_node_t *ast;
583 ast = sdb_parser_parse_conditional(context, expr_iter_data[_i].filter, -1, NULL);
584 filter = sdb_store_query_prepare_matcher(ast);
585 sdb_object_deref(SDB_OBJ(ast));
586 ck_assert(filter != NULL);
587 }
589 iter = sdb_store_expr_iter(&expr_iter_data[_i].expr, obj, filter);
590 fail_unless((iter != NULL) == expr_iter_data[_i].iterable,
591 "sdb_store_expr_iter(%s expression, %s, %s) = %s; expected: %s",
592 EXPR_TO_STRING(&expr_iter_data[_i].expr),
593 obj ? SDB_STORE_TYPE_TO_NAME(obj->type) : "<array>",
594 expr_iter_data[_i].filter, iter ? "<iter>" : "NULL",
595 expr_iter_data[_i].iterable ? "<iter>" : "NULL");
597 /* the iterator will keep a reference */
598 sdb_object_deref(SDB_OBJ(obj)); obj = NULL;
599 sdb_object_deref(SDB_OBJ(filter)); filter = NULL;
601 i = 0;
602 while (sdb_store_expr_iter_has_next(iter)) {
603 char v_str[64], expected_str[64];
604 sdb_data_t v;
606 fail_unless(i < expr_iter_data[_i].expected_len,
607 "iter<%s expression, %s, %s> returned >= %zu elements; "
608 "expected: %zu", EXPR_TO_STRING(&expr_iter_data[_i].expr),
609 SDB_STORE_TYPE_TO_NAME(context), expr_iter_data[_i].filter,
610 i + 1, expr_iter_data[_i].expected_len);
612 v = sdb_store_expr_iter_get_next(iter);
613 sdb_data_format(&v, v_str, sizeof(v_str), SDB_DOUBLE_QUOTED);
614 sdb_data_format(&expr_iter_data[_i].expected[i],
615 expected_str, sizeof(expected_str), SDB_DOUBLE_QUOTED);
616 fail_unless(sdb_data_cmp(&v, &expr_iter_data[_i].expected[i]) == 0,
617 "iter<%s expression, %s, %s>, elem %zu = %s; expected: %s",
618 EXPR_TO_STRING(&expr_iter_data[_i].expr),
619 SDB_STORE_TYPE_TO_NAME(context), expr_iter_data[_i].filter,
620 i, v_str, expected_str);
622 sdb_data_free_datum(&v);
623 ++i;
624 }
626 fail_unless(i == expr_iter_data[_i].expected_len,
627 "iter<%s expression, %s, %s> returned %zu elements; "
628 "expected: %zu", EXPR_TO_STRING(&expr_iter_data[_i].expr),
629 SDB_STORE_TYPE_TO_NAME(context), expr_iter_data[_i].filter,
630 i, expr_iter_data[_i].expected_len);
631 fail_unless(sdb_store_expr_iter_get_next(iter).type == SDB_TYPE_NULL,
632 "iter<%s expression, %s, %s> returned further elements "
633 "passed the end", EXPR_TO_STRING(&expr_iter_data[_i].expr),
634 SDB_STORE_TYPE_TO_NAME(context), expr_iter_data[_i].filter);
636 sdb_store_expr_iter_destroy(iter);
637 }
638 END_TEST
640 TEST_MAIN("core::store_expr")
641 {
642 TCase *tc = tcase_create("core");
643 tcase_add_checked_fixture(tc, populate, turndown);
644 TC_ADD_LOOP_TEST(tc, expr_iter);
645 ADD_TCASE(tc);
646 }
647 TEST_MAIN_END
649 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */