Commit Diff


commit - 661354bb042cc449324d8fbe24196d882f10115c
commit + 3b198c7ca9e3473d97ae4a705fc432cd1d173eac
blob - c715c18feed03184096802d702a00eb0b56e5732
blob + 498815d9ad365eb6cbe56d2adb1f4d3aab92a823
--- .gitignore
+++ .gitignore
@@ -3,6 +3,8 @@ compile_flags.txt
 *.o
 xc
 
+list_test
+
 Makefile
 Makefile.in
 
@@ -21,3 +23,6 @@ depcomp
 install-sh
 missing
 stamp-h1
+test-driver
+*.log
+*trs
blob - a3839f77b2591d5d17ee60251ba51d027bd6ed0c
blob + 46ed7e5e643d2cb26257861d44675bf166c484a4
--- Makefile.am
+++ Makefile.am
@@ -19,6 +19,12 @@ xc_SOURCES =		compat.h \
 			list.c list.h \
 			xc.c
 
+check_PROGRAMS =	list_test
+
+list_test_SOURCES =	list_test.c list.c list.h compat.h
+
+TESTS =			$(check_PROGRAMS)
+
 LDADD =			$(LIBOBJS)
 
 .PHONY: compile_flags.txt
blob - /dev/null
blob + 67f52b009edc9023ea0acbeaa156d9ed82d53a88 (mode 644)
--- /dev/null
+++ list_test.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "compat.h"
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include "list.h"
+
+#define nitems(a) (sizeof(a)/sizeof(a[0]))
+
+struct check {
+	const char	*src;
+	const char	*keyword;
+	int		 should_fail;
+	int		 expected_type;
+	const char	*expected_str;
+	int64_t		 expected_num;
+};
+
+#define CHECKS(_src, _key, _t, _val) {					\
+		.src = _src,						\
+		.keyword = _key,					\
+		.expected_type = _t,					\
+		.expected_str = _val,					\
+	}
+
+#define CKSYMBOL(_src, _key, _val) CHECKS(_src, _key, ATOM_SYMBOL, _val)
+#define CKSTRING(_src, _key, _val) CHECKS(_src, _key, ATOM_STRING, _val)
+#define CKKEYWORD(_src, _key, _val) CHECKS(_src, _key, ATOM_KEYWORD, _val)
+#define CKNIL(_src, _key) CHECKS(_src, _key, ATOM_STRING, NULL)
+
+#define CKNUM(_src, _key, _val) {					\
+		.src = _src,						\
+		.keyword = _key,					\
+		.expected_type = ATOM_NUMBER,				\
+		.expected_num = _val,					\
+	}
+
+#define SHOULD_FAIL(_src) {.src = _src, .should_fail = 1}
+
+/* test suite */
+struct check suite[] = {
+	SHOULD_FAIL(""),
+	SHOULD_FAIL("("),
+	SHOULD_FAIL("(hello"),
+	SHOULD_FAIL("(\"hello"),
+	SHOULD_FAIL("(\"hello)\""),
+
+	CKNIL("(:foo bar :baz 5)", "hello"),
+	CKNIL("(:foo bar :baz)", "baz"),
+
+	CKSYMBOL("(:hello there :how are :you)", "hello", "there"),
+
+	CKNUM("(:foo \"hello\" :bar 7)", "bar", 7),
+};
+
+static inline const char *
+typename(int t)
+{
+	switch (t) {
+	case ATOM_STRING:
+		return "string";
+	case ATOM_SYMBOL:
+		return "symbol";
+	case ATOM_KEYWORD:
+		return "keyword";
+	case ATOM_NUMBER:
+		return "number";
+	default:
+		return "<unknown>";
+	}
+}
+
+int
+main(void)
+{
+	struct listhead	 h;
+	struct item	*item;
+	size_t		 i;
+	char		*dup;
+
+	SIMPLEQ_INIT(&h);
+
+	for (i = 0; i < nitems(suite); ++i) {
+		if ((dup = strdup(suite[i].src)) == NULL)
+			err(1, "strdup");
+
+		if (parse_list(dup, &h) == -1 && !suite[i].should_fail)
+			errx(1, "can't parse: %s", suite[i].src);
+
+		if (suite[i].should_fail)
+			goto next;
+
+		item = plist_get(&h, suite[i].keyword);
+		if (item == NULL &&
+		    suite[i].expected_type != ATOM_STRING &&
+		    suite[i].expected_str != NULL)
+			errx(1, "nil for key :%s where not expected in %s",
+			    suite[i].keyword, suite[i].src);
+
+		if (item == NULL)
+			goto next;
+
+		if (item->type != suite[i].expected_type)
+			errx(1, "wanted type %s; got %s; keyword=%s src: %s",
+			    typename(suite[i].expected_type),
+			    typename(item->type),
+			    suite[i].keyword, suite[i].src);
+
+		switch (item->type) {
+		case ATOM_STRING:
+		case ATOM_SYMBOL:
+		case ATOM_KEYWORD:
+			if (strcmp(item->v.str, suite[i].expected_str))
+				errx(1, "for keyword %s there is %s, not %s."
+				    "  src: %s",
+				    suite[i].keyword, item->v.str,
+				    suite[i].expected_str,
+				    suite[i].src);
+			break;
+		case ATOM_NUMBER:
+			if (item->v.num != suite[i].expected_num)
+				errx(1, "for keyword %s there is %"PRIi64", not "
+				    "%"PRIi64".  src: %s",
+				    suite[i].keyword, item->v.num,
+				    suite[i].expected_num,
+				    suite[i].src);
+			break;
+		default:
+			errx(1, "unknown type %d for src: %s",
+			    item->type, suite[i].src);
+		}
+
+	next:
+		free_list(&h);
+		free(dup);
+	}
+
+	return 0;
+}