From: Sebastian Harl Date: Wed, 9 Apr 2014 15:34:56 +0000 (+0200) Subject: store_lookup: Added "tostring" methods for matcher objects. X-Git-Tag: sysdb-0.1.0~132^2~17 X-Git-Url: https://git.tokkee.org/?p=sysdb.git;a=commitdiff_plain;h=69892731c1a337485c955f5c292d8cf7c179a162 store_lookup: Added "tostring" methods for matcher objects. This is meant for logging and debugging. For now, it's used in tests to check parsed and compiled matchers. --- diff --git a/src/core/store_lookup.c b/src/core/store_lookup.c index e5735d3..bb32157 100644 --- a/src/core/store_lookup.c +++ b/src/core/store_lookup.c @@ -103,6 +103,106 @@ match_name(name_matcher_t *m, const char *name) return 1; } /* match_name */ +static char * +name_tostring(name_matcher_t *m, char *buf, size_t buflen) +{ + snprintf(buf, buflen, "{ %s%s%s, %p }", + m->name ? "'" : "", m->name ? m->name : "NULL", m->name ? "'" : "", + m->name_re); + return buf; +} /* name_tostring */ + +static char * +logical_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen) +{ + char left[buflen + 1], right[buflen + 1]; + + if (! m) { + /* this should not happen */ + snprintf(buf, buflen, "()"); + return buf; + } + + assert((m->type == MATCHER_OR) || (m->type == MATCHER_AND)); + snprintf(buf, buflen, "(%s, %s, %s)", + m->type == MATCHER_OR ? "OR" : "AND", + sdb_store_matcher_tostring(OP_M(m)->left, left, sizeof(left)), + sdb_store_matcher_tostring(OP_M(m)->right, right, sizeof(right))); + return buf; +} /* logical_tostring */ + +static char * +unary_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen) +{ + char op[buflen + 1]; + + if (! m) { + /* this should not happen */ + snprintf(buf, buflen, "()"); + return buf; + } + + assert(m->type == MATCHER_NOT); + snprintf(buf, buflen, "(NOT, %s)", + sdb_store_matcher_tostring(UOP_M(m)->op, op, sizeof(op))); + return buf; +} /* unary_tostring */ + +static char * +attr_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen) +{ + char name[buflen + 1], value[buflen + 1]; + + if (! m) { + snprintf(buf, buflen, "ATTR{}"); + return buf; + } + + assert(m->type == MATCHER_ATTR); + snprintf(buf, buflen, "ATTR{ NAME%s, VALUE%s }", + name_tostring(&OBJ_M(m)->name, name, sizeof(name)), + name_tostring(&ATTR_M(m)->value, value, sizeof(value))); + return buf; +} /* attr_tostring */ + +static char * +service_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen) +{ + char name[buflen + 1], attr[buflen + 1]; + + if (! m) { + snprintf(buf, buflen, "SERVICE{}"); + return buf; + } + + assert(m->type == MATCHER_SERVICE); + snprintf(buf, buflen, "SERVICE{ NAME%s, %s }", + name_tostring(&OBJ_M(m)->name, name, sizeof(name)), + attr_tostring(SDB_STORE_MATCHER(SERVICE_M(m)->attr), + attr, sizeof(attr))); + return buf; +} /* service_tostring */ + +static char * +host_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen) +{ + char name[buflen + 1], service[buflen + 1], attr[buflen + 1]; + + if (! m) { + snprintf(buf, buflen, "HOST{}"); + return buf; + } + + assert(m->type == MATCHER_HOST); + snprintf(buf, buflen, "HOST{ NAME%s, %s, %s }", + name_tostring(&OBJ_M(m)->name, name, sizeof(name)), + service_tostring(SDB_STORE_MATCHER(HOST_M(m)->service), + service, sizeof(service)), + attr_tostring(SDB_STORE_MATCHER(HOST_M(m)->attr), + attr, sizeof(attr))); + return buf; +} /* host_tostring */ + /* match attribute specific values; * always call this function through match_obj() */ static int @@ -218,6 +318,17 @@ static matcher_cb matchers[] = { match_obj, }; +typedef char *(*matcher_tostring_cb)(sdb_store_matcher_t *, char *, size_t); + +static matcher_tostring_cb matchers_tostring[] = { + logical_tostring, + logical_tostring, + unary_tostring, + attr_tostring, + service_tostring, + host_tostring, +}; + static int match_logical(sdb_store_matcher_t *m, sdb_store_base_t *obj) { @@ -613,6 +724,18 @@ sdb_store_matcher_matches(sdb_store_matcher_t *m, sdb_store_base_t *obj) return matchers[m->type](m, obj); } /* sdb_store_matcher_matches */ +char * +sdb_store_matcher_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen) +{ + if (! m) + return NULL; + + if ((m->type < 0) + || (((size_t)m->type >= SDB_STATIC_ARRAY_LEN(matchers_tostring)))) + return NULL; + return matchers_tostring[m->type](m, buf, buflen); +} /* sdb_store_matcher_tostring */ + int sdb_store_lookup(sdb_store_matcher_t *m, sdb_store_lookup_cb cb, void *user_data) diff --git a/src/include/core/store.h b/src/include/core/store.h index cde6ad0..6106b3f 100644 --- a/src/include/core/store.h +++ b/src/include/core/store.h @@ -213,6 +213,14 @@ sdb_store_inv_matcher(sdb_store_matcher_t *m); int sdb_store_matcher_matches(sdb_store_matcher_t *m, sdb_store_base_t *obj); +/* + * sdb_store_matcher_tostring: + * Format a matcher object as string. This is meant for logging or debugging + * purposes. + */ +char * +sdb_store_matcher_tostring(sdb_store_matcher_t *m, char *buf, size_t buflen); + /* * sdb_store_lookup_cb: * Lookup callback. It is called for each matching object when looking up data diff --git a/t/Makefile.am b/t/Makefile.am index c63a2bb..cc2607f 100644 --- a/t/Makefile.am +++ b/t/Makefile.am @@ -10,6 +10,7 @@ check_PROGRAMS = libsysdb_test libsysdb_net_test libsysdb_test_SOURCES = \ libsysdb_test.c libsysdb_test.h \ + libsysdb_testutils.c libsysdb_testutils.h \ core/data_test.c \ core/object_test.c \ core/store_test.c \ @@ -25,7 +26,8 @@ libsysdb_test_CFLAGS = $(AM_CFLAGS) @CHECK_CFLAGS@ libsysdb_test_LDADD = $(top_builddir)/src/libsysdb.la @CHECK_LIBS@ libsysdb_net_test_SOURCES = \ - libsysdb_net_test.c libsysdb_test.h + libsysdb_net_test.c libsysdb_test.h \ + libsysdb_testutils.c libsysdb_testutils.h if BUILD_WITH_FOPENCOOKIE libsysdb_net_test_SOURCES += utils/unixsock_test.c endif diff --git a/t/core/store_lookup_test.c b/t/core/store_lookup_test.c index 8aa730b..6365b6b 100644 --- a/t/core/store_lookup_test.c +++ b/t/core/store_lookup_test.c @@ -420,22 +420,52 @@ lookup_cb(sdb_store_base_t *obj, void *user_data) START_TEST(test_lookup) { +#define PTR_RE "0x[0-9a-f]+" struct { const char *query; int expected; + const char *tostring_re; } golden_data[] = { - { "host.name = 'a'", 1 }, - { "host.name =~ 'a|b'", 2 }, - { "host.name =~ 'host'", 0 }, - { "host.name =~ '.'", 3 }, - { "service.name = 's1'", 2 }, - { "service.name =~ 's'", 2 }, - { "service.name !~ 's'", 1 }, - { "attribute.name = 'k1'", 1 }, - { "attribute.name = 'x'", 0 }, - { "attribute.k1 = 'v1'", 1 }, - { "attribute.k1 != 'v1'", 2 }, - { "attribute.k1 != 'v2'", 3 }, + { "host.name = 'a'", 1, + "HOST\\{ NAME\\{ 'a', \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" }, + { "host.name =~ 'a|b'", 2, + "HOST\\{ NAME\\{ NULL, "PTR_RE" \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" }, + { "host.name =~ 'host'", 0, + "HOST\\{ NAME\\{ NULL, "PTR_RE" \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" }, + { "host.name =~ '.'", 3, + "HOST\\{ NAME\\{ NULL, "PTR_RE" \\}, SERVICE\\{\\}, ATTR\\{\\} \\}" }, + { "service.name = 's1'", 2, + "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{ " + "NAME\\{ 's1', \\(nil\\) }, ATTR\\{\\} " + "\\}, ATTR\\{\\} \\}" }, + { "service.name =~ 's'", 2, + "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{ " + "NAME\\{ NULL, "PTR_RE" }, ATTR\\{\\} " + "\\}, ATTR\\{\\} \\}" }, + { "service.name !~ 's'", 1, + "(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{ " + "NAME\\{ NULL, "PTR_RE" }, ATTR\\{\\} " + "\\}, ATTR\\{\\} \\})" }, + { "attribute.name = 'k1'", 1, + "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " + "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ NULL, \\(nil\\) \\} " + "\\} \\}" }, + { "attribute.name = 'x'", 0, + "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " + "NAME\\{ 'x', \\(nil\\) }, VALUE\\{ NULL, \\(nil\\) \\} " + "\\} \\}" }, + { "attribute.k1 = 'v1'", 1, + "HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " + "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ 'v1', \\(nil\\) \\} " + "\\} \\}" }, + { "attribute.k1 != 'v1'", 2, + "(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " + "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ 'v1', \\(nil\\) \\} " + "\\} \\})" }, + { "attribute.k1 != 'v2'", 3, + "(NOT, HOST\\{ NAME\\{ NULL, \\(nil\\) \\}, SERVICE\\{\\}, ATTR\\{ " + "NAME\\{ 'k1', \\(nil\\) }, VALUE\\{ 'v2', \\(nil\\) \\} " + "\\} \\})" }, }; int check, n; @@ -449,10 +479,19 @@ START_TEST(test_lookup) "sdb_store_lookup called callback %d times; expected: 3", (int)n); for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { - sdb_store_matcher_t *m = sdb_fe_parse_matcher(golden_data[i].query, -1); + sdb_store_matcher_t *m; + char buf[4096]; + + m = sdb_fe_parse_matcher(golden_data[i].query, -1); fail_unless(m != NULL, "sdb_fe_parse_matcher(%s, -1) = NULL; expected: ", golden_data[i].query); + fail_unless(sdb_regmatches(golden_data[i].tostring_re, + sdb_store_matcher_tostring(m, buf, sizeof(buf))) == 0, + "sdb_fe_parse_matcher(%s, -1) = %s; expected: %s", + golden_data[i].query, + sdb_store_matcher_tostring(m, buf, sizeof(buf)), + golden_data[i].tostring_re); n = 0; sdb_store_lookup(m, lookup_cb, &n); diff --git a/t/libsysdb_test.h b/t/libsysdb_test.h index 3357260..5f0e1b4 100644 --- a/t/libsysdb_test.h +++ b/t/libsysdb_test.h @@ -31,6 +31,8 @@ #include "sysdb.h" #include "core/object.h" +#include "libsysdb_testutils.h" + #include #include diff --git a/t/libsysdb_testutils.c b/t/libsysdb_testutils.c new file mode 100644 index 0000000..964afdb --- /dev/null +++ b/t/libsysdb_testutils.c @@ -0,0 +1,54 @@ +/* + * SysDB - t/libsysdb_testutils.c + * Copyright (C) 2014 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "libsysdb_testutils.h" + +#include +#include +#include + +int +sdb_regmatches(const char *regex, const char *string) +{ + regex_t reg; + int status; + + status = regcomp(®, regex, REG_EXTENDED | REG_NOSUB); + if (status) + return status; + + status = regexec(®, string, /* matches = */ 0, NULL, /* flags = */ 0); + regfree(®); + return status; +} /* sdb_regmatches */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/t/libsysdb_testutils.h b/t/libsysdb_testutils.h new file mode 100644 index 0000000..3f828a9 --- /dev/null +++ b/t/libsysdb_testutils.h @@ -0,0 +1,49 @@ +/* + * SysDB - t/libsysdb_testutils.h + * Copyright (C) 2014 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Utility functions for test suites. + */ + +#ifndef T_LIBSYSDB_UTILS_H +#define T_LIBSYSDB_UTILS_H 1 + +/* + * sdb_regmatches: + * Check if a regex matches a string. + * + * Returns: + * - 0 if the regex matches + * - a non-zero error value else (see regcomp(3) for details) + */ +int +sdb_regmatches(const char *regex, const char *string); + +#endif /* T_LIBSYSDB_UTILS_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ +