]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
libcli/wsp: Test AQS parser
authorNoel Power <noel.power@suse.com>
Mon, 24 Oct 2022 19:50:27 +0000 (20:50 +0100)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 25 Oct 2023 22:23:38 +0000 (22:23 +0000)
Signed-off-by: Noel Power <noel.power@suse.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
libcli/wsp/test_wsp_parser.c [new file with mode: 0644]
libcli/wsp/wscript_build
selftest/tests.py

diff --git a/libcli/wsp/test_wsp_parser.c b/libcli/wsp/test_wsp_parser.c
new file mode 100644 (file)
index 0000000..9edebda
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ *  Unix SMB/CIFS implementation.
+ *  Copyright (C) Noel Power
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include <setjmp.h>
+#include <cmocka.h>
+#include <talloc.h>
+#include "lib/cmdline/cmdline.h"
+#include "libcli/util/ntstatus.h"
+#include "lib/util/samba_util.h"
+#include "lib/torture/torture.h"
+#include "lib/param/param.h"
+#include "libcli/wsp/wsp_aqs.h"
+#include "bin/default/librpc/gen_ndr/ndr_wsp.h"
+#include "librpc/wsp/wsp_util.h"
+
+/*
+ * some routines to help stringify the parsed AQS
+ * query so we can test parsing
+ */
+
+static bool is_operator_node(t_query *node)
+{
+       if (node->type == eVALUE) {
+               return false;
+       }
+       return true;
+}
+
+static const char *nodetype_as_string(t_nodetype node)
+{
+       const char *result = NULL;
+       switch (node) {
+               case eNOT:
+                       result = "NOT";
+                       break;
+               case eAND:
+                       result = "AND";
+                       break;
+               case eOR:
+                       result = "OR";
+                       break;
+               case eVALUE:
+               default:
+                       break;
+       }
+       return result;
+}
+
+static const char *restriction_as_string(TALLOC_CTX *ctx,
+                                   struct wsp_crestriction *crestriction )
+{
+       const char *result = NULL;
+       if (crestriction->ultype == RTPROPERTY) {
+               struct wsp_cpropertyrestriction *prop_restr =
+                       &crestriction->restriction.cpropertyrestriction;
+               struct wsp_cbasestoragevariant *value = &prop_restr->prval;
+               result = variant_as_string(ctx, value, true);
+       } else {
+               struct wsp_ccontentrestriction *cont_restr = NULL;
+               cont_restr = &crestriction->restriction.ccontentrestriction;
+               result = talloc_strdup(ctx, cont_restr->pwcsphrase);
+       }
+       return result;
+}
+
+static const char *prop_name_from_restriction(
+               TALLOC_CTX *ctx,
+               struct wsp_crestriction *restriction)
+{
+       const char *result = NULL;
+       struct wsp_cfullpropspec *prop;
+       if (restriction->ultype == RTCONTENT) {
+               prop = &restriction->restriction.ccontentrestriction.property;
+       } else {
+               prop = &restriction->restriction.cpropertyrestriction.property;
+       }
+       result = prop_from_fullprop(ctx, prop);
+       return result;
+}
+
+static char *print_basic_query(TALLOC_CTX *ctx,
+               struct wsp_crestriction *restriction)
+{
+       const char *op_str = op_as_string(restriction);
+       const char *val_str = restriction_as_string(ctx, restriction);
+       const char *prop_name = prop_name_from_restriction(ctx, restriction);
+       char *res = talloc_asprintf(ctx,
+                       "%s %s %s", prop_name, op_str ? op_str : "", val_str);
+       return res;
+}
+
+static char *print_node(TALLOC_CTX *ctx, t_query *node, bool is_rpn)
+{
+       switch(node->type) {
+               case eAND:
+               case eOR:
+               case eNOT:
+                       return talloc_asprintf(ctx,
+                               " %s ", nodetype_as_string(node->type));
+                       break;
+               case eVALUE:
+               default:
+                       return print_basic_query(ctx, node->restriction);
+                       break;
+       }
+}
+
+/*
+ * Algorithm infix (tree)
+ * Print the infix expression for an expression tree.
+ *  Pre : tree is a pointer to an expression tree
+ *  Post: the infix expression has been printed
+ * start infix
+ *  if (tree not empty)
+ *     if (tree token is operator)
+ *        print (open parenthesis)
+ *     end if
+ *     infix (tree left subtree)
+ *     print (tree token)
+ *     infix (tree right subtree)
+ *     if (tree token is operator)
+ *        print (close parenthesis)
+ *     end if
+ *  end if
+ * end infix
+ */
+
+static char *infix(TALLOC_CTX *ctx, t_query *tree)
+{
+       char *sresult = NULL;
+       char *stree = NULL;
+       char *sleft = NULL;
+       char *sright = NULL;
+       if (tree == NULL) {
+               return NULL;
+       }
+
+       if (is_operator_node(tree)) {
+               sresult = talloc_strdup(ctx, "(");
+               SMB_ASSERT(sresult != NULL);
+       }
+       sleft = infix(ctx, tree->left);
+       stree = print_node(ctx, tree, false);
+       sright = infix(ctx, tree->right);
+       sresult = talloc_asprintf(ctx, "%s%s%s%s",
+                       sresult ? sresult : "",
+                       sleft ? sleft : "",
+                       stree? stree : "",
+                       sright ? sright : "");
+
+       if (is_operator_node(tree)) {
+               sresult = talloc_asprintf(ctx, "%s)", sresult);
+               SMB_ASSERT(sresult != NULL);
+       }
+       return sresult;
+}
+
+static struct {
+       const char *aqs;
+       const char *stringified;
+} no_col_map_queries [] = {
+
+       /* equals (numeric) */
+       {
+               "System.Size:10241",
+               "System.Size = 10241"
+       },
+       {
+               "System.Size := 10241",
+               "System.Size = 10241"
+       },
+       /* not equals */
+       {
+               "System.Size:!=10241",
+               "System.Size != 10241"
+       },
+       /* equals (string property) */
+       {
+               "ALL:(somestring)",
+               "All = 'somestring'"
+       },
+       {
+               "ALL:=somestring",
+               "All = 'somestring'"
+       },
+       {
+               "ALL:somestring",
+               "All = 'somestring'"
+       },
+       /* not equals (string) */
+       {
+               "ALL:!=somestring",
+               "All != 'somestring'"
+       },
+       /* Greater than */
+       {
+               "System.Size:(>10241)",
+               "System.Size > 10241"
+       },
+       {
+               "System.Size:>10241",
+               "System.Size > 10241"
+       },
+       /* Less than */
+       {
+               "System.Size:(<10241)",
+               "System.Size < 10241"
+       },
+       /* Greater than or equals */
+       {
+               "System.Size:(>=10241)",
+               "System.Size >= 10241"
+       },
+       {
+               "System.Size:>=10241",
+               "System.Size >= 10241"
+       },
+       /* Less than or equals */
+       {
+               "System.Size:(<=10241)",
+               "System.Size <= 10241"
+       },
+       {
+               "System.Size:<=10241",
+               "System.Size <= 10241"
+       },
+       /* equals (in the sense of matches) */
+       {
+               "ALL:($=somestring)",
+               "All equals somestring"
+       },
+       /* starts with */
+       {
+               "ALL:($<somestring)",
+               "All starts with somestring"
+       },
+       /* range */
+       {
+               "System.Size:10241-102401",
+               "(System.Size >= 10241 AND System.Size < 102401)"
+       },
+       {
+               "System.Size:small",
+               "(System.Size >= 10241 AND System.Size < 102401)"
+       },
+       /* NOT */
+       {
+               "NOT System.Size:10241",
+               "( NOT System.Size = 10241)"
+       },
+       /* AND */
+       {
+               "System.Size:(>=10241) AND System.Size:(<102401)",
+               "(System.Size >= 10241 AND System.Size < 102401)"
+       },
+       /* OR */
+       {
+               "System.Kind:picture OR System.Kind:video",
+               "(System.Kind = 'picture' OR System.Kind = 'video')"
+       },
+       /* MULTIPLE LOGICAL */
+       {
+               "System.Kind:picture AND NOT System.Kind:video OR "
+               "System.Kind:movie",
+               "(System.Kind = 'picture' AND (( NOT System.Kind = 'video') OR "
+               "System.Kind = 'movie'))"
+       },
+       /* parenthesized MULTIPLE LOGICAL */
+       {
+               "(System.Kind:picture AND NOT System.Kind:video) OR "
+               "System.Kind:movie",
+               "((System.Kind = 'picture' AND ( NOT System.Kind = 'video')) "
+               "OR System.Kind = 'movie')"
+       },
+};
+
+static char *dump_cols(TALLOC_CTX *ctx, t_select_stmt *select)
+{
+       t_col_list *cols = select->cols;
+       char *res = NULL;
+       if (cols) {
+               int i;
+               for (i = 0; i < cols->num_cols; i++) {
+                       if (i == 0) {
+                               res = talloc_strdup(ctx,
+                                               cols->cols[i]);
+                       } else {
+                               res = talloc_asprintf(ctx,
+                                               "%s, %s",
+                                               res, cols->cols[i]);
+                       }
+               }
+       }
+       return res;
+}
+
+static void test_wsp_parser(void **state)
+{
+       int i;
+       t_select_stmt *select_stmt = NULL;
+       const char *col_query =
+               "SELECT System.ItemName, System.ItemURL, System.Size WHERE "
+               "System.Kind:picture";
+       char *res = NULL;
+
+       TALLOC_CTX *frame = talloc_stackframe();
+       for (i = 0; i < ARRAY_SIZE(no_col_map_queries); i++) {
+               select_stmt = get_wsp_sql_tree(no_col_map_queries[i].aqs);
+               assert_non_null(select_stmt);
+               assert_null(select_stmt->cols);
+               res = infix(frame, select_stmt->where);
+               DBG_DEBUG("reading query => %s parsed => %s\n",
+                       no_col_map_queries[i].aqs,
+                       res);
+               assert_string_equal(res, no_col_map_queries[i].stringified);
+       }
+       select_stmt = get_wsp_sql_tree(col_query);
+       res = infix(frame, select_stmt->where);
+       assert_string_equal(res, "System.Kind = 'picture'");
+       assert_non_null(select_stmt->cols);
+       res = dump_cols(frame, select_stmt);
+       assert_string_equal(res,
+               "System.ItemName, System.ItemURL, System.Size");
+       TALLOC_FREE(frame);
+}
+
+int main(int argc, const char *argv[])
+{
+       const struct CMUnitTest tests[] = {
+               cmocka_unit_test(test_wsp_parser),
+       };
+       struct poptOption long_options[] = {
+               POPT_AUTOHELP
+               POPT_COMMON_SAMBA
+               POPT_TABLEEND
+       };
+       poptContext pc;
+       int opt;
+       bool ok;
+       struct loadparm_context *lp_ctx = NULL;
+
+       TALLOC_CTX *frame = talloc_stackframe();
+
+       smb_init_locale();
+
+       ok = samba_cmdline_init(frame,
+                               SAMBA_CMDLINE_CONFIG_CLIENT,
+                               false /* require_smbconf */);
+       if (!ok) {
+               DBG_ERR("Failed to init cmdline parser!\n");
+               TALLOC_FREE(frame);
+               exit(1);
+       }
+
+       lp_ctx = samba_cmdline_get_lp_ctx();
+       if (!lp_ctx) {
+               DBG_ERR("Failed to init cmdline parser!\n");
+               TALLOC_FREE(frame);
+               exit(1);
+       }
+
+       lpcfg_set_cmdline(lp_ctx, "log level", "1");
+
+       pc = samba_popt_get_context(getprogname(),
+                                   argc,
+                                   argv,
+                                   long_options,
+                                   0);
+       if (pc == NULL) {
+               DBG_ERR("Failed to setup popt context!\n");
+               TALLOC_FREE(frame);
+               exit(1);
+       }
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch(opt) {
+                   default:
+                           fprintf(stderr, "Unknown Option: %c\n", opt);
+                           exit(1);
+               }
+       }
+
+       cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+
+       return cmocka_run_group_tests(tests, NULL, NULL);
+}
index 7aadbad8f14be31691090c94452784b2db61d4d2..2d34879a68f4880040dfb9404683ce03bea0b060 100644 (file)
@@ -31,3 +31,11 @@ bld.SAMBA_SUBSYSTEM('LIBSAMBA_WSP',
        public_deps='LIBSAMBA_WSP_PARSER',
        enabled=bld.env.with_wsp
        )
+
+bld.SAMBA_BINARY('test_wsp_parser',
+    source='test_wsp_parser.c',
+    deps= 'dcerpc CMDLINE_S3 LIBSAMBA_WSP NDR_WSP NDR_WSP_DATA WSP_UTIL cmocka',
+    enabled=bld.env.with_wsp,
+    install=False
+    )
+
index 89af15a075c0f3ae2d9dae5b85407012ff588952..0828c1ba5b009e93b2732ddacb34bfdf04a6f839 100644 (file)
@@ -457,6 +457,8 @@ plantestsuite("samba.unittests.auth.sam", "none",
 if have_heimdal_support and not using_system_gssapi:
     plantestsuite("samba.unittests.auth.heimdal_gensec_unwrap_des", "none",
                   [valgrindify(os.path.join(bindir(), "test_heimdal_gensec_unwrap_des"))])
+plantestsuite("samba.unittests.test_wsp_parser", "none",
+              [os.path.join(bindir(), "default/libcli/wsp/test_wsp_parser")] + [configuration])
 if with_elasticsearch_backend:
     plantestsuite("samba.unittests.mdsparser_es", "none",
                   [os.path.join(bindir(), "default/source3/test_mdsparser_es")] + [configuration])