summaryrefslogtreecommitdiff
path: root/ccan/tal/str/test
diff options
context:
space:
mode:
Diffstat (limited to 'ccan/tal/str/test')
-rw-r--r--ccan/tal/str/test/helper.h22
-rw-r--r--ccan/tal/str/test/run-fmt-terminate.c22
-rw-r--r--ccan/tal/str/test/run-string.c90
-rw-r--r--ccan/tal/str/test/run-strndup.c22
-rw-r--r--ccan/tal/str/test/run-strreg.c124
-rw-r--r--ccan/tal/str/test/run-take.c48
-rw-r--r--ccan/tal/str/test/run.c158
7 files changed, 486 insertions, 0 deletions
diff --git a/ccan/tal/str/test/helper.h b/ccan/tal/str/test/helper.h
new file mode 100644
index 0000000..5f0b68f
--- /dev/null
+++ b/ccan/tal/str/test/helper.h
@@ -0,0 +1,22 @@
+/* tal/talloc can't implement tal_first/tal_next. */
+#ifdef TAL_USE_TALLOC
+static inline bool no_children(const void *ctx)
+{
+ return talloc_total_blocks(ctx) == 1;
+}
+
+static inline bool single_child(const void *ctx, const void *child)
+{
+ return talloc_total_blocks(ctx) == 2 && tal_parent(child) == ctx;
+}
+#else
+static inline bool no_children(const void *ctx)
+{
+ return !tal_first(ctx);
+}
+
+static inline bool single_child(const void *ctx, const void *child)
+{
+ return tal_first(ctx) == child && !tal_next(child) && !tal_first(child);
+}
+#endif
diff --git a/ccan/tal/str/test/run-fmt-terminate.c b/ccan/tal/str/test/run-fmt-terminate.c
new file mode 100644
index 0000000..374ca03
--- /dev/null
+++ b/ccan/tal/str/test/run-fmt-terminate.c
@@ -0,0 +1,22 @@
+#include <ccan/tal/str/str.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ccan/tal/str/str.c>
+#include <ccan/tap/tap.h>
+#include "helper.h"
+
+/* Empty format string: should still terminate! */
+int main(void)
+{
+ char *str;
+ const char *fmt = "";
+
+ plan_tests(1);
+ /* GCC complains about empty format string, complains about non-literal
+ * with no args... */
+ str = tal_fmt(NULL, fmt, "");
+ ok1(!strcmp(str, ""));
+ tal_free(str);
+
+ return exit_status();
+}
diff --git a/ccan/tal/str/test/run-string.c b/ccan/tal/str/test/run-string.c
new file mode 100644
index 0000000..533ad01
--- /dev/null
+++ b/ccan/tal/str/test/run-string.c
@@ -0,0 +1,90 @@
+#include <ccan/tal/str/str.h>
+#include <ccan/tal/str/str.c>
+#include <ccan/tap/tap.h>
+#include "helper.h"
+
+int main(void)
+{
+ char *parent, *c;
+
+ plan_tests(32);
+
+ parent = tal(NULL, char);
+ ok1(parent);
+
+ c = tal_strdup(parent, "hello");
+ ok1(strcmp(c, "hello") == 0);
+ ok1(tal_parent(c) == parent);
+ tal_free(c);
+
+ c = tal_strndup(parent, "hello", 3);
+ ok1(strcmp(c, "hel") == 0);
+ ok1(tal_parent(c) == parent);
+ tal_free(c);
+
+#ifdef TAL_USE_TALLOC
+ c = tal_talloc_typechk_(parent, char *);
+#else
+ c = tal_typechk_(parent, char *);
+#endif
+ c = tal_dup_arr(parent, char, "hello", 6, 0);
+ ok1(strcmp(c, "hello") == 0);
+ ok1(strcmp(tal_name(c), "char[]") == 0);
+ ok1(tal_parent(c) == parent);
+ tal_free(c);
+
+ /* Now with an extra byte. */
+ c = tal_dup_arr(parent, char, "hello", 6, 1);
+ ok1(strcmp(c, "hello") == 0);
+ ok1(strcmp(tal_name(c), "char[]") == 0);
+ ok1(tal_parent(c) == parent);
+ strcat(c, "x");
+ tal_free(c);
+
+ c = tal_fmt(parent, "hello %s", "there");
+ ok1(strcmp(c, "hello there") == 0);
+ ok1(tal_parent(c) == parent);
+ tal_free(c);
+
+ c = tal_strcat(parent, "hello ", "there");
+ ok1(strcmp(c, "hello there") == 0);
+ ok1(tal_parent(c) == parent);
+
+ /* Make sure take works correctly. */
+ c = tal_strcat(parent, take(c), " again");
+ ok1(strcmp(c, "hello there again") == 0);
+ ok1(tal_parent(c) == parent);
+ ok1(single_child(parent, c));
+
+ c = tal_strcat(parent, "And ", take(c));
+ ok1(strcmp(c, "And hello there again") == 0);
+ ok1(tal_parent(c) == parent);
+ ok1(single_child(parent, c));
+
+ /* NULL pass through works... */
+ c = tal_strcat(parent, take(NULL), take(c));
+ ok1(!c);
+ ok1(no_children(parent));
+
+ c = tal_strcat(parent, take(tal_strdup(parent, "hi")),
+ take(NULL));
+ ok1(!c);
+ ok1(no_children(parent));
+
+ c = tal_strcat(parent, take(NULL), take(NULL));
+ ok1(!c);
+ ok1(no_children(parent));
+
+ /* Appending formatted strings. */
+ c = tal_strdup(parent, "hi");
+ ok1(tal_append_fmt(&c, "%s %s", "there", "world"));
+ ok1(strcmp(c, "hithere world") == 0);
+ ok1(tal_parent(c) == parent);
+
+ ok1(!tal_append_fmt(&c, take(NULL), "there", "world"));
+ ok1(strcmp(c, "hithere world") == 0);
+
+ tal_free(parent);
+
+ return exit_status();
+}
diff --git a/ccan/tal/str/test/run-strndup.c b/ccan/tal/str/test/run-strndup.c
new file mode 100644
index 0000000..55e35fd
--- /dev/null
+++ b/ccan/tal/str/test/run-strndup.c
@@ -0,0 +1,22 @@
+#include <ccan/tal/str/str.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ccan/tal/str/str.c>
+#include <ccan/tap/tap.h>
+#include "helper.h"
+
+int main(void)
+{
+ char *str, *copy;
+
+ plan_tests(1);
+ str = malloc(5);
+ memcpy(str, "hello", 5);
+ /* We should be fine to strndup src without nul terminator. */
+ copy = tal_strndup(NULL, str, 5);
+ ok1(!strcmp(copy, "hello"));
+ tal_free(copy);
+ free(str);
+
+ return exit_status();
+}
diff --git a/ccan/tal/str/test/run-strreg.c b/ccan/tal/str/test/run-strreg.c
new file mode 100644
index 0000000..93b8602
--- /dev/null
+++ b/ccan/tal/str/test/run-strreg.c
@@ -0,0 +1,124 @@
+#include <ccan/tal/str/str.h>
+#include <ccan/tal/str/str.c>
+#include <ccan/tap/tap.h>
+#include "helper.h"
+
+static bool find_parent(tal_t *child, tal_t *parent)
+{
+ tal_t *i;
+
+ for (i = child; i; i = tal_parent(i))
+ if (i == parent)
+ return true;
+
+ return false;
+}
+
+int main(void)
+{
+ void *ctx = tal_strdup(NULL, "toplevel");
+ char *a, *b;
+ /* If it accesses this, it will crash. */
+ char **invalid = (char **)1L;
+
+ plan_tests(41);
+ /* Simple matching. */
+ ok1(tal_strreg(ctx, "hello world!", "hello") == true);
+ ok1(tal_strreg(ctx, "hello world!", "hi") == false);
+
+ /* No parentheses means we don't use any extra args. */
+ ok1(tal_strreg(ctx, "hello world!", "hello", invalid) == true);
+ ok1(tal_strreg(ctx, "hello world!", "hi", invalid) == false);
+
+ ok1(tal_strreg(ctx, "hello world!", "[a-z]+", invalid) == true);
+ ok1(tal_strreg(ctx, "hello world!", "([a-z]+)", &a, invalid) == true);
+ /* Found string */
+ ok1(streq(a, "hello"));
+ /* Allocated off ctx */
+ ok1(find_parent(a, ctx));
+ tal_free(a);
+
+ ok1(tal_strreg(ctx, "hello world!", "([a-z]*) ([a-z]+)",
+ &a, &b, invalid) == true);
+ ok1(streq(a, "hello"));
+ ok1(streq(b, "world"));
+ ok1(find_parent(a, ctx));
+ ok1(find_parent(b, ctx));
+ tal_free(a);
+ tal_free(b);
+
+ /* * after parentheses returns last match. */
+ ok1(tal_strreg(ctx, "hello world!", "([a-z])* ([a-z]+)",
+ &a, &b, invalid) == true);
+ ok1(streq(a, "o"));
+ ok1(streq(b, "world"));
+ tal_free(a);
+ tal_free(b);
+
+ /* Nested parentheses are ordered by open brace. */
+ ok1(tal_strreg(ctx, "hello world!", "(([a-z]*) world)",
+ &a, &b, invalid) == true);
+ ok1(streq(a, "hello world"));
+ ok1(streq(b, "hello"));
+ tal_free(a);
+ tal_free(b);
+
+ /* Nested parentheses are ordered by open brace. */
+ ok1(tal_strreg(ctx, "hello world!", "(([a-z]*) world)",
+ &a, &b, invalid) == true);
+ ok1(streq(a, "hello world"));
+ ok1(streq(b, "hello"));
+ tal_free(a);
+ tal_free(b);
+
+ /* NULL means we're not interested. */
+ ok1(tal_strreg(ctx, "hello world!", "((hello|goodbye) world)",
+ &a, NULL, invalid) == true);
+ ok1(streq(a, "hello world"));
+ tal_free(a);
+
+ /* No leaks! */
+ ok1(no_children(ctx));
+
+ /* NULL arg with take means always fail. */
+ ok1(tal_strreg(ctx, take(NULL), "((hello|goodbye) world)",
+ &b, NULL, invalid) == false);
+
+ /* Take string. */
+ a = tal_strdup(ctx, "hello world!");
+ ok1(tal_strreg(ctx, take(a), "([a-z]+)", &b, invalid) == true);
+ ok1(streq(b, "hello"));
+ ok1(tal_parent(b) == ctx);
+ tal_free(b);
+ ok1(no_children(ctx));
+
+ /* Take regex. */
+ a = tal_strdup(ctx, "([a-z]+)");
+ ok1(tal_strreg(ctx, "hello world!", take(a), &b, invalid) == true);
+ ok1(streq(b, "hello"));
+ ok1(tal_parent(b) == ctx);
+ tal_free(b);
+ ok1(no_children(ctx));
+
+ /* Take both. */
+ a = tal_strdup(ctx, "([a-z]+)");
+ ok1(tal_strreg(ctx, take(tal_strdup(ctx, "hello world!")),
+ take(a), &b, invalid) == true);
+ ok1(streq(b, "hello"));
+ ok1(tal_parent(b) == ctx);
+ tal_free(b);
+ ok1(no_children(ctx));
+
+ /* ... even if we fail to match. */
+ a = tal_strdup(ctx, "([a-z]+)");
+ ok1(tal_strreg(ctx, take(tal_strdup(ctx, "HELLO WORLD!")),
+ take(a), &b, invalid) == false);
+ ok1(no_children(ctx));
+ tal_free(ctx);
+
+ /* Don't get fooled by \(! */
+ ok1(tal_strreg(ctx, "(hello) (world)!", "\\([a-z]*\\) \\([a-z]+\\)",
+ invalid) == true);
+
+ return exit_status();
+}
diff --git a/ccan/tal/str/test/run-take.c b/ccan/tal/str/test/run-take.c
new file mode 100644
index 0000000..edf173f
--- /dev/null
+++ b/ccan/tal/str/test/run-take.c
@@ -0,0 +1,48 @@
+#include <ccan/tal/str/str.h>
+#include <ccan/tal/str/str.c>
+#include <ccan/tap/tap.h>
+#include "helper.h"
+
+int main(void)
+{
+ char *parent, *c;
+
+ plan_tests(14);
+
+ parent = tal(NULL, char);
+ ok1(parent);
+
+ c = tal_strdup(parent, "hello");
+
+ c = tal_strdup(parent, take(c));
+ ok1(strcmp(c, "hello") == 0);
+ ok1(tal_parent(c) == parent);
+
+ c = tal_strndup(parent, take(c), 5);
+ ok1(strcmp(c, "hello") == 0);
+ ok1(tal_parent(c) == parent);
+
+ c = tal_strndup(parent, take(c), 3);
+ ok1(strcmp(c, "hel") == 0);
+ ok1(tal_parent(c) == parent);
+ tal_free(c);
+
+ c = tal_strdup(parent, "hello %s");
+ c = tal_fmt(parent, take(c), "there");
+ ok1(strcmp(c, "hello there") == 0);
+ ok1(tal_parent(c) == parent);
+ /* No leftover allocations. */
+ tal_free(c);
+ ok1(no_children(parent));
+
+ tal_free(parent);
+ ok1(!taken_any());
+
+ /* NULL pass-through. */
+ c = NULL;
+ ok1(tal_strdup(NULL, take(c)) == NULL);
+ ok1(tal_strndup(NULL, take(c), 5) == NULL);
+ ok1(tal_fmt(NULL, take(c), 0) == NULL);
+
+ return exit_status();
+}
diff --git a/ccan/tal/str/test/run.c b/ccan/tal/str/test/run.c
new file mode 100644
index 0000000..a59d940
--- /dev/null
+++ b/ccan/tal/str/test/run.c
@@ -0,0 +1,158 @@
+#include <ccan/tal/str/str.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ccan/tal/str/str.c>
+#include <ccan/tap/tap.h>
+#include "helper.h"
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
+
+static const char *substrings[]
+= { "far", "bar", "baz", "b", "ba", "z", "ar", NULL };
+
+int main(void)
+{
+ char **split, *str;
+ void *ctx;
+
+ plan_tests(69);
+ split = tal_strsplit(NULL, "hello world", " ", STR_EMPTY_OK);
+ ok1(!strcmp(split[0], "hello"));
+ ok1(!strcmp(split[1], ""));
+ ok1(!strcmp(split[2], "world"));
+ ok1(split[3] == NULL);
+ ok1(tal_count(split) == 4);
+ tal_free(split);
+
+ split = tal_strsplit(NULL, "hello world", " ", STR_NO_EMPTY);
+ ok1(!strcmp(split[0], "hello"));
+ ok1(!strcmp(split[1], "world"));
+ ok1(split[2] == NULL);
+ ok1(tal_count(split) == 3);
+ tal_free(split);
+
+ split = tal_strsplit(NULL, " hello world", " ", STR_NO_EMPTY);
+ ok1(!strcmp(split[0], "hello"));
+ ok1(!strcmp(split[1], "world"));
+ ok1(split[2] == NULL);
+ ok1(tal_count(split) == 3);
+ tal_free(split);
+
+ split = tal_strsplit(NULL, "hello world", "o ", STR_EMPTY_OK);
+ ok1(!strcmp(split[0], "hell"));
+ ok1(!strcmp(split[1], ""));
+ ok1(!strcmp(split[2], ""));
+ ok1(!strcmp(split[3], "w"));
+ ok1(!strcmp(split[4], "rld"));
+ ok1(split[5] == NULL);
+ ok1(tal_count(split) == 6);
+
+ ctx = split;
+ split = tal_strsplit(ctx, "hello world", "o ", STR_EMPTY_OK);
+ ok1(tal_parent(split) == ctx);
+ tal_free(ctx);
+
+ str = tal_strjoin(NULL, (char **)substrings, ", ", STR_TRAIL);
+ ok1(!strcmp(str, "far, bar, baz, b, ba, z, ar, "));
+ ctx = str;
+ str = tal_strjoin(ctx, (char **)substrings, "", STR_TRAIL);
+ ok1(!strcmp(str, "farbarbazbbazar"));
+ ok1(tal_parent(str) == ctx);
+ str = tal_strjoin(ctx, (char **)substrings, ", ", STR_NO_TRAIL);
+ ok1(tal_parent(str) == ctx);
+ ok1(!strcmp(str, "far, bar, baz, b, ba, z, ar"));
+ str = tal_strjoin(ctx, (char **)substrings, "", STR_NO_TRAIL);
+ ok1(!strcmp(str, "farbarbazbbazar"));
+ ok1(tal_parent(str) == ctx);
+ tal_free(ctx);
+
+ ctx = tal_strdup(NULL, "context");
+ /* Pass through NULLs from take. */
+ ok1(tal_strsplit(NULL, take(NULL), " ", STR_EMPTY_OK) == NULL);
+ ok1(tal_strsplit(NULL, "foo", take(NULL), STR_EMPTY_OK) == NULL);
+
+ /* tal_strsplit take string. It reallocs it to same size, but
+ * that sometimes causes a move, so we can't directly check
+ * that split[0] == str. */
+ str = tal_strdup(ctx, "hello world");
+ ok1(tal_check(ctx, NULL));
+ ok1(tal_check(str, NULL));
+ split = tal_strsplit(ctx, take(str), " ", STR_EMPTY_OK);
+ ok1(tal_parent(split) == ctx);
+ ok1(!strcmp(split[0], "hello"));
+ ok1(!strcmp(split[1], "world"));
+ ok1(split[2] == NULL);
+ ok1(tal_check(split, NULL));
+ ok1(tal_check(ctx, NULL));
+ tal_free(split);
+ /* Previous free should get rid of str */
+ ok1(no_children(ctx));
+
+ /* tal_strsplit take delims */
+ str = tal_strdup(ctx, " ");
+ split = tal_strsplit(ctx, "hello world", take(str), STR_EMPTY_OK);
+ ok1(tal_parent(split) == ctx);
+ ok1(!strcmp(split[0], "hello"));
+ ok1(!strcmp(split[1], "world"));
+ ok1(split[2] == NULL);
+ ok1(tal_check(split, NULL));
+ ok1(tal_check(ctx, NULL));
+ tal_free(split);
+ /* str is gone... */
+ ok1(no_children(ctx));
+
+ /* tal_strsplit takes both. */
+ split = tal_strsplit(ctx, take(tal_strdup(NULL, "hello world")),
+ take(tal_strdup(NULL, " ")), STR_EMPTY_OK);
+ ok1(tal_parent(split) == ctx);
+ ok1(!strcmp(split[0], "hello"));
+ ok1(!strcmp(split[1], "world"));
+ ok1(split[2] == NULL);
+ ok1(tal_check(split, NULL));
+ ok1(tal_check(ctx, NULL));
+ tal_free(split);
+ /* temp allocs are gone... */
+ ok1(no_children(ctx));
+
+ /* tal_strjoin passthrough taken NULLs OK. */
+ ok1(tal_strjoin(ctx, take(NULL), "", STR_TRAIL) == NULL);
+ ok1(tal_strjoin(ctx, take(NULL), "", STR_NO_TRAIL) == NULL);
+ ok1(tal_strjoin(ctx, split, take(NULL), STR_TRAIL) == NULL);
+ ok1(tal_strjoin(ctx, split, take(NULL), STR_NO_TRAIL) == NULL);
+
+ /* tal_strjoin take strings[] */
+ split = tal_strsplit(ctx, "hello world", " ", STR_EMPTY_OK);
+ str = tal_strjoin(ctx, take(split), " there ", STR_NO_TRAIL);
+ ok1(!strcmp(str, "hello there world"));
+ ok1(tal_parent(str) == ctx);
+ /* split is gone... */
+ ok1(single_child(ctx, str));
+ tal_free(str);
+ ok1(no_children(ctx));
+
+ /* tal_strjoin take delim */
+ split = tal_strsplit(ctx, "hello world", " ", STR_EMPTY_OK);
+ str = tal_strjoin(ctx, split, take(tal_strdup(ctx, " there ")),
+ STR_NO_TRAIL);
+ ok1(!strcmp(str, "hello there world"));
+ ok1(tal_parent(str) == ctx);
+ tal_free(split);
+ /* tmp alloc is gone, str is only remainder. */
+ ok1(single_child(ctx, str));
+ tal_free(str);
+ ok1(no_children(ctx));
+
+ /* tal_strjoin take both. */
+ str = tal_strjoin(ctx, take(tal_strsplit(ctx, "hello world", " ",
+ STR_EMPTY_OK)),
+ take(tal_strdup(ctx, " there ")), STR_NO_TRAIL);
+ ok1(!strcmp(str, "hello there world"));
+ ok1(tal_parent(str) == ctx);
+ /* tmp allocs are gone, str is only remainder. */
+ ok1(single_child(ctx, str));
+ tal_free(str);
+ ok1(no_children(ctx));
+ tal_free(ctx);
+
+ return exit_status();
+}