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 void
41 populate(void)
42 {
43 const char *hosts[] = { "a", "b", "c" };
45 struct {
46 const char *host;
47 const char *metric;
48 } metrics[] = {
49 { "a", "m1" },
50 { "b", "m1" },
51 { "b", "m2" },
52 };
54 struct {
55 const char *host;
56 const char *service;
57 } services[] = {
58 { "a", "s1" },
59 { "a", "s2" },
60 { "b", "s1" },
61 { "b", "s3" },
62 };
64 struct {
65 const char *host;
66 const char *name;
67 sdb_data_t value;
68 } attrs[] = {
69 { "a", "k1", { SDB_TYPE_STRING, { .string = "v1" } } },
70 { "a", "k2", { SDB_TYPE_INTEGER, { .integer = 123 } } },
71 { "b", "k1", { SDB_TYPE_STRING, { .string = "v2" } } },
72 };
74 struct {
75 const char *host;
76 const char *service;
77 const char *name;
78 sdb_data_t value;
79 } svc_attrs[] = {
80 { "a", "s1", "k1", { SDB_TYPE_STRING, { .string = "v1" } } },
81 { "a", "s2", "k2", { SDB_TYPE_INTEGER, { .integer = 123 } } },
82 };
84 struct {
85 const char *host;
86 const char *metric;
87 const char *name;
88 sdb_data_t value;
89 } metric_attrs[] = {
90 { "b", "m2", "k1", { SDB_TYPE_STRING, { .string = "v1" } } },
91 { "b", "m2", "k2", { SDB_TYPE_INTEGER, { .integer = 123 } } },
92 };
94 size_t i;
96 sdb_store_init();
98 for (i = 0; i < SDB_STATIC_ARRAY_LEN(hosts); ++i) {
99 int status = sdb_plugin_store_host(hosts[i], 1);
100 ck_assert(status == 0);
101 }
103 for (i = 0; i < SDB_STATIC_ARRAY_LEN(metrics); ++i) {
104 int status = sdb_plugin_store_metric(metrics[i].host,
105 metrics[i].metric, /* store */ NULL, 1);
106 ck_assert(status == 0);
107 }
109 for (i = 0; i < SDB_STATIC_ARRAY_LEN(services); ++i) {
110 int status = sdb_plugin_store_service(services[i].host,
111 services[i].service, 1);
112 ck_assert(status == 0);
113 }
115 for (i = 0; i < SDB_STATIC_ARRAY_LEN(attrs); ++i) {
116 int status = sdb_plugin_store_attribute(attrs[i].host,
117 attrs[i].name, &attrs[i].value, 1);
118 ck_assert(status == 0);
119 }
121 for (i = 0; i < SDB_STATIC_ARRAY_LEN(svc_attrs); ++i) {
122 int status = sdb_plugin_store_service_attribute(svc_attrs[i].host,
123 svc_attrs[i].service, svc_attrs[i].name,
124 &svc_attrs[i].value, 1);
125 ck_assert(status == 0);
126 }
128 for (i = 0; i < SDB_STATIC_ARRAY_LEN(metric_attrs); ++i) {
129 int status = sdb_plugin_store_metric_attribute(metric_attrs[i].host,
130 metric_attrs[i].metric, metric_attrs[i].name,
131 &metric_attrs[i].value, 1);
132 ck_assert(status == 0);
133 }
134 } /* populate */
136 #define NAME { SDB_TYPE_INTEGER, { .integer = SDB_FIELD_NAME } }
137 #define LAST_UPDATE { SDB_TYPE_INTEGER, { .integer = SDB_FIELD_LAST_UPDATE } }
138 #define AGE { SDB_TYPE_INTEGER, { .integer = SDB_FIELD_AGE } }
139 #define INTERVAL { SDB_TYPE_INTEGER, { .integer = SDB_FIELD_INTERVAL } }
140 #define BACKENDS { SDB_TYPE_INTEGER, { .integer = SDB_FIELD_BACKEND } }
141 #define HOSTS { SDB_TYPE_INTEGER, { .integer = SDB_HOST } }
142 #define SERVICES { SDB_TYPE_INTEGER, { .integer = SDB_SERVICE } }
143 #define METRICS { SDB_TYPE_INTEGER, { .integer = SDB_METRIC } }
144 #define ATTRS { SDB_TYPE_INTEGER, { .integer = SDB_ATTRIBUTE } }
145 static sdb_store_expr_t namer = {
146 SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, NAME,
147 };
148 static int64_t int_values[] = { 1, 2, 3, 4, 5 };
149 static double dec_values[] = { 47.0, 11.0, 32.0, 64.0 };
150 static char *str_values[] = { "foo", "bar", "qux" };
151 static sdb_time_t dt_values[] = { 4711L, 1234567890L };
152 static struct {
153 size_t length;
154 unsigned char *datum;
155 } bin_values[] = { { 4, (unsigned char *)"\3\2\0\1" } };
156 struct {
157 sdb_store_expr_t expr;
158 bool iterable;
160 char *host;
161 int child_type;
162 char *child; /* optional */
163 char *filter; /* optional */
165 sdb_data_t expected[5];
166 size_t expected_len;
167 } expr_iter_data[] = {
168 /* iterate host children */
169 {
170 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, SERVICES }, true,
171 "a", -1, NULL, NULL,
172 {
173 { SDB_TYPE_STRING, { .string = "s1" } },
174 { SDB_TYPE_STRING, { .string = "s2" } },
175 { 0 },
176 { 0 },
177 { 0 },
178 }, 2,
179 },
180 {
181 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, SERVICES }, true,
182 "b", -1, NULL, NULL,
183 {
184 { SDB_TYPE_STRING, { .string = "s1" } },
185 { SDB_TYPE_STRING, { .string = "s3" } },
186 { 0 },
187 { 0 },
188 { 0 },
189 }, 2,
190 },
191 {
192 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, SERVICES }, true,
193 "a", -1, NULL, "name = 'a' OR name = 's1'",
194 {
195 { SDB_TYPE_STRING, { .string = "s1" } },
196 { 0 },
197 { 0 },
198 { 0 },
199 { 0 },
200 }, 1,
201 },
202 {
203 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, SERVICES }, true,
204 "a", -1, NULL, "name = 'a' OR name = 's2'",
205 {
206 { SDB_TYPE_STRING, { .string = "s2" } },
207 { 0 },
208 { 0 },
209 { 0 },
210 { 0 },
211 }, 1,
212 },
213 {
214 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, SERVICES }, true,
215 "a", -1, NULL, "name = 'a'",
216 {
217 { 0 },
218 { 0 },
219 { 0 },
220 { 0 },
221 { 0 },
222 }, 0,
223 },
224 {
225 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, METRICS }, true,
226 "a", -1, NULL, NULL,
227 {
228 { SDB_TYPE_STRING, { .string = "m1" } },
229 { 0 },
230 { 0 },
231 { 0 },
232 { 0 },
233 }, 1,
234 },
235 {
236 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, METRICS }, true,
237 "a", -1, NULL, "name = 'a' OR name = 'm1'",
238 {
239 { SDB_TYPE_STRING, { .string = "m1" } },
240 { 0 },
241 { 0 },
242 { 0 },
243 { 0 },
244 }, 1,
245 },
246 {
247 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, METRICS }, true,
248 "a", -1, NULL, "name = 'a' OR name = 'm2'",
249 {
250 { 0 },
251 { 0 },
252 { 0 },
253 { 0 },
254 { 0 },
255 }, 0,
256 },
257 {
258 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, METRICS }, true,
259 "a", -1, NULL, "name = 'a'",
260 {
261 { 0 },
262 { 0 },
263 { 0 },
264 { 0 },
265 { 0 },
266 }, 0,
267 },
268 {
269 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, ATTRS }, true,
270 "a", -1, NULL, NULL,
271 {
272 { SDB_TYPE_STRING, { .string = "k1" } },
273 { SDB_TYPE_STRING, { .string = "k2" } },
274 { 0 },
275 { 0 },
276 { 0 },
277 }, 2,
278 },
279 {
280 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, HOSTS }, false,
281 "a", -1, NULL, NULL,
282 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
283 },
284 /* host fields */
285 {
286 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, BACKENDS }, true,
287 "a", -1, NULL, NULL,
288 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
289 },
290 {
291 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, NAME }, false,
292 "a", -1, NULL, NULL,
293 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
294 },
295 {
296 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, LAST_UPDATE }, false,
297 "a", -1, NULL, NULL,
298 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
299 },
300 {
301 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, AGE }, false,
302 "a", -1, NULL, NULL,
303 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
304 },
305 {
306 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, INTERVAL }, false,
307 "a", -1, NULL, NULL,
308 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
309 },
310 /* service children */
311 {
312 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, ATTRS }, true,
313 "a", SDB_SERVICE, "s1", NULL,
314 {
315 { SDB_TYPE_STRING, { .string = "hostname" } },
316 { SDB_TYPE_STRING, { .string = "k1" } },
317 { 0 },
318 { 0 },
319 { 0 },
320 }, 2,
321 },
322 {
323 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, ATTRS }, true,
324 "a", SDB_SERVICE, "s1", "age >= 0s",
325 {
326 { SDB_TYPE_STRING, { .string = "hostname" } },
327 { SDB_TYPE_STRING, { .string = "k1" } },
328 { 0 },
329 { 0 },
330 { 0 },
331 }, 2,
332 },
333 {
334 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, ATTRS }, true,
335 "a", SDB_SERVICE, "s1", "age < 0s",
336 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }, 0,
337 },
338 {
339 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, HOSTS }, false,
340 "a", SDB_SERVICE, "s1", NULL,
341 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }, 0,
342 },
343 {
344 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, SERVICES }, false,
345 "a", SDB_SERVICE, "s1", NULL,
346 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }, 0,
347 },
348 {
349 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, METRICS }, false,
350 "a", SDB_SERVICE, "s1", NULL,
351 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }, 0,
352 },
353 /* service fields */
354 {
355 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, BACKENDS }, true,
356 "a", SDB_SERVICE, "s1", NULL,
357 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
358 },
359 {
360 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, NAME }, false,
361 "a", SDB_SERVICE, "s1", NULL,
362 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
363 },
364 {
365 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, LAST_UPDATE }, false,
366 "a", SDB_SERVICE, "s1", NULL,
367 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
368 },
369 {
370 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, AGE }, 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, INTERVAL }, false,
376 "a", SDB_SERVICE, "s1", NULL,
377 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
378 },
379 /* metric children */
380 {
381 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, ATTRS }, true,
382 "b", SDB_METRIC, "m2", NULL,
383 {
384 { SDB_TYPE_STRING, { .string = "hostname" } },
385 { SDB_TYPE_STRING, { .string = "k1" } },
386 { SDB_TYPE_STRING, { .string = "k2" } },
387 { 0 },
388 { 0 },
389 }, 3,
390 },
391 {
392 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, ATTRS }, true,
393 "b", SDB_METRIC, "m2", "age >= 0s",
394 {
395 { SDB_TYPE_STRING, { .string = "hostname" } },
396 { SDB_TYPE_STRING, { .string = "k1" } },
397 { SDB_TYPE_STRING, { .string = "k2" } },
398 { 0 },
399 { 0 },
400 }, 3,
401 },
402 {
403 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, ATTRS }, true,
404 "b", SDB_METRIC, "m2", "name = 'b' OR name = 'm2' OR name = 'k2'",
405 {
406 { SDB_TYPE_STRING, { .string = "k2" } },
407 { 0 },
408 { 0 },
409 { 0 },
410 { 0 },
411 }, 1,
412 },
413 {
414 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, ATTRS }, true,
415 "b", SDB_METRIC, "m2", "age < 0s",
416 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }, 0,
417 },
418 {
419 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, HOSTS }, false,
420 "b", SDB_METRIC, "m2", NULL,
421 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }, 0,
422 },
423 {
424 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, SERVICES }, false,
425 "b", SDB_METRIC, "m2", NULL,
426 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }, 0,
427 },
428 {
429 { SDB_OBJECT_INIT, TYPED_EXPR, -1, &namer, NULL, METRICS }, false,
430 "b", SDB_METRIC, "m2", NULL,
431 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }, 0,
432 },
433 /* metric fields */
434 {
435 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, BACKENDS }, true,
436 "b", SDB_METRIC, "m2", NULL,
437 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
438 },
439 {
440 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, NAME }, false,
441 "b", SDB_METRIC, "m2", NULL,
442 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
443 },
444 {
445 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, LAST_UPDATE }, false,
446 "b", SDB_METRIC, "m2", NULL,
447 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
448 },
449 {
450 { SDB_OBJECT_INIT, FIELD_VALUE, -1, NULL, NULL, AGE }, 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, INTERVAL }, false,
456 "b", SDB_METRIC, "m2", NULL,
457 { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, }, 0,
458 },
459 /* arrays */
460 {
461 {
462 SDB_OBJECT_INIT, 0, -1, NULL, NULL,
463 {
464 SDB_TYPE_INTEGER | SDB_TYPE_ARRAY,
465 { .array = { SDB_STATIC_ARRAY_LEN(int_values), int_values } },
466 },
467 }, true,
468 NULL, -1, NULL, NULL,
469 {
470 { SDB_TYPE_INTEGER, { .integer = 1 } },
471 { SDB_TYPE_INTEGER, { .integer = 2 } },
472 { SDB_TYPE_INTEGER, { .integer = 3 } },
473 { SDB_TYPE_INTEGER, { .integer = 4 } },
474 { SDB_TYPE_INTEGER, { .integer = 5 } },
475 }, 5,
476 },
477 {
478 {
479 SDB_OBJECT_INIT, 0, -1, NULL, NULL,
480 {
481 SDB_TYPE_DECIMAL | SDB_TYPE_ARRAY,
482 { .array = { SDB_STATIC_ARRAY_LEN(dec_values), dec_values } },
483 },
484 }, true,
485 NULL, -1, NULL, NULL,
486 {
487 { SDB_TYPE_DECIMAL, { .decimal = 47.0 } },
488 { SDB_TYPE_DECIMAL, { .decimal = 11.0 } },
489 { SDB_TYPE_DECIMAL, { .decimal = 32.0 } },
490 { SDB_TYPE_DECIMAL, { .decimal = 64.0 } },
491 { 0 },
492 }, 4,
493 },
494 {
495 {
496 SDB_OBJECT_INIT, 0, -1, NULL, NULL,
497 {
498 SDB_TYPE_STRING | SDB_TYPE_ARRAY,
499 { .array = { SDB_STATIC_ARRAY_LEN(str_values), str_values } },
500 },
501 }, true,
502 NULL, -1, NULL, NULL,
503 {
504 { SDB_TYPE_STRING, { .string = "foo" } },
505 { SDB_TYPE_STRING, { .string = "bar" } },
506 { SDB_TYPE_STRING, { .string = "qux" } },
507 { 0 },
508 { 0 },
509 }, 3,
510 },
511 {
512 {
513 SDB_OBJECT_INIT, 0, -1, NULL, NULL,
514 {
515 SDB_TYPE_DATETIME | SDB_TYPE_ARRAY,
516 { .array = { SDB_STATIC_ARRAY_LEN(dt_values), dt_values } },
517 },
518 }, true,
519 NULL, -1, NULL, NULL,
520 {
521 { SDB_TYPE_DATETIME, { .datetime = 4711L } },
522 { SDB_TYPE_DATETIME, { .datetime = 1234567890L } },
523 { 0 },
524 { 0 },
525 { 0 },
526 }, 2,
527 },
528 {
529 {
530 SDB_OBJECT_INIT, 0, -1, NULL, NULL,
531 {
532 SDB_TYPE_BINARY | SDB_TYPE_ARRAY,
533 { .array = { SDB_STATIC_ARRAY_LEN(bin_values), bin_values } },
534 },
535 }, true,
536 NULL, -1, NULL, NULL,
537 {
538 { SDB_TYPE_BINARY, { .binary = { 4, (unsigned char *)"\3\2\0\1" } } },
539 { 0 },
540 { 0 },
541 { 0 },
542 { 0 },
543 }, 1,
544 },
545 };
547 START_TEST(test_expr_iter)
548 {
549 sdb_store_obj_t *obj = NULL;
550 sdb_store_matcher_t *filter = NULL;
551 int context = SDB_HOST;
553 bool iterable;
554 sdb_store_expr_iter_t *iter;
555 size_t i;
557 if (expr_iter_data[_i].host) {
558 obj = sdb_store_get_host(expr_iter_data[_i].host);
559 ck_assert(obj != NULL);
561 if (expr_iter_data[_i].child) {
562 sdb_store_obj_t *child = sdb_store_get_child(obj,
563 expr_iter_data[_i].child_type, expr_iter_data[_i].child);
564 ck_assert(child != NULL);
565 sdb_object_deref(SDB_OBJ(obj));
566 obj = child;
567 context = expr_iter_data[_i].child_type;
568 }
569 ck_assert(obj->type == context);
570 }
572 if (expr_iter_data[_i].filter) {
573 sdb_ast_node_t *ast;
574 ast = sdb_parser_parse_conditional(expr_iter_data[_i].filter, -1, NULL);
575 filter = sdb_store_query_prepare_matcher(ast);
576 sdb_object_deref(SDB_OBJ(ast));
577 ck_assert(filter != NULL);
578 }
580 iterable = sdb_store_expr_iterable(&expr_iter_data[_i].expr, context);
581 fail_unless(iterable == expr_iter_data[_i].iterable,
582 "%s expression not iterable in %s context",
583 EXPR_TO_STRING(&expr_iter_data[_i].expr),
584 SDB_STORE_TYPE_TO_NAME(context));
586 iter = sdb_store_expr_iter(&expr_iter_data[_i].expr, obj, filter);
587 fail_unless((iter != NULL) == iterable,
588 "sdb_store_expr_iter(%s expression, %s, %s) = %s; expected: %s",
589 EXPR_TO_STRING(&expr_iter_data[_i].expr),
590 obj ? SDB_STORE_TYPE_TO_NAME(obj->type) : "<array>",
591 expr_iter_data[_i].filter, iter ? "<iter>" : "NULL",
592 iterable ? "<iter>" : "NULL");
594 /* the iterator will keep a reference */
595 sdb_object_deref(SDB_OBJ(obj)); obj = NULL;
596 sdb_object_deref(SDB_OBJ(filter)); filter = NULL;
598 i = 0;
599 while (sdb_store_expr_iter_has_next(iter)) {
600 char v_str[64], expected_str[64];
601 sdb_data_t v;
603 fail_unless(i < expr_iter_data[_i].expected_len,
604 "iter<%s expression, %s, %s> returned >= %zu elements; "
605 "expected: %zu", EXPR_TO_STRING(&expr_iter_data[_i].expr),
606 SDB_STORE_TYPE_TO_NAME(context), expr_iter_data[_i].filter,
607 i + 1, expr_iter_data[_i].expected_len);
609 v = sdb_store_expr_iter_get_next(iter);
610 sdb_data_format(&v, v_str, sizeof(v_str), SDB_DOUBLE_QUOTED);
611 sdb_data_format(&expr_iter_data[_i].expected[i],
612 expected_str, sizeof(expected_str), SDB_DOUBLE_QUOTED);
613 fail_unless(sdb_data_cmp(&v, &expr_iter_data[_i].expected[i]) == 0,
614 "iter<%s expression, %s, %s>, elem %zu = %s; expected: %s",
615 EXPR_TO_STRING(&expr_iter_data[_i].expr),
616 SDB_STORE_TYPE_TO_NAME(context), expr_iter_data[_i].filter,
617 i, v_str, expected_str);
619 sdb_data_free_datum(&v);
620 ++i;
621 }
623 fail_unless(i == expr_iter_data[_i].expected_len,
624 "iter<%s expression, %s, %s> returned %zu elements; "
625 "expected: %zu", EXPR_TO_STRING(&expr_iter_data[_i].expr),
626 SDB_STORE_TYPE_TO_NAME(context), expr_iter_data[_i].filter,
627 i, expr_iter_data[_i].expected_len);
628 fail_unless(sdb_store_expr_iter_get_next(iter).type == SDB_TYPE_NULL,
629 "iter<%s expression, %s, %s> returned further elements "
630 "passed the end", EXPR_TO_STRING(&expr_iter_data[_i].expr),
631 SDB_STORE_TYPE_TO_NAME(context), expr_iter_data[_i].filter);
633 sdb_store_expr_iter_destroy(iter);
634 }
635 END_TEST
637 TEST_MAIN("core::store_expr")
638 {
639 TCase *tc = tcase_create("core");
640 tcase_add_checked_fixture(tc, populate, sdb_store_clear);
641 TC_ADD_LOOP_TEST(tc, expr_iter);
642 ADD_TCASE(tc);
643 }
644 TEST_MAIN_END
646 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */