test_common.c test_list.c tinytest.c test_cbtree.c \
test_utf8.c test_strpool.c test_pgutil.c test_regex.c \
test_cxalloc.c test_bits.c test_base.c test_netdb.c \
- test_cfparser.c test_endian.c test_hashtab.c test_mdict.c
+ test_cfparser.c test_endian.c test_hashtab.c test_mdict.c \
+ test_shlist.c
OBJS = $(addprefix obj/, $(SRCS:.c=.o))
HDRS = test_common.h test_config.h tinytest.h tinytest_macros.h
LIBS =
$(Q) $(CC) -o $@ $(objs) $(LIBS)
clean:
- rm -f libusual.a obj/* *.o regtest
+ rm -f libusual.a obj/* *.o regtest *.gcov
rm -f config.test usual/config.h test_config.h
rm -f regtest.compat regtest.system
rm -f libusual_compat.a libusual_system.a
vcheck: regtest
valgrind --leak-check=full ./regtest
+BADGC = ../usual/base.c ../usual/signal.c
+gc:
+ make clean all CC="$(CC) -fprofile-arcs -ftest-coverage"
+ ./regtest
+ gcov -f -o obj $(SRCS) $(filter-out $(BADGC), $(USUAL_SRCS)) > gc.log
+
--- /dev/null
+#include <usual/shlist.h>
+
+#include "test_common.h"
+
+#include <usual/string.h>
+
+struct MyNode {
+ struct SHList node;
+ char val[16];
+};
+
+static const char *xval(const struct SHList *elem)
+{
+ const struct MyNode *n;
+ if (!elem) return NULL;
+ n = container_of(elem, struct MyNode, node);
+ return n->val;
+}
+
+static struct MyNode *new_node(int v)
+{
+ struct MyNode *n = malloc(sizeof(*n));
+ if (!n) return NULL;
+ shlist_init(&n->node);
+ snprintf(n->val, sizeof(n->val), "%d", v);
+ return n;
+}
+
+static const char *check_list(const struct SHList *list)
+{
+ const struct SHList *old, *cur;
+
+ old = NULL;
+ for (cur = shlist_next(list, list); cur != list; cur = shlist_next(list, cur)) {
+ if (old) {
+ if (shlist_prev(list, cur) != old)
+ return "FAIL 1";
+ } else {
+ if (shlist_prev(list, cur) != list)
+ return "FAIL 2";
+ }
+ old = cur;
+ }
+ if (shlist_prev(list, list) != ((old) ? old : list))
+ return "FAIL 3";
+ return "OK";
+}
+
+static const char *xshow(const struct SHList *list)
+{
+ static char res[1024];
+ struct SHList *el;
+ const char *ck = check_list(list);
+
+ if (strcmp(ck, "OK") != 0)
+ return ck;
+
+ res[0] = 0;
+ shlist_for_each(el, list) {
+ if (res[0])
+ strcat(res, ",");
+ strcat(res, xval(el));
+ }
+ return res;
+}
+
+static const char *xadd(struct SHList *list, int v)
+{
+ struct MyNode *n = new_node(v);
+ if (!n) return "FAIL";
+ shlist_append(list, &n->node);
+ return xshow(list);
+}
+
+static const char *xadd1(struct SHList *list, int v)
+{
+ struct MyNode *n = new_node(v);
+ if (!n) return "FAIL";
+ shlist_prepend(list, &n->node);
+ return xshow(list);
+}
+
+static const char *xdel(struct SHList *list, int v)
+{
+ char buf[32];
+ struct SHList *el, *tmp;
+ struct MyNode *n;
+ snprintf(buf, sizeof(buf), "%d", v);
+ shlist_for_each_safe(el, list, tmp) {
+ n = container_of(el, struct MyNode, node);
+ if (strcmp(buf, n->val) == 0) {
+ shlist_remove(list, el);
+ free(n);
+ }
+ }
+ if (!check_list(list))
+ return "FAIL";
+ return xshow(list);
+}
+
+static void test_shlist(void *p)
+{
+ struct SHList rlist, *list = &rlist;
+ shlist_init(list);
+ str_check(check_list(list), "OK");
+ str_check(xadd(list, 2), "2");
+ str_check(xadd1(list, 1), "1,2");
+ str_check(xadd(list, 3), "1,2,3");
+ str_check(xadd(list, 4), "1,2,3,4");
+ str_check(check_list(list), "OK");
+
+ {
+ struct MyNode *n;
+ str_check(xadd1(list, 0), "0,1,2,3,4");
+ n = shlist_pop_type(list, struct MyNode, node);
+ str_check(n->val, "0");
+ free(n);
+ }
+
+ {
+ struct MyNode *n;
+ struct SHList *el;
+ str_check(xadd1(list, 0), "0,1,2,3,4");
+ el = shlist_pop(list);
+ n = container_of(el, struct MyNode, node);
+ str_check(n->val, "0");
+ free(n);
+ }
+
+
+ str_check(xval(shlist_first(list)), "1");
+ str_check(xval(shlist_last(list)), "4");
+ int_check(shlist_empty(list), 0);
+
+ str_check(xdel(list, 2), "1,3,4");
+ str_check(xdel(list, 1), "3,4");
+ str_check(xdel(list, 4), "3");
+ str_check(xdel(list, 3), "");
+ str_check(check_list(list), "OK");
+ int_check(shlist_empty(list), 1);
+end:;
+}
+
+struct testcase_t shlist_tests[] = {
+ { "basic", test_shlist },
+ END_OF_TESTCASES
+};
+