Code

b15809a589bc890dd36ff5c8809bdf71b75cfd84
[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         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)
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);
634 END_TEST
636 TEST_MAIN("core::store_expr")
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);
643 TEST_MAIN_END
645 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */