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