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