Code

153e52f1c84bb393bcd560541485ee71e5af8044
[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/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)
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);
635 END_TEST
637 TEST_MAIN("core::store_expr")
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);
644 TEST_MAIN_END
646 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */