Code

store: Add sdb_store_query_prepare_matcher().
[sysdb.git] / t / unit / core / store_expr_test.c
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         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 = "hostname" } },
313                         { SDB_TYPE_STRING, { .string = "k1" } },
314                         { 0 },
315                         { 0 },
316                         { 0 },
317                 }, 2,
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 = "hostname" } },
324                         { SDB_TYPE_STRING, { .string = "k1" } },
325                         { 0 },
326                         { 0 },
327                         { 0 },
328                 }, 2,
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 = "hostname" } },
382                         { SDB_TYPE_STRING, { .string = "k1" } },
383                         { SDB_TYPE_STRING, { .string = "k2" } },
384                         { 0 },
385                         { 0 },
386                 }, 3,
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 = "hostname" } },
393                         { SDB_TYPE_STRING, { .string = "k1" } },
394                         { SDB_TYPE_STRING, { .string = "k2" } },
395                         { 0 },
396                         { 0 },
397                 }, 3,
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)
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                 sdb_ast_node_t *ast;
571                 ast = sdb_parser_parse_conditional(expr_iter_data[_i].filter, -1, NULL);
572                 filter = sdb_store_query_prepare_matcher(ast);
573                 sdb_object_deref(SDB_OBJ(ast));
574                 ck_assert(filter != NULL);
575         }
577         iterable = sdb_store_expr_iterable(&expr_iter_data[_i].expr, context);
578         fail_unless(iterable == expr_iter_data[_i].iterable,
579                         "%s expression not iterable in %s context",
580                         EXPR_TO_STRING(&expr_iter_data[_i].expr),
581                         SDB_STORE_TYPE_TO_NAME(context));
583         iter = sdb_store_expr_iter(&expr_iter_data[_i].expr, obj, filter);
584         fail_unless((iter != NULL) == iterable,
585                         "sdb_store_expr_iter(%s expression, %s, %s) = %s; expected: %s",
586                         EXPR_TO_STRING(&expr_iter_data[_i].expr),
587                         obj ? SDB_STORE_TYPE_TO_NAME(obj->type) : "<array>",
588                         expr_iter_data[_i].filter, iter ? "<iter>" : "NULL",
589                         iterable ? "<iter>" : "NULL");
591         /* the iterator will keep a reference */
592         sdb_object_deref(SDB_OBJ(obj)); obj = NULL;
593         sdb_object_deref(SDB_OBJ(filter)); filter = NULL;
595         i = 0;
596         while (sdb_store_expr_iter_has_next(iter)) {
597                 char v_str[64], expected_str[64];
598                 sdb_data_t v;
600                 fail_unless(i < expr_iter_data[_i].expected_len,
601                                 "iter<%s expression, %s, %s> returned >= %zu elements; "
602                                 "expected: %zu", EXPR_TO_STRING(&expr_iter_data[_i].expr),
603                                 SDB_STORE_TYPE_TO_NAME(context), expr_iter_data[_i].filter,
604                                 i + 1, expr_iter_data[_i].expected_len);
606                 v = sdb_store_expr_iter_get_next(iter);
607                 sdb_data_format(&v, v_str, sizeof(v_str), SDB_DOUBLE_QUOTED);
608                 sdb_data_format(&expr_iter_data[_i].expected[i],
609                                 expected_str, sizeof(expected_str), SDB_DOUBLE_QUOTED);
610                 fail_unless(sdb_data_cmp(&v, &expr_iter_data[_i].expected[i]) == 0,
611                                 "iter<%s expression, %s, %s>, elem %zu = %s; expected: %s",
612                                 EXPR_TO_STRING(&expr_iter_data[_i].expr),
613                                 SDB_STORE_TYPE_TO_NAME(context), expr_iter_data[_i].filter,
614                                 i, v_str, expected_str);
616                 sdb_data_free_datum(&v);
617                 ++i;
618         }
620         fail_unless(i == expr_iter_data[_i].expected_len,
621                         "iter<%s expression, %s, %s> returned %zu elements; "
622                         "expected: %zu", EXPR_TO_STRING(&expr_iter_data[_i].expr),
623                         SDB_STORE_TYPE_TO_NAME(context), expr_iter_data[_i].filter,
624                         i, expr_iter_data[_i].expected_len);
625         fail_unless(sdb_store_expr_iter_get_next(iter).type == SDB_TYPE_NULL,
626                         "iter<%s expression, %s, %s> returned further elements "
627                         "passed the end", EXPR_TO_STRING(&expr_iter_data[_i].expr),
628                         SDB_STORE_TYPE_TO_NAME(context), expr_iter_data[_i].filter);
630         sdb_store_expr_iter_destroy(iter);
632 END_TEST
634 TEST_MAIN("core::store_expr")
636         TCase *tc = tcase_create("core");
637         tcase_add_checked_fixture(tc, populate, sdb_store_clear);
638         TC_ADD_LOOP_TEST(tc, expr_iter);
639         ADD_TCASE(tc);
641 TEST_MAIN_END
643 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */