#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 */
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);
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) {
comp->cur_group = cur_group;
if (ret < 0)
- return ret;
+ return -1;
return 0;
}
}
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;
goto fail;
}
- item->node = node;
item->type = type;
item->start = start_cp;
item->full = full_cp;
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)
fail:
ec_free(display_copy);
- return ret;
+ return -1;
}
int
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;
fail:
ec_free(completion_copy);
- return ret;
+ return -1;
}
int
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;
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:
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;
}
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)
{
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;
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;
{
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);