use helper in cmd node
[protos/libecoli.git] / lib / ecoli_complete.c
index e488e0e..7ad846c 100644 (file)
 #include <ecoli_strvec.h>
 #include <ecoli_keyval.h>
 #include <ecoli_log.h>
+#include <ecoli_test.h>
 #include <ecoli_node.h>
 #include <ecoli_parse.h>
+#include <ecoli_node_sh_lex.h>
+#include <ecoli_node_str.h>
+#include <ecoli_node_or.h>
 #include <ecoli_complete.h>
 
+EC_LOG_TYPE_REGISTER(comp);
+
 struct ec_comp_item {
        TAILQ_ENTRY(ec_comp_item) next;
        enum ec_comp_type type;
-       const struct ec_node *node;
        struct ec_comp_group *grp;
        char *start;      /* the initial token */
        char *full;       /* the full token after completion */
@@ -69,14 +74,16 @@ ec_node_complete_child(const struct ec_node *node,
        struct ec_comp_group *cur_group;
        int ret;
 
-       if (node->type->complete == NULL)
-               return -ENOTSUP;
+       if (ec_node_type(node)->complete == NULL) {
+               errno = ENOTSUP;
+               return -1;
+       }
 
        /* save previous parse state, prepare child state */
        cur_state = comp->cur_state;
        child_state = ec_parse(node);
        if (child_state == NULL)
-               return -ENOMEM;
+               return -1;
 
        if (cur_state != NULL)
                ec_parse_link_child(cur_state, child_state);
@@ -85,7 +92,7 @@ ec_node_complete_child(const struct ec_node *node,
        comp->cur_group = NULL;
 
        /* fill the comp struct with items */
-       ret = node->type->complete(node, comp, strvec);
+       ret = ec_node_type(node)->complete(node, comp, strvec);
 
        /* restore parent parse state */
        if (cur_state != NULL) {
@@ -97,7 +104,7 @@ ec_node_complete_child(const struct ec_node *node,
        comp->cur_group = cur_group;
 
        if (ret < 0)
-               return ret;
+               return -1;
 
        return 0;
 }
@@ -181,8 +188,8 @@ fail:
 }
 
 static struct ec_comp_item *
-ec_comp_item(const struct ec_node *node, enum ec_comp_type type,
-               const char *start, const char *full)
+ec_comp_item(enum ec_comp_type type,
+       const char *start, const char *full)
 {
        struct ec_comp_item *item = NULL;
        struct ec_keyval *attrs = NULL;
@@ -226,7 +233,6 @@ ec_comp_item(const struct ec_node *node, enum ec_comp_type type,
                        goto fail;
        }
 
-       item->node = node;
        item->type = type;
        item->start = start_cp;
        item->full = full_cp;
@@ -251,11 +257,12 @@ int ec_comp_item_set_display(struct ec_comp_item *item,
                                const char *display)
 {
        char *display_copy = NULL;
-       int ret = 0;
 
        if (item == NULL || display == NULL ||
-                       item->type == EC_COMP_UNKNOWN)
-               return -EINVAL;
+                       item->type == EC_COMP_UNKNOWN) {
+               errno = EINVAL;
+               return -1;
+       }
 
        display_copy = ec_strdup(display);
        if (display_copy == NULL)
@@ -268,7 +275,7 @@ int ec_comp_item_set_display(struct ec_comp_item *item,
 
 fail:
        ec_free(display_copy);
-       return ret;
+       return -1;
 }
 
 int
@@ -276,13 +283,13 @@ ec_comp_item_set_completion(struct ec_comp_item *item,
                                const char *completion)
 {
        char *completion_copy = NULL;
-       int ret = 0;
 
        if (item == NULL || completion == NULL ||
-                       item->type == EC_COMP_UNKNOWN)
-               return -EINVAL;
+                       item->type == EC_COMP_UNKNOWN) {
+               errno = EINVAL;
+               return -1;
+       }
 
-       ret = -ENOMEM;
        completion_copy = ec_strdup(completion);
        if (completion_copy == NULL)
                goto fail;
@@ -294,7 +301,7 @@ ec_comp_item_set_completion(struct ec_comp_item *item,
 
 fail:
        ec_free(completion_copy);
-       return ret;
+       return -1;
 }
 
 int
@@ -302,13 +309,13 @@ ec_comp_item_set_str(struct ec_comp_item *item,
                        const char *str)
 {
        char *str_copy = NULL;
-       int ret = 0;
 
        if (item == NULL || str == NULL ||
-                       item->type == EC_COMP_UNKNOWN)
-               return -EINVAL;
+                       item->type == EC_COMP_UNKNOWN) {
+               errno = EINVAL;
+               return -1;
+       }
 
-       ret = -ENOMEM;
        str_copy = ec_strdup(str);
        if (str_copy == NULL)
                goto fail;
@@ -320,15 +327,17 @@ ec_comp_item_set_str(struct ec_comp_item *item,
 
 fail:
        ec_free(str_copy);
-       return ret;
+       return -1;
 }
 
 static int
-ec_comp_item_add(struct ec_comp *comp,
+ec_comp_item_add(struct ec_comp *comp, const struct ec_node *node,
                struct ec_comp_item *item)
 {
-       if (comp == NULL || item == NULL || item->node == NULL)
-               return -EINVAL;
+       if (comp == NULL || item == NULL) {
+               errno = EINVAL;
+               return -1;
+       }
 
        switch (item->type) {
        case EC_COMP_UNKNOWN:
@@ -341,15 +350,16 @@ ec_comp_item_add(struct ec_comp *comp,
                comp->count_partial++;
                break;
        default:
-               return -EINVAL;
+               errno = EINVAL;
+               return -1;
        }
 
        if (comp->cur_group == NULL) {
                struct ec_comp_group *grp;
 
-               grp = ec_comp_group(item->node, comp->cur_state);
+               grp = ec_comp_group(node, comp->cur_state);
                if (grp == NULL)
-                       return -ENOMEM;
+                       return -1;
                TAILQ_INSERT_TAIL(&comp->groups, grp, next);
                comp->cur_group = grp;
        }
@@ -385,18 +395,18 @@ ec_comp_item_get_type(const struct ec_comp_item *item)
        return item->type;
 }
 
-const struct ec_node *
-ec_comp_item_get_node(const struct ec_comp_item *item)
-{
-       return item->node;
-}
-
 const struct ec_comp_group *
 ec_comp_item_get_grp(const struct ec_comp_item *item)
 {
        return item->grp;
 }
 
+const struct ec_node *
+ec_comp_item_get_node(const struct ec_comp_item *item)
+{
+       return ec_comp_item_get_grp(item)->node;
+}
+
 static void
 ec_comp_item_free(struct ec_comp_item *item)
 {
@@ -420,11 +430,11 @@ int ec_comp_add_item(struct ec_comp *comp,
        struct ec_comp_item *item = NULL;
        int ret;
 
-       item = ec_comp_item(node, type, start, full);
+       item = ec_comp_item(type, start, full);
        if (item == NULL)
                return -1;
 
-       ret = ec_comp_item_add(comp, item);
+       ret = ec_comp_item_add(comp, node, item);
        if (ret < 0)
                goto fail;
 
@@ -507,7 +517,7 @@ void ec_comp_dump(FILE *out, const struct ec_comp *comp)
 
        TAILQ_FOREACH(grp, &comp->groups, next) {
                fprintf(out, "node=%p, node_type=%s\n",
-                       grp->node, grp->node->type->name);
+                       grp->node, ec_node_type(grp->node)->name);
                TAILQ_FOREACH(item, &grp->items, next) {
                        const char *typestr;
 
@@ -634,3 +644,122 @@ void ec_comp_iter_free(struct ec_comp_iter *iter)
 {
        ec_free(iter);
 }
+
+/* LCOV_EXCL_START */
+static int ec_comp_testcase(void)
+{
+       struct ec_node *node = NULL;
+       struct ec_comp *c = NULL;
+       struct ec_comp_iter *iter = NULL;
+       struct ec_comp_item *item;
+       FILE *f = NULL;
+       char *buf = NULL;
+       size_t buflen = 0;
+       int testres = 0;
+
+       node = ec_node_sh_lex(EC_NO_ID,
+                       EC_NODE_OR(EC_NO_ID,
+                               ec_node_str("id_x", "xx"),
+                               ec_node_str("id_y", "yy")));
+       if (node == NULL)
+               goto fail;
+
+       c = ec_node_complete(node, "xcdscds");
+       testres |= EC_TEST_CHECK(
+               c != NULL && ec_comp_count(c, EC_COMP_ALL) == 0,
+               "complete count should is not 0\n");
+       ec_comp_free(c);
+
+       c = ec_node_complete(node, "x");
+       testres |= EC_TEST_CHECK(
+               c != NULL && ec_comp_count(c, EC_COMP_ALL) == 1,
+               "complete count should is not 1\n");
+       ec_comp_free(c);
+
+       c = ec_node_complete(node, "");
+       testres |= EC_TEST_CHECK(
+               c != NULL && ec_comp_count(c, EC_COMP_ALL) == 2,
+               "complete count should is not 2\n");
+
+       f = open_memstream(&buf, &buflen);
+       if (f == NULL)
+               goto fail;
+       ec_comp_dump(f, NULL);
+       fclose(f);
+       f = NULL;
+
+       testres |= EC_TEST_CHECK(
+               strstr(buf, "no completion"), "bad dump\n");
+       free(buf);
+       buf = NULL;
+
+       f = open_memstream(&buf, &buflen);
+       if (f == NULL)
+               goto fail;
+       ec_comp_dump(f, c);
+       fclose(f);
+       f = NULL;
+
+       testres |= EC_TEST_CHECK(
+               strstr(buf, "comp=<xx>"), "bad dump\n");
+       testres |= EC_TEST_CHECK(
+               strstr(buf, "comp=<yy>"), "bad dump\n");
+       free(buf);
+       buf = NULL;
+
+       iter = ec_comp_iter(c, EC_COMP_ALL);
+       item = ec_comp_iter_next(iter);
+       if (item == NULL)
+               goto fail;
+
+       testres |= EC_TEST_CHECK(
+               !strcmp(ec_comp_item_get_display(item), "xx"),
+               "bad item display\n");
+       testres |= EC_TEST_CHECK(
+               ec_comp_item_get_type(item) == EC_COMP_FULL,
+               "bad item type\n");
+       testres |= EC_TEST_CHECK(
+               !strcmp(ec_node_id(ec_comp_item_get_node(item)), "id_x"),
+               "bad item node\n");
+
+       item = ec_comp_iter_next(iter);
+       if (item == NULL)
+               goto fail;
+
+       testres |= EC_TEST_CHECK(
+               !strcmp(ec_comp_item_get_display(item), "yy"),
+               "bad item display\n");
+       testres |= EC_TEST_CHECK(
+               ec_comp_item_get_type(item) == EC_COMP_FULL,
+               "bad item type\n");
+       testres |= EC_TEST_CHECK(
+               !strcmp(ec_node_id(ec_comp_item_get_node(item)), "id_y"),
+               "bad item node\n");
+
+       item = ec_comp_iter_next(iter);
+       testres |= EC_TEST_CHECK(item == NULL, "should be the last item\n");
+
+       ec_comp_iter_free(iter);
+       ec_comp_free(c);
+       ec_node_free(node);
+
+       return testres;
+
+fail:
+       ec_comp_iter_free(iter);
+       ec_comp_free(c);
+       ec_node_free(node);
+       if (f != NULL)
+               fclose(f);
+       free(buf);
+
+       return -1;
+}
+/* LCOV_EXCL_STOP */
+
+static struct ec_test ec_comp_test = {
+       .name = "comp",
+       .test = ec_comp_testcase,
+};
+
+EC_TEST_REGISTER(ec_comp_test);