commit 1715f48abd1f7070eb0ae0ba44fde2a9483a6c41
parent 0f61313c2da4475e6f114570e14f03f9add56b07
Author: Ed van Bruggen <edvb@uw.edu>
Date:   Thu,  3 Jan 2019 20:28:02 -0800
Write unit tests in C
Diffstat:
29 files changed, 251 insertions(+), 286 deletions(-)
diff --git a/Makefile b/Makefile
@@ -4,9 +4,10 @@
 include config.mk
 
 EXE = tisp
-SRC = $(wildcard *.c */*.c)
-OBJ = $(SRC:.c=.o)
-LIB = tib/libtibmath.so
+SRC = tisp.c main.c util.c extern/linenoise.c
+TIB = tib/math.c tib/io.c
+OBJ = $(SRC:.c=.o) $(TIB:.c=.o)
+LIB = tib/libtibmath.so tib/libtibio.so
 
 all: options $(EXE)
 
@@ -29,7 +30,7 @@ config.h:
 	@echo creating $@ from config.def.h
 	@cp config.def.h $@
 
-$(LIB): $(wildcard tib/*.c)
+$(LIB): $(TIB)
 	@echo $(CC) -o $@
 	@gcc -shared -o $@ $(OBJ)
 
@@ -39,7 +40,7 @@ $(EXE): $(OBJ) $(LIB)
 
 clean:
 	@echo cleaning
-	@rm -f $(OBJ) $(LIB) $(EXE)
+	@rm -f $(OBJ) $(LIB) $(EXE) test test.o test.out
 
 install: all
 	@echo installing $(EXE) to $(DESTDIR)$(PREFIX)/bin
@@ -62,9 +63,11 @@ uninstall:
 	@echo removing libraries from $(DESTDIR)$(PREFIX)/lib/tisp
 	@rm -rf $(DESTDIR)$(PREFIX)/lib/tisp/
 
-test: $(EXE)
+test: $(OBJ) $(LIB) test.o
 	@echo running tests
-	@cd t && ./t
+	@echo $(CC) -o test
+	@$(CC) -o test tisp.o tib/math.o util.o test.o $(LDFLAGS)
+	@./test
 
 man:
 	@echo -n updating man page $(EXE).1 ...
@@ -79,4 +82,4 @@ man:
 	 md2roff - | sed "9s/]/]\ /g" | sed "9s/|/|\ /g" > $(EXE).1
 	@echo \ done
 
-.PHONY: all options clean install uninstall man
+.PHONY: all options clean install uninstall test man
diff --git a/t/math/add.expect b/t/math/add.expect
@@ -1,3 +0,0 @@
-2
-4
-1312
diff --git a/t/math/add.tsp b/t/math/add.tsp
@@ -1,3 +0,0 @@
-(+ 1 1)
-(+ 1 (+ 1 2))
-(+ 1029 283)
diff --git a/t/math/compare.expect b/t/math/compare.expect
@@ -1,12 +0,0 @@
-t
-()
-()
-t
-t
-()
-t
-()
-()
-t
-t
-()
diff --git a/t/math/compare.tsp b/t/math/compare.tsp
@@ -1,12 +0,0 @@
-(< 2 3)
-(< 3 3)
-(< 4 3)
-(<= -2 +4)
-(<= -2 -2)
-(<= 4 -2)
-(> 89 34)
-(> 48 48)
-(> 98 183)
-(>= +4 -282)
-(>= 39 39)
-(>= -32 -30)
diff --git a/t/math/sub.expect b/t/math/sub.expect
@@ -1,5 +0,0 @@
--3
--3
-289
-1
--35
diff --git a/t/math/sub.tsp b/t/math/sub.tsp
@@ -1,5 +0,0 @@
-(- 3)
-(- +3)
-(- -289)
-(- 5 4)
-(- 53 88)
diff --git a/t/prim/cond.expect b/t/prim/cond.expect
@@ -1,8 +0,0 @@
-()
-1
-1
-3
-2
-()
-2
-()
diff --git a/t/prim/cond.tsp b/t/prim/cond.tsp
@@ -1,8 +0,0 @@
-(cond)
-(cond (t 1))
-(cond ((= 1 1) 1) ((= 1 2) 2) (t 3))
-(cond ((= 1 2) 1) ((= 1 2) 2) (t (+ 1 2)))
-(cond ((= 1 2) 1) ((= 1 1) 2) (t 3))
-(cond ((= 1 2) 1) ((= 1 3) 2))
-(cond ((= 1 2) 1) ("foo" 2) (t 3))
-(cond (() (+ 1 2)))
diff --git a/t/prim/cons.expect b/t/prim/cons.expect
@@ -1,6 +0,0 @@
-(1 . 2)
-(1 2 . 3)
-(1 2 3 . 4)
-("foo" . "bar")
-(3 . 3)
-((1 . 2) 3 . 4)
diff --git a/t/prim/cons.tsp b/t/prim/cons.tsp
@@ -1,6 +0,0 @@
-(cons 1 2)
-(cons 1 (cons 2 3))
-(cons 1 (cons 2 (cons 3 4)))
-(cons "foo" "bar")
-(cons (+ 1 2) 3)
-(cons (cons 1 2) (cons 3 4))
diff --git a/t/prim/cxr.expect b/t/prim/cxr.expect
@@ -1,11 +0,0 @@
-1
-2
-1
-2
-3
-4
-(2 3 4)
-(3 4)
-1
-(2 . 3)
-3
diff --git a/t/prim/cxr.tsp b/t/prim/cxr.tsp
@@ -1,14 +0,0 @@
-(car (cons 1 2))
-(cdr (cons 1 2))
-
-(car (quote (1 2 3 4)))
-(car (cdr (quote (1 2 3 4))))
-(car (cdr (cdr (quote (1 2 3 4)))))
-(car (cdr (cdr (cdr (quote (1 2 3 4))))))
-
-(cdr (quote (1 2 3 4)))
-(cdr (cdr (quote (1 2 3 4))))
-
-(car (cons 1 (cons 2 3)))
-(cdr (cons 1 (cons 2 3)))
-(cdr (cdr (cons 1 (cons 2 3))))
diff --git a/t/prim/define.expect b/t/prim/define.expect
@@ -1,3 +0,0 @@
-4
-4
-8
diff --git a/t/prim/define.tsp b/t/prim/define.tsp
@@ -1,6 +0,0 @@
-(define foo 4)
-foo
-(define bar foo)
-bar
-(define add +)
-(add foo bar)
diff --git a/t/prim/eq.expect b/t/prim/eq.expect
@@ -1,29 +0,0 @@
-t
-t
-t
-t
-t
-()
-()
-()
-()
-t
-t
-t
-t
-()
-()
-()
-()
-t
-t
-()
-t
-()
-()
-()
-()
-t
-t
-()
-t
diff --git a/t/prim/eq.tsp b/t/prim/eq.tsp
@@ -1,29 +0,0 @@
-(=)
-(= 1)
-(= "foo")
-(= 1 1)
-(= 1 1 1 1 1 1)
-(= 1 2)
-(= 1 1 2 1 1 1)
-(= 1 1 1 1 1 2)
-(= 2 1 1 1 1 1)
-(= 4/5 4/5)
-(= 2/1 2)
-(= 2/4 1/2)
-(= 2/4 1/2 4/8 3/6)
-(= 1/2 4/5)
-(= 5/4 4/5)
-(= 3 3/2)
-(= 3 3/2 3 3 3)
-(= (+ 1 1) (+ 2 0))
-(= "foo" "foo")
-(= "foo" "bar")
-(= "foo" "foo" "foo" "foo" "foo")
-(= "foo" "bar" "foo" "foo" "foo")
-(= "foo" 3)
-(= "foo" "foo" 4 "foo" "foo")
-(= "foo" "FOO")
-(= t t)
-(= car car)
-(= car cdr)
-(= quote quote quote)
diff --git a/t/prim/lambda.expect b/t/prim/lambda.expect
@@ -1,5 +0,0 @@
-3
-3
-9
-4
-5
diff --git a/t/prim/lambda.tsp b/t/prim/lambda.tsp
@@ -1,5 +0,0 @@
-((lambda (x) x) 3)
-((lambda (x) x) (+ 1 2))
-((lambda (x) (+ x 1)) 8)
-((lambda (a b) (+ a b)) 2 2)
-((lambda () 5))
diff --git a/t/prim/quote.expect b/t/prim/quote.expect
@@ -1,10 +0,0 @@
-1
-9234
-"foo"
-bar
-(1 2 3 4)
-(quote 1)
-(+ 2 2)
-12
-foo
-(1 2 3 4)
diff --git a/t/prim/quote.tsp b/t/prim/quote.tsp
@@ -1,11 +0,0 @@
-(quote 1)
-(quote 9234)
-(quote "foo")
-(quote bar)
-(quote (1 2 3 4))
-(quote (quote 1))
-(quote (+ 2 2))
-
-'12
-'foo
-'(1 2 3 4)
diff --git a/t/simple/comments.expect b/t/simple/comments.expect
@@ -1,2 +0,0 @@
-2
-4
diff --git a/t/simple/comments.tsp b/t/simple/comments.tsp
@@ -1,11 +0,0 @@
-; commment
-; (+ 1 1)
-(+ 1 ; more comments
-   1)
-
-   ; white space too
-  	  (+ 2 2)
-
-
-
-; another comment
diff --git a/t/simple/frac.expect b/t/simple/frac.expect
@@ -1,11 +0,0 @@
-3/4
-4/3
-1/2
-2
-2
-1/2
-1192/3619
--1/2
--1/2
--2
-2
diff --git a/t/simple/frac.tsp b/t/simple/frac.tsp
@@ -1,11 +0,0 @@
-3/4
-4/3
-1/2
-2/1
-8/4
-4/8
-02384/7238
--1/2
-1/-2
--6/3
--6/-3
diff --git a/t/simple/self.expect b/t/simple/self.expect
@@ -1,14 +0,0 @@
-1
-2
-0
-30
-12
--4
--83
-0
-4
-123
-"foo"
-"foo bar"
-t
-()
diff --git a/t/simple/self.tsp b/t/simple/self.tsp
@@ -1,14 +0,0 @@
-1
-2
-0
-30
-12
--4
--083
--0
-+4
-+123
-"foo"
-"foo bar"
-t
-()
diff --git a/t/t b/t/t
@@ -1,24 +0,0 @@
-#!/usr/bin/env bash
-
-total=0
-pass=0
-
-export LD_LIBRARY_PATH="$PWD/../tib:$LD_LIBRARY_PATH"
-
-for file in */*.tsp; do
-	expect=${file%.tsp}.expect
-
-	echo -n "testing $file ... "
-	if [[ $(../tisp "$file" 2>&1 | diff -q "$expect" - 2>&1 ) ]]; then
-		echo fail
-	else
-		echo ok
-		((pass++))
-	fi
-	((total++))
-done
-
-echo "$pass/$total tests passed"
-
-[[ $pass == $total ]] && exit 0
-exit 1
diff --git a/test.c b/test.c
@@ -0,0 +1,240 @@
+/* See LICENSE file for copyright and license details. */
+#include <assert.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "../util.h"
+#include "../tisp.h"
+#include "../tib/math.h"
+
+int
+tisp_test(Env env, const char *input, const char *expect)
+{
+	struct Str str;
+	Val v;
+	FILE *f = fopen("test.out", "w");
+	size_t nread;
+	char buf[BUFSIZ] = {0};
+
+	str.d = strdup(input);
+	v = tisp_read(env, &str);
+	if (!(v = tisp_eval(env, v)))
+		return 0;
+
+	tisp_print(f, v);
+	fclose(f);
+	f = fopen("test.out", "r");
+	while ((nread = fread(buf, 1, sizeof(buf), f)) > 0) ;
+
+	return strcmp(buf, expect) == 0;
+}
+
+/* TODO mark and show which lines error-ed */
+char *tests[][2] = {
+
+	{ "self",        NULL },
+	{ "1",           "1" },
+	{ "2",           "2" },
+	{ "0",           "0" },
+	{ "30",          "30" },
+	{ "12",          "12" },
+	{ "-4",          "-4" },
+	{ "-083",        "-83" },
+	{ "-0",          "0" },
+	{ "+4",          "4" },
+	{ "+123",        "123" },
+	{ "12.0",        "12.0" },
+	{ "08",          "8" },
+	{ "+12.34",      "12.3" },
+	{ ".34",         "0.3" },
+	{ "2.",          "2.0" },
+	{ "1e0",         "1" },
+	{ "1E+0",        "1" },
+	{ "1e-0",        "1" },
+	{ "1E4",         "10000" },
+	{ ".1e-4",       "0.0" },
+	{ "-5.0e006",    "-5000000.0" },
+	{ "-5.E+16",     "-50000000000000000.0" },
+	{ "-.05",        "-0.1" },
+	{ "-.0",         "-0.0" },
+	{ "-1.e6",       "-1000000.0" },
+	{ "\"foo\"",     "\"foo\"" },
+	{ "\"foo bar\"", "\"foo bar\"" },
+	{ "t",           "t" },
+	{ "()",          "()" },
+
+	{ "frac",       NULL },
+	{ "3/4",        "3/4" },
+	{ "4/3",        "4/3" },
+	{ "+1/2",       "1/2" },
+	{ "2/1",        "2" },
+	{ "8/+1",       "8" },
+	{ "8/4",        "2" },
+	{ "4/8",        "1/2" },
+	{ "02384/7238", "1192/3619" },
+	{ "-1/2",       "-1/2" },
+	{ "1/-2",       "-1/2" },
+	{ "-6/3",       "-2" },
+	{ "-6/-3",      "2" },
+
+	{ "comments",                  NULL },
+	{ "; commment",                "()" },
+	{ "; (+ 1 1)",                 "()" },
+	{ "(+ 1 ; more comments\n1)",  "2" },
+
+	{ "whitespace",                      NULL },
+	{ "\t \n  \n\n\t\n \t\n",            "()" },
+	{ "\t  \t(+   \t\t5 \n \n5  \n\t)",  "10" },
+
+	{ "quote",                   NULL },
+	{ "(quote 1)",               "1" },
+	{ "(quote 9234)",            "9234" },
+	{ "(quote \"foo\")",         "\"foo\"" },
+	{ "(quote bar)",             "bar" },
+	{ "(quote (1 2 3 4))",       "(1 2 3 4)" },
+	{ "(quote (quote 1))",       "(quote 1)" },
+	{ "(quote (+ 2 2))",         "(+ 2 2)" },
+	{ "'12",                     "12" },
+	{ "'foo",                    "foo" },
+	{ "'(1 2 3 4)",              "(1 2 3 4)" },
+
+	{ "cons",                         NULL },
+	{ "(cons 1 2)",                   "(1 . 2)" },
+	{ "(cons 1 (cons 2 3))",          "(1 2 . 3)" },
+	{ "(cons 1 (cons 2 (cons 3 4)))", "(1 2 3 . 4)" },
+	{ "(cons \"foo\" \"bar\")",       "(\"foo\" . \"bar\")" },
+	{ "(cons (+ 1 2) 3)",             "(3 . 3)" },
+	{ "(cons (cons 1 2) (cons 3 4))", "((1 . 2) 3 . 4)" },
+
+	{ "cxr",                                       NULL },
+	{ "(car (cons 1 2))",                          "1" },
+	{ "(cdr (cons 1 2))",                          "2" },
+	{ "(car (quote (1 2 3 4)))",                   "1" },
+	{ "(car (cdr (quote (1 2 3 4))))",             "2" },
+	{ "(car (cdr (cdr (quote (1 2 3 4)))))",       "3" },
+	{ "(car (cdr (cdr (cdr (quote (1 2 3 4))))))", "4" },
+	{ "(cdr (quote (1 2 3 4)))",                   "(2 3 4)" },
+	{ "(cdr (cdr (quote (1 2 3 4))))",             "(3 4)" },
+	{ "(car (cons 1 (cons 2 3)))",                 "1" },
+	{ "(cdr (cons 1 (cons 2 3)))",                 "(2 . 3)" },
+	{ "(cdr (cdr (cons 1 (cons 2 3))))",           "3" },
+
+	{ "cond",                                       NULL },
+	{ "(cond)",                                     "()" },
+	{ "(cond (t 1))",                               "1" },
+	{ "(cond ((= 1 1) 1) ((= 1 2) 2) (t 3))",       "1" },
+	{ "(cond ((= 1 2) 1) ((= 1 2) 2) (t (+ 1 2)))", "3" },
+	{ "(cond ((= 1 2) 1) ((= 1 1) 2) (t 3))",       "2" },
+	{ "(cond ((= 1 2) 1) ((= 1 3) 2))",             "()" },
+	{ "(cond ((= 1 2) 1) (\"foo\" 2) (t 3))",       "2" },
+	{ "(cond (() (+ 1 2)))",                        "()" },
+
+	{ "eq",                                          NULL },
+	{ "(=)",                                         "t" },
+	{ "(= 1)",                                       "t" },
+	{ "(= \"foo\")",                                 "t" },
+	{ "(= 1 1)",                                     "t" },
+	{ "(= 1 1 1 1 1 1)",                             "t" },
+	{ "(= 1 2)",                                     "()" },
+	{ "(= 1 1 2 1 1 1)",                             "()" },
+	{ "(= 1 1 1 1 1 2)",                             "()" },
+	{ "(= 2 1 1 1 1 1)",                             "()" },
+	{ "(= 4/5 4/5)",                                 "t" },
+	{ "(= 2/1 2)",                                   "t" },
+	{ "(= 2/4 1/2)",                                 "t" },
+	{ "(= 2/4 1/2 4/8 3/6)",                         "t" },
+	{ "(= 1/2 4/5)",                                 "()" },
+	{ "(= 5/4 4/5)",                                 "()" },
+	{ "(= 3 3/2)",                                   "()" },
+	{ "(= 3 3/2 3 3 3)",                             "()" },
+	{ "(= (+ 1 1) (+ 2 0))",                         "t" },
+	{ "(= \"foo\" \"foo\")",                         "t" },
+	{ "(= \"foo\" \"bar\")",                         "()" },
+	{ "(= \"foo\" \"foo\" \"foo\" \"foo\" \"foo\")", "t" },
+	{ "(= \"foo\" \"bar\" \"foo\" \"foo\" \"foo\")", "()" },
+	{ "(= \"foo\" 3)",                               "()" },
+	{ "(= \"foo\" \"foo\" 4 \"foo\" \"foo\")",       "()" },
+	{ "(= \"foo\" \"FOO\")",                         "()" },
+	{ "(= t t)",                                     "t" },
+	{ "(= car car)",                                 "t" },
+	{ "(= car cdr)",                                 "()" },
+	{ "(= quote quote quote)",                       "t" },
+
+	{ "define",                      NULL },
+	{ "(define foo 4)",              ""   },
+	{ "foo",                         "4"  },
+	{ "(define bar foo)",            ""   },
+	{ "bar",                         "4"  },
+	{ "(define add +)",              ""   },
+	{ "(add foo bar)",               "8"  },
+	{ "(define (one x) (add x 1))",  ""   },
+	{ "(one foo)",                   "5"  },
+
+	{ "lambda",                       NULL },
+	{ "((lambda (x) x) 3)",           "3" },
+	{ "((lambda (x) x) (+ 1 2))",     "3" },
+	{ "((lambda (x) (+ x 1)) 8)",     "9" },
+	{ "((lambda (a b) (+ a b)) 2 2)", "4" },
+	{ "((lambda () 5))",              "5" },
+
+	{ "add",           NULL },
+	{ "(+ 1 1)",       "2" },
+	{ "(+ 1 (+ 1 2))", "4" },
+	{ "(+ 1029 283)",  "1312" },
+
+	{ "sub",       NULL },
+	{ "(- 3)",     "-3" },
+	{ "(- +3)",    "-3" },
+	{ "(- -289)",  "289" },
+	{ "(- 5 4)",   "1" },
+	{ "(- 53 88)", "-35" },
+
+	{ "compare",      NULL },
+	{ "(< 2 3)",      "t" },
+	{ "(< 3 3)",      "()" },
+	{ "(< 4 3)",      "()" },
+	{ "(<= -2 +4)",   "t" },
+	{ "(<= -2 -2)",   "t" },
+	{ "(<= 4 -2)",    "()" },
+	{ "(> 89 34)",    "t" },
+	{ "(> 48 48)",    "()" },
+	{ "(> 98 183)",   "()" },
+	{ "(>= +4 -282)", "t" },
+	{ "(>= 39 39)",   "t" },
+	{ "(>= -32 -30)", "()" },
+
+	{ NULL,          NULL },
+};
+
+int
+main(void)
+{
+	int correct = 0, total = 0, seccorrect = 0, sectotal = 0;
+	Env env = tisp_env_init(64);
+	tib_env_math(env);
+
+	for (int i = 0; ; i++) {
+		if (!tests[i][1]) {
+			if (i != 0)
+				printf("%d/%d\n", seccorrect, sectotal);
+			if (!tests[i][0])
+				break;
+			printf("%-10s ", tests[i][0]);
+			seccorrect = 0;
+			sectotal = 0;
+		} else {
+			if (tisp_test(env, tests[i][0], tests[i][1])) {
+				correct++;
+				seccorrect++;
+			}
+			total++;
+			sectotal++;
+		}
+	}
+	printf("%-10s %d/%d\n", "total", correct, total);
+
+	tisp_env_free(env);
+	return correct != total;
+}