diff options
| -rw-r--r-- | .gitmodules | 3 | ||||
| -rw-r--r-- | Makefile.am | 43 | ||||
| -rw-r--r-- | configure.ac | 24 | ||||
| m--------- | squareball | 0 | ||||
| -rw-r--r-- | src/utils.c | 612 | ||||
| -rw-r--r-- | src/utils.h | 102 | ||||
| -rw-r--r-- | tests/check_source_parser.c | 2 | ||||
| -rw-r--r-- | tests/check_utils.c | 959 | 
8 files changed, 1694 insertions, 51 deletions
diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 061fb99..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "squareball"] -	path = squareball -	url = https://github.com/rafaelmartins/squareball.git diff --git a/Makefile.am b/Makefile.am index a0559ea..8237508 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,16 +1,11 @@  ## Autotools settings -if INTERNAL_SQUAREBALL -SUBDIRS = squareball -endif -  ACLOCAL_AMFLAGS = -I m4  AM_DISTCHECK_CONFIGURE_FLAGS = \  	--enable-tests \  	--enable-ronn \  	--disable-valgrind \ -	--with-squareball=internal \  	$(NULL) @@ -43,6 +38,7 @@ noinst_HEADERS = \  	src/renderer.h \  	src/source-parser.h \  	src/template-parser.h \ +	src/utils.h \  	$(NULL)  noinst_LTLIBRARIES = \ @@ -69,17 +65,16 @@ libblogc_la_SOURCES = \  	src/renderer.c \  	src/source-parser.c \  	src/template-parser.c \ +	src/utils.c \  	$(NULL)  libblogc_la_CFLAGS = \  	$(AM_CFLAGS) \  	-I$(top_srcdir)/src \ -	$(SQUAREBALL_CFLAGS) \  	$(NULL)  libblogc_la_LIBADD = \  	$(LIBM) \ -	$(SQUAREBALL_LIBS) \  	$(NULL) @@ -90,12 +85,10 @@ blogc_SOURCES = \  blogc_CFLAGS = \  	$(AM_CFLAGS) \  	-I$(top_srcdir)/src \ -	$(SQUAREBALL_CFLAGS) \  	$(NULL)  blogc_LDADD = \  	libblogc.la \ -	$(SQUAREBALL_LIBS) \  	$(NULL) @@ -170,6 +163,7 @@ check_PROGRAMS += \  	tests/check_renderer \  	tests/check_source_parser \  	tests/check_template_parser \ +	tests/check_utils \  	$(NULL)  tests_check_error_SOURCES = \ @@ -177,7 +171,6 @@ tests_check_error_SOURCES = \  	$(NULL)  tests_check_error_CFLAGS = \ -	$(SQUAREBALL_CFLAGS) \  	$(CMOCKA_CFLAGS) \  	$(NULL) @@ -186,7 +179,6 @@ tests_check_error_LDFLAGS = \  	$(NULL)  tests_check_error_LDADD = \ -	$(SQUAREBALL_LIBS) \  	$(CMOCKA_LIBS) \  	libblogc.la \  	$(NULL) @@ -196,7 +188,6 @@ tests_check_loader_SOURCES = \  	$(NULL)  tests_check_loader_CFLAGS = \ -	$(SQUAREBALL_CFLAGS) \  	$(CMOCKA_CFLAGS) \  	$(NULL) @@ -207,7 +198,6 @@ tests_check_loader_LDFLAGS = \  	$(NULL)  tests_check_loader_LDADD = \ -	$(SQUAREBALL_LIBS) \  	$(CMOCKA_LIBS) \  	libblogc.la \  	$(NULL) @@ -217,7 +207,6 @@ tests_check_content_parser_SOURCES = \  	$(NULL)  tests_check_content_parser_CFLAGS = \ -	$(SQUAREBALL_CFLAGS) \  	$(CMOCKA_CFLAGS) \  	$(NULL) @@ -226,7 +215,6 @@ tests_check_content_parser_LDFLAGS = \  	$(NULL)  tests_check_content_parser_LDADD = \ -	$(SQUAREBALL_LIBS) \  	$(CMOCKA_LIBS) \  	libblogc.la \  	$(NULL) @@ -236,7 +224,6 @@ tests_check_datetime_parser_SOURCES = \  	$(NULL)  tests_check_datetime_parser_CFLAGS = \ -	$(SQUAREBALL_CFLAGS) \  	$(CMOCKA_CFLAGS) \  	$(NULL) @@ -245,7 +232,6 @@ tests_check_datetime_parser_LDFLAGS = \  	$(NULL)  tests_check_datetime_parser_LDADD = \ -	$(SQUAREBALL_LIBS) \  	$(CMOCKA_LIBS) \  	libblogc.la \  	$(NULL) @@ -255,7 +241,6 @@ tests_check_renderer_SOURCES = \  	$(NULL)  tests_check_renderer_CFLAGS = \ -	$(SQUAREBALL_CFLAGS) \  	$(CMOCKA_CFLAGS) \  	$(NULL) @@ -264,7 +249,6 @@ tests_check_renderer_LDFLAGS = \  	$(NULL)  tests_check_renderer_LDADD = \ -	$(SQUAREBALL_LIBS) \  	$(CMOCKA_LIBS) \  	libblogc.la \  	$(NULL) @@ -274,7 +258,6 @@ tests_check_source_parser_SOURCES = \  	$(NULL)  tests_check_source_parser_CFLAGS = \ -	$(SQUAREBALL_CFLAGS) \  	$(CMOCKA_CFLAGS) \  	$(NULL) @@ -283,7 +266,6 @@ tests_check_source_parser_LDFLAGS = \  	$(NULL)  tests_check_source_parser_LDADD = \ -	$(SQUAREBALL_LIBS) \  	$(CMOCKA_LIBS) \  	libblogc.la \  	$(NULL) @@ -293,7 +275,6 @@ tests_check_template_parser_SOURCES = \  	$(NULL)  tests_check_template_parser_CFLAGS = \ -	$(SQUAREBALL_CFLAGS) \  	$(CMOCKA_CFLAGS) \  	$(NULL) @@ -302,7 +283,23 @@ tests_check_template_parser_LDFLAGS = \  	$(NULL)  tests_check_template_parser_LDADD = \ -	$(SQUAREBALL_LIBS) \ +	$(CMOCKA_LIBS) \ +	libblogc.la \ +	$(NULL) + +tests_check_utils_SOURCES = \ +	tests/check_utils.c \ +	$(NULL) + +tests_check_utils_CFLAGS = \ +	$(CMOCKA_CFLAGS) \ +	$(NULL) + +tests_check_utils_LDFLAGS = \ +	-no-install \ +	$(NULL) + +tests_check_utils_LDADD = \  	$(CMOCKA_LIBS) \  	libblogc.la \  	$(NULL) diff --git a/configure.ac b/configure.ac index 0bc1e19..1e7366e 100644 --- a/configure.ac +++ b/configure.ac @@ -123,29 +123,6 @@ AC_CHECK_HEADERS([sys/types.h sys/stat.h time.h])  LT_LIB_M -AC_ARG_WITH([squareball], [AS_HELP_STRING([--with-squareball=@<:@internal/system@:>@], -            [whether to use library squareball from system [default=internal]])]) -AS_IF([test "x$with_squareball" = "xsystem"], [ -  SQUAREBALL="system" -  PKG_CHECK_MODULES([SQUAREBALL], [squareball >= 0.2.0], , [ -    AC_MSG_ERROR([library squareball requested from system but not found or not new enough]) -  ]) -], [ -  SQUAREBALL="internal" -  SQUAREBALL_CFLAGS='-I$(top_srcdir)/squareball/src' -  SQUAREBALL_LIBS='$(top_builddir)/squareball/libsquareball.la' -  AC_SUBST(SQUAREBALL_LIBS) -  AC_SUBST(SQUAREBALL_CFLAGS) -  ac_configure_args_pre="$ac_configure_args" -  ac_configure_args_post="$ac_configure_args --enable-bundleme" -  ac_configure_args="$ac_configure_args_post" -  AC_CONFIG_COMMANDS_PRE([ac_configure_args="$ac_configure_args_pre"]) -  AC_CONFIG_COMMANDS_POST([ac_configure_args="$ac_configure_args_post"]) -  AC_CONFIG_SUBDIRS([squareball]) -  ac_configure_args="$ac_configure_args_pre" -]) -AM_CONDITIONAL(INTERNAL_SQUAREBALL, [test "x$with_squareball" != "xsystem"]) -  AC_CONFIG_FILES([    Makefile    blogc.spec @@ -164,7 +141,6 @@ AS_ECHO("          cflags:       ${CFLAGS}          ldflags:      ${LDFLAGS} -        squareball:   ${SQUAREBALL}          tests:        ${TESTS}          ronn:         ${RONN} diff --git a/squareball b/squareball deleted file mode 160000 -Subproject e2639b044e450ed54cf6e768ed2eb8b88e5c055 diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..855b503 --- /dev/null +++ b/src/utils.c @@ -0,0 +1,612 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2014-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br> + * + * This program can be distributed under the terms of the BSD License. + * See the file LICENSE. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif /* HAVE_CONFIG_H */ + +#define SB_STRING_CHUNK_SIZE 128 + +#include <ctype.h> +#include <string.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdio.h> + +#include "utils.h" + + +void* +sb_malloc(size_t size) +{ +    // simple things simple! +    void *rv = malloc(size); +    if (rv == NULL) { +        fprintf(stderr, "fatal: Failed to allocate memory!\n"); +        abort(); +    } +    return rv; +} + + +void* +sb_realloc(void *ptr, size_t size) +{ +    // simple things even simpler :P +    void *rv = realloc(ptr, size); +    if (rv == NULL && size != 0) { +        fprintf(stderr, "fatal: Failed to reallocate memory!\n"); +        free(ptr); +        abort(); +    } +    return rv; +} + + +sb_slist_t* +sb_slist_append(sb_slist_t *l, void *data) +{ +    sb_slist_t *node = sb_malloc(sizeof(sb_slist_t)); +    node->data = data; +    node->next = NULL; +    if (l == NULL) { +        l = node; +    } +    else { +        sb_slist_t *tmp; +        for (tmp = l; tmp->next != NULL; tmp = tmp->next); +        tmp->next = node; +    } +    return l; +} + + +sb_slist_t* +sb_slist_prepend(sb_slist_t *l, void *data) +{ +    sb_slist_t *node = sb_malloc(sizeof(sb_slist_t)); +    node->data = data; +    node->next = l; +    l = node; +    return l; +} + + +void +sb_slist_free_full(sb_slist_t *l, sb_free_func_t free_func) +{ +    while (l != NULL) { +        sb_slist_t *tmp = l->next; +        if ((free_func != NULL) && (l->data != NULL)) +            free_func(l->data); +        free(l); +        l = tmp; +    } +} + + +void +sb_slist_free(sb_slist_t *l) +{ +    sb_slist_free_full(l, NULL); +} + + +size_t +sb_slist_length(sb_slist_t *l) +{ +    if (l == NULL) +        return 0; +    size_t i; +    sb_slist_t *tmp; +    for (tmp = l, i = 0; tmp != NULL; tmp = tmp->next, i++); +    return i; +} + + +char* +sb_strdup(const char *s) +{ +    if (s == NULL) +        return NULL; +    size_t l = strlen(s); +    char *tmp = malloc(l + 1); +    if (tmp == NULL) +        return NULL; +    memcpy(tmp, s, l + 1); +    return tmp; +} + + +char* +sb_strndup(const char *s, size_t n) +{ +    if (s == NULL) +        return NULL; +    size_t l = strnlen(s, n); +    char *tmp = malloc(l + 1); +    if (tmp == NULL) +        return NULL; +    memcpy(tmp, s, l); +    tmp[l] = '\0'; +    return tmp; +} + + +char* +sb_strdup_vprintf(const char *format, va_list ap) +{ +    va_list ap2; +    va_copy(ap2, ap); +    int l = vsnprintf(NULL, 0, format, ap2); +    va_end(ap2); +    if (l < 0) +        return NULL; +    char *tmp = malloc(l + 1); +    if (!tmp) +        return NULL; +    int l2 = vsnprintf(tmp, l + 1, format, ap); +    if (l2 < 0) { +        free(tmp); +        return NULL; +    } +    return tmp; +} + + +char* +sb_strdup_printf(const char *format, ...) +{ +    va_list ap; +    va_start(ap, format); +    char *tmp = sb_strdup_vprintf(format, ap); +    va_end(ap); +    return tmp; +} + + +bool +sb_str_starts_with(const char *str, const char *prefix) +{ +    int str_l = strlen(str); +    int str_lp = strlen(prefix); +    if (str_lp > str_l) +        return false; +    return strncmp(str, prefix, str_lp) == 0; +} + + +bool +sb_str_ends_with(const char *str, const char *suffix) +{ +    int str_l = strlen(str); +    int str_ls = strlen(suffix); +    if (str_ls > str_l) +        return false; +    return strcmp(str + str_l - str_ls, suffix) == 0; +} + + +char* +sb_str_lstrip(char *str) +{ +    if (str == NULL) +        return NULL; +    int i; +    size_t str_len = strlen(str); +    for (i = 0; i < str_len; i++) { +        if ((str[i] != ' ') && (str[i] != '\t') && (str[i] != '\n') && +            (str[i] != '\r') && (str[i] != '\t') && (str[i] != '\f') && +            (str[i] != '\v')) +        { +            str += i; +            break; +        } +        if (i == str_len - 1) { +            str += str_len; +            break; +        } +    } +    return str; +} + + +char* +sb_str_rstrip(char *str) +{ +    if (str == NULL) +        return NULL; +    int i; +    size_t str_len = strlen(str); +    for (i = str_len - 1; i >= 0; i--) { +        if ((str[i] != ' ') && (str[i] != '\t') && (str[i] != '\n') && +            (str[i] != '\r') && (str[i] != '\t') && (str[i] != '\f') && +            (str[i] != '\v')) +        { +            str[i + 1] = '\0'; +            break; +        } +        if (i == 0) { +            str[0] = '\0'; +            break; +        } +    } +    return str; +} + + +char* +sb_str_strip(char *str) +{ +    return sb_str_lstrip(sb_str_rstrip(str)); +} + + +char** +sb_str_split(const char *str, char c, unsigned int max_pieces) +{ +    if (str == NULL) +        return NULL; +    char **rv = sb_malloc(sizeof(char*)); +    unsigned int i, start = 0, count = 0; +    for (i = 0; i < strlen(str) + 1; i++) { +        if (str[0] == '\0') +            break; +        if ((str[i] == c && (!max_pieces || count + 1 < max_pieces)) || str[i] == '\0') { +            rv = sb_realloc(rv, (count + 1) * sizeof(char*)); +            rv[count] = sb_malloc(i - start + 1); +            memcpy(rv[count], str + start, i - start); +            rv[count++][i - start] = '\0'; +            start = i + 1; +        } +    } +    rv = sb_realloc(rv, (count + 1) * sizeof(char*)); +    rv[count] = NULL; +    return rv; +} + + +char* +sb_str_replace(const char *str, const char search, const char *replace) +{ +    char **pieces = sb_str_split(str, search, 0); +    if (pieces == NULL) +        return NULL; +    char* rv = sb_strv_join(pieces, replace); +    sb_strv_free(pieces); +    if (rv == NULL) +        return sb_strdup(str); +    return rv; +} + + +void +sb_strv_free(char **strv) +{ +    if (strv == NULL) +        return; +    for (size_t i = 0; strv[i] != NULL; i++) +        free(strv[i]); +    free(strv); +} + + +char* +sb_strv_join(char **strv, const char *separator) +{ +    if (strv == NULL || separator == NULL) +        return NULL; +    sb_string_t *str = sb_string_new(); +    for (size_t i = 0; strv[i] != NULL; i++) { +        str = sb_string_append(str, strv[i]); +        if (strv[i + 1] != NULL) +            str = sb_string_append(str, separator); +    } +    return sb_string_free(str, false); +} + + +size_t +sb_strv_length(char **strv) +{ +    if (strv == NULL) +        return 0; +    size_t i; +    for (i = 0; strv[i] != NULL; i++); +    return i; +} + + +sb_string_t* +sb_string_new(void) +{ +    sb_string_t* rv = sb_malloc(sizeof(sb_string_t)); +    rv->str = NULL; +    rv->len = 0; +    rv->allocated_len = 0; + +    // initialize with empty string +    rv = sb_string_append(rv, ""); + +    return rv; +} + + +char* +sb_string_free(sb_string_t *str, bool free_str) +{ +    if (str == NULL) +        return NULL; +    char *rv = NULL; +    if (free_str) +        free(str->str); +    else +        rv = str->str; +    free(str); +    return rv; +} + + +sb_string_t* +sb_string_dup(sb_string_t *str) +{ +    if (str == NULL) +        return NULL; +    sb_string_t* new = sb_string_new(); +    return sb_string_append_len(new, str->str, str->len); +} + + +sb_string_t* +sb_string_append_len(sb_string_t *str, const char *suffix, size_t len) +{ +    if (str == NULL) +        return NULL; +    if (suffix == NULL) +        return str; +    size_t old_len = str->len; +    str->len += len; +    if (str->len + 1 > str->allocated_len) { +        str->allocated_len = (((str->len + 1) / SB_STRING_CHUNK_SIZE) + 1) * SB_STRING_CHUNK_SIZE; +        str->str = sb_realloc(str->str, str->allocated_len); +    } +    memcpy(str->str + old_len, suffix, len); +    str->str[str->len] = '\0'; +    return str; +} + + +sb_string_t* +sb_string_append(sb_string_t *str, const char *suffix) +{ +    if (str == NULL) +        return NULL; +    const char *my_suffix = suffix == NULL ? "" : suffix; +    return sb_string_append_len(str, my_suffix, strlen(my_suffix)); +} + + +sb_string_t* +sb_string_append_c(sb_string_t *str, char c) +{ +    if (str == NULL) +        return NULL; +    size_t old_len = str->len; +    str->len += 1; +    if (str->len + 1 > str->allocated_len) { +        str->allocated_len = (((str->len + 1) / SB_STRING_CHUNK_SIZE) + 1) * SB_STRING_CHUNK_SIZE; +        str->str = sb_realloc(str->str, str->allocated_len); +    } +    str->str[old_len] = c; +    str->str[str->len] = '\0'; +    return str; +} + + +sb_string_t* +sb_string_append_printf(sb_string_t *str, const char *format, ...) +{ +    if (str == NULL) +        return NULL; +    va_list ap; +    va_start(ap, format); +    char *tmp = sb_strdup_vprintf(format, ap); +    va_end(ap); +    str = sb_string_append(str, tmp); +    free(tmp); +    return str; +} + + +sb_trie_t* +sb_trie_new(sb_free_func_t free_func) +{ +    sb_trie_t *trie = sb_malloc(sizeof(sb_trie_t)); +    trie->root = NULL; +    trie->free_func = free_func; +    return trie; +} + + +static void +sb_trie_free_node(sb_trie_t *trie, sb_trie_node_t *node) +{ +    if (trie == NULL || node == NULL) +        return; +    if (node->data != NULL && trie->free_func != NULL) +        trie->free_func(node->data); +    sb_trie_free_node(trie, node->next); +    sb_trie_free_node(trie, node->child); +    free(node); +} + + +void +sb_trie_free(sb_trie_t *trie) +{ +    if (trie == NULL) +        return; +    sb_trie_free_node(trie, trie->root); +    free(trie); +} + + +void +sb_trie_insert(sb_trie_t *trie, const char *key, void *data) +{ +    if (trie == NULL || key == NULL || data == NULL) +        return; + +    sb_trie_node_t *parent = NULL; +    sb_trie_node_t *previous; +    sb_trie_node_t *current; +    sb_trie_node_t *tmp; + +    while (1) { + +        if (trie->root == NULL || (parent != NULL && parent->child == NULL)) { +            current = sb_malloc(sizeof(sb_trie_node_t)); +            current->key = *key; +            current->data = NULL; +            current->next = NULL; +            current->child = NULL; +            if (trie->root == NULL) +                trie->root = current; +            else +                parent->child = current; +            parent = current; +            goto clean; +        } + +        tmp = parent == NULL ? trie->root : parent->child; +        previous = NULL; + +        while (tmp != NULL && tmp->key != *key) { +            previous = tmp; +            tmp = tmp->next; +        } + +        parent = tmp; + +        if (previous == NULL || parent != NULL) +            goto clean; + +        current = sb_malloc(sizeof(sb_trie_node_t)); +        current->key = *key; +        current->data = NULL; +        current->next = NULL; +        current->child = NULL; +        previous->next = current; +        parent = current; + +clean: +        if (*key == '\0') { +            if (parent->data != NULL && trie->free_func != NULL) +                trie->free_func(parent->data); +            parent->data = data; +            break; +        } +        key++; +    } +} + + +void* +sb_trie_lookup(sb_trie_t *trie, const char *key) +{ +    if (trie == NULL || trie->root == NULL || key == NULL) +        return NULL; + +    sb_trie_node_t *parent = trie->root; +    sb_trie_node_t *tmp; +    while (1) { +        for (tmp = parent; tmp != NULL; tmp = tmp->next) { + +            if (tmp->key == *key) { +                if (tmp->key == '\0') +                    return tmp->data; +                parent = tmp->child; +                break; +            } +        } +        if (tmp == NULL) +            return NULL; + +        if (*key == '\0') +            break; +        key++; +    } +    return NULL; +} + + +static void +sb_trie_size_node(sb_trie_node_t *node, size_t *count) +{ +    if (node == NULL || count == NULL) +        return; + +    if (node->key == '\0') +        (*count)++; + +    sb_trie_size_node(node->next, count); +    sb_trie_size_node(node->child, count); +} + + +size_t +sb_trie_size(sb_trie_t *trie) +{ +    if (trie == NULL) +        return 0; + +    size_t count = 0; +    sb_trie_size_node(trie->root, &count); +    return count; +} + + +static void +sb_trie_foreach_node(sb_trie_node_t *node, sb_string_t *str, +    sb_trie_foreach_func_t func, void *user_data) +{ +    if (node == NULL || str == NULL || func == NULL) +        return; + +    if (node->key == '\0') { +        char *tmp = sb_string_free(str, false); +        func(tmp, node->data, user_data); +        free(tmp); +    } + +    if (node->child != NULL) { +        sb_string_t *child = sb_string_dup(str); +        child = sb_string_append_c(child, node->key); +        sb_trie_foreach_node(node->child, child, func, user_data); +    } + +    if (node->next != NULL) +        sb_trie_foreach_node(node->next, str, func, user_data); + +    if (node->child != NULL && node->next == NULL) +        sb_string_free(str, true); +} + + +void +sb_trie_foreach(sb_trie_t *trie, sb_trie_foreach_func_t func, +    void *user_data) +{ +    if (trie == NULL || trie->root == NULL || func == NULL) +        return; + +    sb_string_t *str = sb_string_new(); +    sb_trie_foreach_node(trie->root, str, func, user_data); +} diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..411295a --- /dev/null +++ b/src/utils.h @@ -0,0 +1,102 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2014-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br> + * + * This program can be distributed under the terms of the BSD License. + * See the file LICENSE. + */ + +#ifndef _UTILS_H +#define _UTILS_H + +#include <stddef.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdarg.h> +#include <stdlib.h> + + +// memory + +typedef void (*sb_free_func_t) (void *ptr); + +void* sb_malloc(size_t size); +void* sb_realloc(void *ptr, size_t size); + + +// slist + +typedef struct _sb_slist_t { +    struct _sb_slist_t *next; +    void *data; +} sb_slist_t; + +sb_slist_t* sb_slist_append(sb_slist_t *l, void *data); +sb_slist_t* sb_slist_prepend(sb_slist_t *l, void *data); +void sb_slist_free(sb_slist_t *l); +void sb_slist_free_full(sb_slist_t *l, sb_free_func_t free_func); +size_t sb_slist_length(sb_slist_t *l); + + +// strfuncs + +char* sb_strdup(const char *s); +char* sb_strndup(const char *s, size_t n); +char* sb_strdup_vprintf(const char *format, va_list ap); +char* sb_strdup_printf(const char *format, ...); +bool sb_str_starts_with(const char *str, const char *prefix); +bool sb_str_ends_with(const char *str, const char *suffix); +char* sb_str_lstrip(char *str); +char* sb_str_rstrip(char *str); +char* sb_str_strip(char *str); +char** sb_str_split(const char *str, char c, unsigned int max_pieces); +char* sb_str_replace(const char *str, const char search, const char *replace); +void sb_strv_free(char **strv); +char* sb_strv_join(char **strv, const char *separator); +size_t sb_strv_length(char **strv); + + +// string + +typedef struct { +    char *str; +    size_t len; +    size_t allocated_len; +} sb_string_t; + +sb_string_t* sb_string_new(void); +char* sb_string_free(sb_string_t *str, bool free_str); +sb_string_t* sb_string_dup(sb_string_t *str); +sb_string_t* sb_string_append_len(sb_string_t *str, const char *suffix, size_t len); +sb_string_t* sb_string_append(sb_string_t *str, const char *suffix); +sb_string_t* sb_string_append_c(sb_string_t *str, char c); +sb_string_t* sb_string_append_printf(sb_string_t *str, const char *format, ...); + + +// trie + +typedef struct _sb_trie_node_t { +    char key; +    void *data; +    struct _sb_trie_node_t *next, *child; +} sb_trie_node_t; + +struct _sb_trie_t { +    sb_trie_node_t *root; +    sb_free_func_t free_func; +}; + +typedef struct _sb_trie_t sb_trie_t; + +typedef void (*sb_trie_foreach_func_t)(const char *key, void *data, +    void *user_data); + +sb_trie_t* sb_trie_new(sb_free_func_t free_func); +void sb_trie_free(sb_trie_t *trie); +void sb_trie_insert(sb_trie_t *trie, const char *key, void *data); +void* sb_trie_lookup(sb_trie_t *trie, const char *key); +size_t sb_trie_size(sb_trie_t *trie); +void sb_trie_foreach(sb_trie_t *trie, sb_trie_foreach_func_t func, +    void *user_data); + +#endif /* _UTILS_H */ diff --git a/tests/check_source_parser.c b/tests/check_source_parser.c index 0f891dd..477399c 100644 --- a/tests/check_source_parser.c +++ b/tests/check_source_parser.c @@ -173,7 +173,7 @@ test_source_parse_with_description(void **state)          "# This is a test\n"          "\n"          "bola\n"; -    sb_error_t *err = NULL; +    blogc_error_t *err = NULL;      sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);      assert_null(err);      assert_non_null(source); diff --git a/tests/check_utils.c b/tests/check_utils.c new file mode 100644 index 0000000..6a6ceca --- /dev/null +++ b/tests/check_utils.c @@ -0,0 +1,959 @@ +/* + * blogc: A blog compiler. + * Copyright (C) 2014-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br> + * + * This program can be distributed under the terms of the BSD License. + * See the file LICENSE. + */ + +#include <stdarg.h> +#include <stddef.h> +#include <setjmp.h> +#include <cmocka.h> + +#include <stdlib.h> + +#include "../src/utils.h" + +#define SB_STRING_CHUNK_SIZE 128 + + +static void +test_slist_append(void **state) +{ +    sb_slist_t *l = NULL; +    l = sb_slist_append(l, (void*) sb_strdup("bola")); +    assert_non_null(l); +    assert_string_equal(l->data, "bola"); +    assert_null(l->next); +    l = sb_slist_append(l, (void*) sb_strdup("guda")); +    assert_non_null(l); +    assert_string_equal(l->data, "bola"); +    assert_non_null(l->next); +    assert_string_equal(l->next->data, "guda"); +    assert_null(l->next->next); +    sb_slist_free_full(l, free); +} + + +static void +test_slist_prepend(void **state) +{ +    sb_slist_t *l = NULL; +    l = sb_slist_prepend(l, (void*) sb_strdup("bola")); +    assert_non_null(l); +    assert_string_equal(l->data, "bola"); +    assert_null(l->next); +    l = sb_slist_prepend(l, (void*) sb_strdup("guda")); +    assert_non_null(l); +    assert_string_equal(l->data, "guda"); +    assert_non_null(l->next); +    assert_string_equal(l->next->data, "bola"); +    assert_null(l->next->next); +    sb_slist_free_full(l, free); +} + + +static void +test_slist_free(void **state) +{ +    sb_slist_t *l = NULL; +    char *t1 = sb_strdup("bola"); +    char *t2 = sb_strdup("guda"); +    char *t3 = sb_strdup("chunda"); +    l = sb_slist_append(l, (void*) t1); +    l = sb_slist_append(l, (void*) t2); +    l = sb_slist_append(l, (void*) t3); +    sb_slist_free(l); +    assert_string_equal(t1, "bola"); +    assert_string_equal(t2, "guda"); +    assert_string_equal(t3, "chunda"); +    free(t1); +    free(t2); +    free(t3); +} + + +static void +test_slist_length(void **state) +{ +    sb_slist_t *l = NULL; +    l = sb_slist_append(l, (void*) sb_strdup("bola")); +    l = sb_slist_append(l, (void*) sb_strdup("guda")); +    l = sb_slist_append(l, (void*) sb_strdup("chunda")); +    assert_int_equal(sb_slist_length(l), 3); +    sb_slist_free_full(l, free); +    assert_int_equal(sb_slist_length(NULL), 0); +} + + +static void +test_strdup(void **state) +{ +    char *str = sb_strdup("bola"); +    assert_string_equal(str, "bola"); +    free(str); +    str = sb_strdup(NULL); +    assert_null(str); +} + + +static void +test_strndup(void **state) +{ +    char *str = sb_strndup("bolaguda", 4); +    assert_string_equal(str, "bola"); +    free(str); +    str = sb_strndup("bolaguda", 30); +    assert_string_equal(str, "bolaguda"); +    free(str); +    str = sb_strndup("bolaguda", 8); +    assert_string_equal(str, "bolaguda"); +    free(str); +    str = sb_strdup(NULL); +    assert_null(str); +} + + +static void +test_strdup_printf(void **state) +{ +    char *str = sb_strdup_printf("bola"); +    assert_string_equal(str, "bola"); +    free(str); +    str = sb_strdup_printf("bola, %s", "guda"); +    assert_string_equal(str, "bola, guda"); +    free(str); +} + + +static void +test_str_starts_with(void **state) +{ +    assert_true(sb_str_starts_with("bolaguda", "bola")); +    assert_true(sb_str_starts_with("bola", "bola")); +    assert_false(sb_str_starts_with("gudabola", "bola")); +    assert_false(sb_str_starts_with("guda", "bola")); +    assert_false(sb_str_starts_with("bola", "bolaguda")); +} + + +static void +test_str_ends_with(void **state) +{ +    assert_true(sb_str_ends_with("bolaguda", "guda")); +    assert_true(sb_str_ends_with("bola", "bola")); +    assert_false(sb_str_ends_with("gudabola", "guda")); +    assert_false(sb_str_ends_with("guda", "bola")); +    assert_false(sb_str_ends_with("bola", "gudabola")); +} + + +static void +test_str_lstrip(void **state) +{ +    char *str = sb_strdup("  \tbola\n  \t"); +    assert_string_equal(sb_str_lstrip(str), "bola\n  \t"); +    free(str); +    str = sb_strdup("guda"); +    assert_string_equal(sb_str_lstrip(str), "guda"); +    free(str); +    str = sb_strdup("\n"); +    assert_string_equal(sb_str_lstrip(str), ""); +    free(str); +    str = sb_strdup("\t \n"); +    assert_string_equal(sb_str_lstrip(str), ""); +    free(str); +    str = sb_strdup(""); +    assert_string_equal(sb_str_lstrip(str), ""); +    free(str); +    assert_null(sb_str_lstrip(NULL)); +} + + +static void +test_str_rstrip(void **state) +{ +    char *str = sb_strdup("  \tbola\n  \t"); +    assert_string_equal(sb_str_rstrip(str), "  \tbola"); +    free(str); +    str = sb_strdup("guda"); +    assert_string_equal(sb_str_rstrip(str), "guda"); +    free(str); +    str = sb_strdup("\n"); +    assert_string_equal(sb_str_rstrip(str), ""); +    free(str); +    str = sb_strdup("\t \n"); +    assert_string_equal(sb_str_rstrip(str), ""); +    free(str); +    str = sb_strdup(""); +    assert_string_equal(sb_str_rstrip(str), ""); +    free(str); +    assert_null(sb_str_rstrip(NULL)); +} + + +static void +test_str_strip(void **state) +{ +    char *str = sb_strdup("  \tbola\n  \t"); +    assert_string_equal(sb_str_strip(str), "bola"); +    free(str); +    str = sb_strdup("guda"); +    assert_string_equal(sb_str_strip(str), "guda"); +    free(str); +    str = sb_strdup("\n"); +    assert_string_equal(sb_str_strip(str), ""); +    free(str); +    str = sb_strdup("\t \n"); +    assert_string_equal(sb_str_strip(str), ""); +    free(str); +    str = sb_strdup(""); +    assert_string_equal(sb_str_strip(str), ""); +    free(str); +    assert_null(sb_str_strip(NULL)); +} + + +static void +test_str_split(void **state) +{ +    char **strv = sb_str_split("bola:guda:chunda", ':', 0); +    assert_string_equal(strv[0], "bola"); +    assert_string_equal(strv[1], "guda"); +    assert_string_equal(strv[2], "chunda"); +    assert_null(strv[3]); +    sb_strv_free(strv); +    strv = sb_str_split("bola:guda:chunda", ':', 2); +    assert_string_equal(strv[0], "bola"); +    assert_string_equal(strv[1], "guda:chunda"); +    assert_null(strv[2]); +    sb_strv_free(strv); +    strv = sb_str_split("bola:guda:chunda", ':', 1); +    assert_string_equal(strv[0], "bola:guda:chunda"); +    assert_null(strv[1]); +    sb_strv_free(strv); +    strv = sb_str_split("", ':', 1); +    assert_null(strv[0]); +    sb_strv_free(strv); +    assert_null(sb_str_split(NULL, ':', 0)); +} + + +static void +test_str_replace(void **state) +{ +    char *str = sb_str_replace("bolao", 'o', "zaz"); +    assert_string_equal(str, "bzazlazaz"); +    free(str); +    str = sb_str_replace("bolao", 'b', "zaz"); +    assert_string_equal(str, "zazolao"); +    free(str); +    str = sb_str_replace("bolao", 'b', NULL); +    assert_string_equal(str, "bolao"); +    free(str); +    assert_null(sb_str_replace(NULL, 'b', "zaz")); +} + + +static void +test_strv_join(void **state) +{ +    char *pieces[] = {"guda","bola", "chunda", NULL}; +    char *str = sb_strv_join(pieces, ":"); +    assert_string_equal(str, "guda:bola:chunda"); +    free(str); +    char *pieces2[] = {NULL}; +    str = sb_strv_join(pieces2, ":"); +    assert_string_equal(str, ""); +    free(str); +    assert_null(sb_strv_join(pieces, NULL)); +    assert_null(sb_strv_join(NULL, ":")); +    assert_null(sb_strv_join(NULL, NULL)); +} + + +static void +test_strv_length(void **state) +{ +    char *pieces[] = {"guda","bola", "chunda", NULL}; +    assert_int_equal(sb_strv_length(pieces), 3); +    char *pieces2[] = {NULL}; +    assert_int_equal(sb_strv_length(pieces2), 0); +    assert_int_equal(sb_strv_length(NULL), 0); +} + + +static void +test_string_new(void **state) +{ +    sb_string_t *str = sb_string_new(); +    assert_non_null(str); +    assert_string_equal(str->str, ""); +    assert_int_equal(str->len, 0); +    assert_int_equal(str->allocated_len, SB_STRING_CHUNK_SIZE); +    assert_null(sb_string_free(str, true)); +} + + +static void +test_string_free(void **state) +{ +    sb_string_t *str = sb_string_new(); +    free(str->str); +    str->str = sb_strdup("bola"); +    str->len = 4; +    str->allocated_len = SB_STRING_CHUNK_SIZE; +    char *tmp = sb_string_free(str, false); +    assert_string_equal(tmp, "bola"); +    free(tmp); +    assert_null(sb_string_free(NULL, false)); +} + + +static void +test_string_dup(void **state) +{ +    sb_string_t *str = sb_string_new(); +    free(str->str); +    str->str = sb_strdup("bola"); +    str->len = 4; +    str->allocated_len = SB_STRING_CHUNK_SIZE; +    sb_string_t *new = sb_string_dup(str); +    assert_non_null(new); +    assert_string_equal(new->str, "bola"); +    assert_int_equal(new->len, 4); +    assert_int_equal(new->allocated_len, SB_STRING_CHUNK_SIZE); +    assert_null(sb_string_free(new, true)); +    assert_null(sb_string_free(str, true)); +    assert_null(sb_string_dup(NULL)); +} + + +static void +test_string_append_len(void **state) +{ +    sb_string_t *str = sb_string_new(); +    str = sb_string_append_len(str, "guda", 4); +    assert_non_null(str); +    assert_string_equal(str->str, "guda"); +    assert_int_equal(str->len, 4); +    assert_int_equal(str->allocated_len, SB_STRING_CHUNK_SIZE); +    assert_null(sb_string_free(str, true)); +    str = sb_string_new(); +    str = sb_string_append_len(str, "guda", 4); +    str = sb_string_append_len(str, "bola", 4); +    assert_non_null(str); +    assert_string_equal(str->str, "gudabola"); +    assert_int_equal(str->len, 8); +    assert_int_equal(str->allocated_len, SB_STRING_CHUNK_SIZE); +    assert_null(sb_string_free(str, true)); +    str = sb_string_new(); +    str = sb_string_append_len(str, "guda", 3); +    str = sb_string_append_len(str, "bola", 4); +    assert_non_null(str); +    assert_string_equal(str->str, "gudbola"); +    assert_int_equal(str->len, 7); +    assert_int_equal(str->allocated_len, SB_STRING_CHUNK_SIZE); +    assert_null(sb_string_free(str, true)); +    str = sb_string_new(); +    str = sb_string_append_len(str, "guda", 4); +    str = sb_string_append_len(str, +        "cwlwmwxxmvjnwtidmjehzdeexbxjnjowruxjrqpgpfhmvwgqeacdjissntmbtsjidzkcw" +        "nnqhxhneolbwqlctcxmrsutolrjikpavxombpfpjyaqltgvzrjidotalcuwrwxtaxjiwa" +        "xfhfyzymtffusoqywaruxpybwggukltspqqmghzpqstvcvlqbkhquihzndnrvkaqvevaz" +        "dxrewtgapkompnviiyielanoyowgqhssntyvcvqqtfjmkphywbkvzfyttaalttywhqcec" +        "hgrwzaglzogwjvqncjzodaqsblcbpcdpxmrtctzginvtkckhqvdplgjvbzrnarcxjrsbc" +        "sbfvpylgjznsuhxcxoqbpxowmsrgwimxjgyzwwmryqvstwzkglgeezelvpvkwefqdatnd" +        "dxntikgoqlidfnmdhxzevqzlzubvyleeksdirmmttqthhkvfjggznpmarcamacpvwsrnr" +        "ftzfeyasjpxoevyptpdnqokswiondusnuymqwaryrmdgscbnuilxtypuynckancsfnwtg" +        "okxhegoifakimxbbafkeannglvsxprqzfekdinssqymtfexf", 600); +    str = sb_string_append_len(str, NULL, 0); +    str = sb_string_append_len(str, +        "cwlwmwxxmvjnwtidmjehzdeexbxjnjowruxjrqpgpfhmvwgqeacdjissntmbtsjidzkcw" +        "nnqhxhneolbwqlctcxmrsutolrjikpavxombpfpjyaqltgvzrjidotalcuwrwxtaxjiwa" +        "xfhfyzymtffusoqywaruxpybwggukltspqqmghzpqstvcvlqbkhquihzndnrvkaqvevaz" +        "dxrewtgapkompnviiyielanoyowgqhssntyvcvqqtfjmkphywbkvzfyttaalttywhqcec" +        "hgrwzaglzogwjvqncjzodaqsblcbpcdpxmrtctzginvtkckhqvdplgjvbzrnarcxjrsbc" +        "sbfvpylgjznsuhxcxoqbpxowmsrgwimxjgyzwwmryqvstwzkglgeezelvpvkwefqdatnd" +        "dxntikgoqlidfnmdhxzevqzlzubvyleeksdirmmttqthhkvfjggznpmarcamacpvwsrnr" +        "ftzfeyasjpxoevyptpdnqokswiondusnuymqwaryrmdgscbnuilxtypuynckancsfnwtg" +        "okxhegoifakimxbbafkeannglvsxprqzfekdinssqymtfexf", 600); +    assert_non_null(str); +    assert_string_equal(str->str, +        "gudacwlwmwxxmvjnwtidmjehzdeexbxjnjowruxjrqpgpfhmvwgqeacdjissntmbtsjid" +        "zkcwnnqhxhneolbwqlctcxmrsutolrjikpavxombpfpjyaqltgvzrjidotalcuwrwxtax" +        "jiwaxfhfyzymtffusoqywaruxpybwggukltspqqmghzpqstvcvlqbkhquihzndnrvkaqv" +        "evazdxrewtgapkompnviiyielanoyowgqhssntyvcvqqtfjmkphywbkvzfyttaalttywh" +        "qcechgrwzaglzogwjvqncjzodaqsblcbpcdpxmrtctzginvtkckhqvdplgjvbzrnarcxj" +        "rsbcsbfvpylgjznsuhxcxoqbpxowmsrgwimxjgyzwwmryqvstwzkglgeezelvpvkwefqd" +        "atnddxntikgoqlidfnmdhxzevqzlzubvyleeksdirmmttqthhkvfjggznpmarcamacpvw" +        "srnrftzfeyasjpxoevyptpdnqokswiondusnuymqwaryrmdgscbnuilxtypuynckancsf" +        "nwtgokxhegoifakimxbbafkeannglvsxprqzfekdinssqymtfexfcwlwmwxxmvjnwtidm" +        "jehzdeexbxjnjowruxjrqpgpfhmvwgqeacdjissntmbtsjidzkcwnnqhxhneolbwqlctc" +        "xmrsutolrjikpavxombpfpjyaqltgvzrjidotalcuwrwxtaxjiwaxfhfyzymtffusoqyw" +        "aruxpybwggukltspqqmghzpqstvcvlqbkhquihzndnrvkaqvevazdxrewtgapkompnvii" +        "yielanoyowgqhssntyvcvqqtfjmkphywbkvzfyttaalttywhqcechgrwzaglzogwjvqnc" +        "jzodaqsblcbpcdpxmrtctzginvtkckhqvdplgjvbzrnarcxjrsbcsbfvpylgjznsuhxcx" +        "oqbpxowmsrgwimxjgyzwwmryqvstwzkglgeezelvpvkwefqdatnddxntikgoqlidfnmdh" +        "xzevqzlzubvyleeksdirmmttqthhkvfjggznpmarcamacpvwsrnrftzfeyasjpxoevypt" +        "pdnqokswiondusnuymqwaryrmdgscbnuilxtypuynckancsfnwtgokxhegoifakimxbba" +        "fkeannglvsxprqzfekdinssqymtfexf"); +    assert_int_equal(str->len, 1204); +    assert_int_equal(str->allocated_len, SB_STRING_CHUNK_SIZE * 10); +    assert_null(sb_string_free(str, true)); +    str = sb_string_new(); +    str = sb_string_append_len(str, NULL, 0); +    assert_non_null(str); +    assert_string_equal(str->str, ""); +    assert_int_equal(str->len, 0); +    assert_int_equal(str->allocated_len, SB_STRING_CHUNK_SIZE); +    assert_null(sb_string_free(str, true)); +    assert_null(sb_string_append_len(NULL, "foo", 3)); +} + + +static void +test_string_append(void **state) +{ +    sb_string_t *str = sb_string_new(); +    str = sb_string_append(str, "guda"); +    assert_non_null(str); +    assert_string_equal(str->str, "guda"); +    assert_int_equal(str->len, 4); +    assert_int_equal(str->allocated_len, SB_STRING_CHUNK_SIZE); +    assert_null(sb_string_free(str, true)); +    str = sb_string_new(); +    str = sb_string_append(str, "guda"); +    str = sb_string_append(str, "bola"); +    assert_non_null(str); +    assert_string_equal(str->str, "gudabola"); +    assert_int_equal(str->len, 8); +    assert_int_equal(str->allocated_len, SB_STRING_CHUNK_SIZE); +    assert_null(sb_string_free(str, true)); +    str = sb_string_new(); +    str = sb_string_append(str, "guda"); +    str = sb_string_append(str, +        "cwlwmwxxmvjnwtidmjehzdeexbxjnjowruxjrqpgpfhmvwgqeacdjissntmbtsjidzkcw" +        "nnqhxhneolbwqlctcxmrsutolrjikpavxombpfpjyaqltgvzrjidotalcuwrwxtaxjiwa" +        "xfhfyzymtffusoqywaruxpybwggukltspqqmghzpqstvcvlqbkhquihzndnrvkaqvevaz" +        "dxrewtgapkompnviiyielanoyowgqhssntyvcvqqtfjmkphywbkvzfyttaalttywhqcec" +        "hgrwzaglzogwjvqncjzodaqsblcbpcdpxmrtctzginvtkckhqvdplgjvbzrnarcxjrsbc" +        "sbfvpylgjznsuhxcxoqbpxowmsrgwimxjgyzwwmryqvstwzkglgeezelvpvkwefqdatnd" +        "dxntikgoqlidfnmdhxzevqzlzubvyleeksdirmmttqthhkvfjggznpmarcamacpvwsrnr" +        "ftzfeyasjpxoevyptpdnqokswiondusnuymqwaryrmdgscbnuilxtypuynckancsfnwtg" +        "okxhegoifakimxbbafkeannglvsxprqzfekdinssqymtfexf"); +    str = sb_string_append(str, NULL); +    str = sb_string_append(str, +        "cwlwmwxxmvjnwtidmjehzdeexbxjnjowruxjrqpgpfhmvwgqeacdjissntmbtsjidzkcw" +        "nnqhxhneolbwqlctcxmrsutolrjikpavxombpfpjyaqltgvzrjidotalcuwrwxtaxjiwa" +        "xfhfyzymtffusoqywaruxpybwggukltspqqmghzpqstvcvlqbkhquihzndnrvkaqvevaz" +        "dxrewtgapkompnviiyielanoyowgqhssntyvcvqqtfjmkphywbkvzfyttaalttywhqcec" +        "hgrwzaglzogwjvqncjzodaqsblcbpcdpxmrtctzginvtkckhqvdplgjvbzrnarcxjrsbc" +        "sbfvpylgjznsuhxcxoqbpxowmsrgwimxjgyzwwmryqvstwzkglgeezelvpvkwefqdatnd" +        "dxntikgoqlidfnmdhxzevqzlzubvyleeksdirmmttqthhkvfjggznpmarcamacpvwsrnr" +        "ftzfeyasjpxoevyptpdnqokswiondusnuymqwaryrmdgscbnuilxtypuynckancsfnwtg" +        "okxhegoifakimxbbafkeannglvsxprqzfekdinssqymtfexf"); +    assert_non_null(str); +    assert_string_equal(str->str, +        "gudacwlwmwxxmvjnwtidmjehzdeexbxjnjowruxjrqpgpfhmvwgqeacdjissntmbtsjid" +        "zkcwnnqhxhneolbwqlctcxmrsutolrjikpavxombpfpjyaqltgvzrjidotalcuwrwxtax" +        "jiwaxfhfyzymtffusoqywaruxpybwggukltspqqmghzpqstvcvlqbkhquihzndnrvkaqv" +        "evazdxrewtgapkompnviiyielanoyowgqhssntyvcvqqtfjmkphywbkvzfyttaalttywh" +        "qcechgrwzaglzogwjvqncjzodaqsblcbpcdpxmrtctzginvtkckhqvdplgjvbzrnarcxj" +        "rsbcsbfvpylgjznsuhxcxoqbpxowmsrgwimxjgyzwwmryqvstwzkglgeezelvpvkwefqd" +        "atnddxntikgoqlidfnmdhxzevqzlzubvyleeksdirmmttqthhkvfjggznpmarcamacpvw" +        "srnrftzfeyasjpxoevyptpdnqokswiondusnuymqwaryrmdgscbnuilxtypuynckancsf" +        "nwtgokxhegoifakimxbbafkeannglvsxprqzfekdinssqymtfexfcwlwmwxxmvjnwtidm" +        "jehzdeexbxjnjowruxjrqpgpfhmvwgqeacdjissntmbtsjidzkcwnnqhxhneolbwqlctc" +        "xmrsutolrjikpavxombpfpjyaqltgvzrjidotalcuwrwxtaxjiwaxfhfyzymtffusoqyw" +        "aruxpybwggukltspqqmghzpqstvcvlqbkhquihzndnrvkaqvevazdxrewtgapkompnvii" +        "yielanoyowgqhssntyvcvqqtfjmkphywbkvzfyttaalttywhqcechgrwzaglzogwjvqnc" +        "jzodaqsblcbpcdpxmrtctzginvtkckhqvdplgjvbzrnarcxjrsbcsbfvpylgjznsuhxcx" +        "oqbpxowmsrgwimxjgyzwwmryqvstwzkglgeezelvpvkwefqdatnddxntikgoqlidfnmdh" +        "xzevqzlzubvyleeksdirmmttqthhkvfjggznpmarcamacpvwsrnrftzfeyasjpxoevypt" +        "pdnqokswiondusnuymqwaryrmdgscbnuilxtypuynckancsfnwtgokxhegoifakimxbba" +        "fkeannglvsxprqzfekdinssqymtfexf"); +    assert_int_equal(str->len, 1204); +    assert_int_equal(str->allocated_len, SB_STRING_CHUNK_SIZE * 10); +    assert_null(sb_string_free(str, true)); +    str = sb_string_new(); +    str = sb_string_append(str, NULL); +    assert_non_null(str); +    assert_string_equal(str->str, ""); +    assert_int_equal(str->len, 0); +    assert_int_equal(str->allocated_len, SB_STRING_CHUNK_SIZE); +    assert_null(sb_string_free(str, true)); +    assert_null(sb_string_append(NULL, "asd")); +    assert_null(sb_string_append(NULL, NULL)); +} + + +static void +test_string_append_c(void **state) +{ +    sb_string_t *str = sb_string_new(); +    str = sb_string_append_len(str, "guda", 4); +    for (int i = 0; i < 600; i++) +        str = sb_string_append_c(str, 'c'); +    assert_non_null(str); +    assert_string_equal(str->str, +        "gudaccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" +        "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" +        "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" +        "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" +        "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" +        "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" +        "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" +        "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" +        "cccccccccccccccccccccccccccccccccccccccccccccccccccc"); +    assert_int_equal(str->len, 604); +    assert_int_equal(str->allocated_len, SB_STRING_CHUNK_SIZE * 5); +    assert_null(sb_string_free(str, true)); +    assert_null(sb_string_append_c(NULL, 0)); +} + + +static void +test_string_append_printf(void **state) +{ +    sb_string_t *str = sb_string_new(); +    str = sb_string_append_printf(str, "guda: %s %d", "bola", 1); +    assert_non_null(str); +    assert_string_equal(str->str, "guda: bola 1"); +    assert_int_equal(str->len, 12); +    assert_int_equal(str->allocated_len, SB_STRING_CHUNK_SIZE); +    assert_null(sb_string_free(str, true)); +    assert_null(sb_string_append_printf(NULL, "asd")); +} + + +static void +test_trie_new(void **state) +{ +    sb_trie_t *trie = sb_trie_new(free); +    assert_non_null(trie); +    assert_null(trie->root); +    assert_true(trie->free_func == free); +    sb_trie_free(trie); +} + + +static void +test_trie_insert(void **state) +{ +    sb_trie_t *trie = sb_trie_new(free); + +    sb_trie_insert(trie, "bola", sb_strdup("guda")); +    assert_true(trie->root->key == 'b'); +    assert_null(trie->root->data); +    assert_true(trie->root->child->key == 'o'); +    assert_null(trie->root->child->data); +    assert_true(trie->root->child->child->key == 'l'); +    assert_null(trie->root->child->child->data); +    assert_true(trie->root->child->child->child->key == 'a'); +    assert_null(trie->root->child->child->child->data); +    assert_true(trie->root->child->child->child->child->key == '\0'); +    assert_string_equal(trie->root->child->child->child->child->data, "guda"); + + +    sb_trie_insert(trie, "chu", sb_strdup("nda")); +    assert_true(trie->root->key == 'b'); +    assert_null(trie->root->data); +    assert_true(trie->root->child->key == 'o'); +    assert_null(trie->root->child->data); +    assert_true(trie->root->child->child->key == 'l'); +    assert_null(trie->root->child->child->data); +    assert_true(trie->root->child->child->child->key == 'a'); +    assert_null(trie->root->child->child->child->data); +    assert_true(trie->root->child->child->child->child->key == '\0'); +    assert_string_equal(trie->root->child->child->child->child->data, "guda"); + +    assert_true(trie->root->next->key == 'c'); +    assert_null(trie->root->next->data); +    assert_true(trie->root->next->child->key == 'h'); +    assert_null(trie->root->next->child->data); +    assert_true(trie->root->next->child->child->key == 'u'); +    assert_null(trie->root->next->child->child->data); +    assert_true(trie->root->next->child->child->child->key == '\0'); +    assert_string_equal(trie->root->next->child->child->child->data, "nda"); + + +    sb_trie_insert(trie, "bote", sb_strdup("aba")); +    assert_true(trie->root->key == 'b'); +    assert_null(trie->root->data); +    assert_true(trie->root->child->key == 'o'); +    assert_null(trie->root->child->data); +    assert_true(trie->root->child->child->key == 'l'); +    assert_null(trie->root->child->child->data); +    assert_true(trie->root->child->child->child->key == 'a'); +    assert_null(trie->root->child->child->child->data); +    assert_true(trie->root->child->child->child->child->key == '\0'); +    assert_string_equal(trie->root->child->child->child->child->data, "guda"); + +    assert_true(trie->root->next->key == 'c'); +    assert_null(trie->root->next->data); +    assert_true(trie->root->next->child->key == 'h'); +    assert_null(trie->root->next->child->data); +    assert_true(trie->root->next->child->child->key == 'u'); +    assert_null(trie->root->next->child->child->data); +    assert_true(trie->root->next->child->child->child->key == '\0'); +    assert_string_equal(trie->root->next->child->child->child->data, "nda"); + +    assert_true(trie->root->child->child->next->key == 't'); +    assert_null(trie->root->child->child->next->data); +    assert_true(trie->root->child->child->next->child->key == 'e'); +    assert_null(trie->root->child->child->next->child->data); +    assert_true(trie->root->child->child->next->child->child->key == '\0'); +    assert_string_equal(trie->root->child->child->next->child->child->data, "aba"); + + +    sb_trie_insert(trie, "bo", sb_strdup("haha")); +    assert_true(trie->root->key == 'b'); +    assert_null(trie->root->data); +    assert_true(trie->root->child->key == 'o'); +    assert_null(trie->root->child->data); +    assert_true(trie->root->child->child->key == 'l'); +    assert_null(trie->root->child->child->data); +    assert_true(trie->root->child->child->child->key == 'a'); +    assert_null(trie->root->child->child->child->data); +    assert_true(trie->root->child->child->child->child->key == '\0'); +    assert_string_equal(trie->root->child->child->child->child->data, "guda"); + +    assert_true(trie->root->next->key == 'c'); +    assert_null(trie->root->next->data); +    assert_true(trie->root->next->child->key == 'h'); +    assert_null(trie->root->next->child->data); +    assert_true(trie->root->next->child->child->key == 'u'); +    assert_null(trie->root->next->child->child->data); +    assert_true(trie->root->next->child->child->child->key == '\0'); +    assert_string_equal(trie->root->next->child->child->child->data, "nda"); + +    assert_true(trie->root->child->child->next->key == 't'); +    assert_null(trie->root->child->child->next->data); +    assert_true(trie->root->child->child->next->child->key == 'e'); +    assert_null(trie->root->child->child->next->child->data); +    assert_true(trie->root->child->child->next->child->child->key == '\0'); +    assert_string_equal(trie->root->child->child->next->child->child->data, "aba"); + +    assert_true(trie->root->child->child->next->next->key == '\0'); +    assert_string_equal(trie->root->child->child->next->next->data, "haha"); + +    sb_trie_free(trie); + + +    trie = sb_trie_new(free); + +    sb_trie_insert(trie, "chu", sb_strdup("nda")); +    assert_true(trie->root->key == 'c'); +    assert_null(trie->root->data); +    assert_true(trie->root->child->key == 'h'); +    assert_null(trie->root->child->data); +    assert_true(trie->root->child->child->key == 'u'); +    assert_null(trie->root->child->child->data); +    assert_true(trie->root->child->child->child->key == '\0'); +    assert_string_equal(trie->root->child->child->child->data, "nda"); + + +    sb_trie_insert(trie, "bola", sb_strdup("guda")); +    assert_true(trie->root->key == 'c'); +    assert_null(trie->root->data); +    assert_true(trie->root->child->key == 'h'); +    assert_null(trie->root->child->data); +    assert_true(trie->root->child->child->key == 'u'); +    assert_null(trie->root->child->child->data); +    assert_true(trie->root->child->child->child->key == '\0'); +    assert_string_equal(trie->root->child->child->child->data, "nda"); + +    assert_true(trie->root->next->key == 'b'); +    assert_null(trie->root->next->data); +    assert_true(trie->root->next->child->key == 'o'); +    assert_null(trie->root->next->child->data); +    assert_true(trie->root->next->child->child->key == 'l'); +    assert_null(trie->root->next->child->child->data); +    assert_true(trie->root->next->child->child->child->key == 'a'); +    assert_null(trie->root->next->child->child->child->data); +    assert_true(trie->root->next->child->child->child->child->key == '\0'); +    assert_string_equal(trie->root->next->child->child->child->child->data, "guda"); + + +    sb_trie_insert(trie, "bote", sb_strdup("aba")); +    assert_true(trie->root->key == 'c'); +    assert_null(trie->root->data); +    assert_true(trie->root->child->key == 'h'); +    assert_null(trie->root->child->data); +    assert_true(trie->root->child->child->key == 'u'); +    assert_null(trie->root->child->child->data); +    assert_true(trie->root->child->child->child->key == '\0'); +    assert_string_equal(trie->root->child->child->child->data, "nda"); + +    assert_true(trie->root->next->key == 'b'); +    assert_null(trie->root->next->data); +    assert_true(trie->root->next->child->key == 'o'); +    assert_null(trie->root->next->child->data); +    assert_true(trie->root->next->child->child->key == 'l'); +    assert_null(trie->root->next->child->child->data); +    assert_true(trie->root->next->child->child->child->key == 'a'); +    assert_null(trie->root->next->child->child->child->data); +    assert_true(trie->root->next->child->child->child->child->key == '\0'); +    assert_string_equal(trie->root->next->child->child->child->child->data, "guda"); + +    assert_true(trie->root->next->child->child->next->key == 't'); +    assert_null(trie->root->next->child->child->next->data); +    assert_true(trie->root->next->child->child->next->child->key == 'e'); +    assert_null(trie->root->next->child->child->next->child->data); +    assert_true(trie->root->next->child->child->next->child->child->key == '\0'); +    assert_string_equal(trie->root->next->child->child->next->child->child->data, "aba"); + + +    sb_trie_insert(trie, "bo", sb_strdup("haha")); +    assert_true(trie->root->key == 'c'); +    assert_null(trie->root->data); +    assert_true(trie->root->child->key == 'h'); +    assert_null(trie->root->child->data); +    assert_true(trie->root->child->child->key == 'u'); +    assert_null(trie->root->child->child->data); +    assert_true(trie->root->child->child->child->key == '\0'); +    assert_string_equal(trie->root->child->child->child->data, "nda"); + +    assert_true(trie->root->next->key == 'b'); +    assert_null(trie->root->next->data); +    assert_true(trie->root->next->child->key == 'o'); +    assert_null(trie->root->next->child->data); +    assert_true(trie->root->next->child->child->key == 'l'); +    assert_null(trie->root->next->child->child->data); +    assert_true(trie->root->next->child->child->child->key == 'a'); +    assert_null(trie->root->next->child->child->child->data); +    assert_true(trie->root->next->child->child->child->child->key == '\0'); +    assert_string_equal(trie->root->next->child->child->child->child->data, "guda"); + +    assert_true(trie->root->next->child->child->next->key == 't'); +    assert_null(trie->root->next->child->child->next->data); +    assert_true(trie->root->next->child->child->next->child->key == 'e'); +    assert_null(trie->root->next->child->child->next->child->data); +    assert_true(trie->root->next->child->child->next->child->child->key == '\0'); +    assert_string_equal(trie->root->next->child->child->next->child->child->data, "aba"); + +    assert_true(trie->root->next->child->child->next->next->key == '\0'); +    assert_string_equal(trie->root->next->child->child->next->next->data, "haha"); + +    sb_trie_free(trie); +} + + +static void +test_trie_insert_duplicated(void **state) +{ +    sb_trie_t *trie = sb_trie_new(free); + +    sb_trie_insert(trie, "bola", sb_strdup("guda")); +    assert_true(trie->root->key == 'b'); +    assert_null(trie->root->data); +    assert_true(trie->root->child->key == 'o'); +    assert_null(trie->root->child->data); +    assert_true(trie->root->child->child->key == 'l'); +    assert_null(trie->root->child->child->data); +    assert_true(trie->root->child->child->child->key == 'a'); +    assert_null(trie->root->child->child->child->data); +    assert_true(trie->root->child->child->child->child->key == '\0'); +    assert_string_equal(trie->root->child->child->child->child->data, "guda"); + +    sb_trie_insert(trie, "bola", sb_strdup("asdf")); +    assert_true(trie->root->key == 'b'); +    assert_null(trie->root->data); +    assert_true(trie->root->child->key == 'o'); +    assert_null(trie->root->child->data); +    assert_true(trie->root->child->child->key == 'l'); +    assert_null(trie->root->child->child->data); +    assert_true(trie->root->child->child->child->key == 'a'); +    assert_null(trie->root->child->child->child->data); +    assert_true(trie->root->child->child->child->child->key == '\0'); +    assert_string_equal(trie->root->child->child->child->child->data, "asdf"); + +    sb_trie_free(trie); + +    trie = NULL; +    sb_trie_insert(trie, "bola", NULL); +    assert_null(trie); +} + + +static void +test_trie_keep_data(void **state) +{ +    sb_trie_t *trie = sb_trie_new(NULL); + +    char *t1 = "guda"; +    char *t2 = "nda"; +    char *t3 = "aba"; +    char *t4 = "haha"; + +    sb_trie_insert(trie, "bola", t1); +    sb_trie_insert(trie, "chu", t2); +    sb_trie_insert(trie, "bote", t3); +    sb_trie_insert(trie, "bo", t4); + +    sb_trie_free(trie); + +    assert_string_equal(t1, "guda"); +    assert_string_equal(t2, "nda"); +    assert_string_equal(t3, "aba"); +    assert_string_equal(t4, "haha"); +} + + +static void +test_trie_lookup(void **state) +{ +    sb_trie_t *trie = sb_trie_new(free); + +    sb_trie_insert(trie, "bola", sb_strdup("guda")); +    sb_trie_insert(trie, "chu", sb_strdup("nda")); +    sb_trie_insert(trie, "bote", sb_strdup("aba")); +    sb_trie_insert(trie, "bo", sb_strdup("haha")); + +    assert_string_equal(sb_trie_lookup(trie, "bola"), "guda"); +    assert_string_equal(sb_trie_lookup(trie, "chu"), "nda"); +    assert_string_equal(sb_trie_lookup(trie, "bote"), "aba"); +    assert_string_equal(sb_trie_lookup(trie, "bo"), "haha"); + +    assert_null(sb_trie_lookup(trie, "arcoiro")); + +    sb_trie_free(trie); + +    trie = sb_trie_new(free); + +    sb_trie_insert(trie, "chu", sb_strdup("nda")); +    sb_trie_insert(trie, "bola", sb_strdup("guda")); +    sb_trie_insert(trie, "bote", sb_strdup("aba")); +    sb_trie_insert(trie, "bo", sb_strdup("haha")); +    sb_trie_insert(trie, "copa", sb_strdup("bu")); +    sb_trie_insert(trie, "b", sb_strdup("c")); +    sb_trie_insert(trie, "test", sb_strdup("asd")); + +    assert_string_equal(sb_trie_lookup(trie, "bola"), "guda"); +    assert_string_equal(sb_trie_lookup(trie, "chu"), "nda"); +    assert_string_equal(sb_trie_lookup(trie, "bote"), "aba"); +    assert_string_equal(sb_trie_lookup(trie, "bo"), "haha"); + +    assert_null(sb_trie_lookup(trie, "arcoiro")); + +    sb_trie_free(trie); + +    assert_null(sb_trie_lookup(NULL, "bola")); +} + + +static void +test_trie_size(void **state) +{ +    sb_trie_t *trie = sb_trie_new(free); + +    sb_trie_insert(trie, "bola", sb_strdup("guda")); +    sb_trie_insert(trie, "chu", sb_strdup("nda")); +    sb_trie_insert(trie, "bote", sb_strdup("aba")); +    sb_trie_insert(trie, "bo", sb_strdup("haha")); + +    assert_int_equal(sb_trie_size(trie), 4); +    assert_int_equal(sb_trie_size(NULL), 0); + +    sb_trie_free(trie); + +    trie = sb_trie_new(free); + +    sb_trie_insert(trie, "chu", sb_strdup("nda")); +    sb_trie_insert(trie, "bola", sb_strdup("guda")); +    sb_trie_insert(trie, "bote", sb_strdup("aba")); +    sb_trie_insert(trie, "bo", sb_strdup("haha")); +    sb_trie_insert(trie, "copa", sb_strdup("bu")); +    sb_trie_insert(trie, "b", sb_strdup("c")); +    sb_trie_insert(trie, "test", sb_strdup("asd")); + +    assert_int_equal(sb_trie_size(trie), 7); +    assert_int_equal(sb_trie_size(NULL), 0); + +    sb_trie_free(trie); +} + + +static unsigned int counter; +static char *expected_keys[] = {"chu", "copa", "bola", "bote", "bo", "b", "test"}; +static char *expected_datas[] = {"nda", "bu", "guda", "aba", "haha", "c", "asd"}; + +static void +mock_foreach(const char *key, void *data, void *user_data) +{ +    assert_string_equal(user_data, "foo"); +    assert_string_equal(key, expected_keys[counter]); +    assert_string_equal((char*) data, expected_datas[counter++]); +} + + +static void +test_trie_foreach(void **state) +{ +    sb_trie_t *trie = sb_trie_new(free); + +    sb_trie_insert(trie, "chu", sb_strdup("nda")); +    sb_trie_insert(trie, "bola", sb_strdup("guda")); +    sb_trie_insert(trie, "bote", sb_strdup("aba")); +    sb_trie_insert(trie, "bo", sb_strdup("haha")); +    sb_trie_insert(trie, "copa", sb_strdup("bu")); +    sb_trie_insert(trie, "b", sb_strdup("c")); +    sb_trie_insert(trie, "test", sb_strdup("asd")); + +    counter = 0; +    sb_trie_foreach(trie, mock_foreach, "foo"); +    sb_trie_foreach(NULL, mock_foreach, "foo"); +    sb_trie_foreach(trie, NULL, "foo"); +    sb_trie_foreach(NULL, NULL, "foo"); + +    sb_trie_free(trie); +} + + +int +main(void) +{ +    const UnitTest tests[] = { + +        // slist +        unit_test(test_slist_append), +        unit_test(test_slist_prepend), +        unit_test(test_slist_free), +        unit_test(test_slist_length), + +        // strfuncs +        unit_test(test_strdup), +        unit_test(test_strndup), +        unit_test(test_strdup_printf), +        unit_test(test_str_starts_with), +        unit_test(test_str_ends_with), +        unit_test(test_str_lstrip), +        unit_test(test_str_rstrip), +        unit_test(test_str_strip), +        unit_test(test_str_split), +        unit_test(test_str_replace), +        unit_test(test_strv_join), +        unit_test(test_strv_length), + +        // string +        unit_test(test_string_new), +        unit_test(test_string_free), +        unit_test(test_string_dup), +        unit_test(test_string_append_len), +        unit_test(test_string_append), +        unit_test(test_string_append_c), +        unit_test(test_string_append_printf), + +        // trie +        unit_test(test_trie_new), +        unit_test(test_trie_insert), +        unit_test(test_trie_insert_duplicated), +        unit_test(test_trie_keep_data), +        unit_test(test_trie_lookup), +        unit_test(test_trie_size), +        unit_test(test_trie_foreach), +    }; +    return run_tests(tests); +}  | 
