commit 9e8613cdd656dae8a2147f346896043ce7bca20f from: Sven M. Hallberg date: Fri Jun 27 21:17:54 2025 UTC add test.h tests commit - 82c5d7ffa2717e040bee77e99df37f811f76eded commit + 9e8613cdd656dae8a2147f346896043ce7bca20f blob - /dev/null blob + ec54dce8f6246aadc8840288e1f4fe2f1a597361 (mode 755) --- /dev/null +++ tests/helpers/assert-c @@ -0,0 +1,45 @@ +#!/bin/sh +# +# compile and run a C program given on stdin, pass the given input, and +# compare output and exit code to expected results. further arguments are +# passed as arguments to the executable. + +if [ $# -lt 4 ] +then + echo "usage: exit assert-c stdin stdout stderr [arg ...]" >&2 + exit 127 +fi + +tst=${tst:-/tmp/assert-c.$$} +src=$tst.c +inp=$tst.inp +out=$tst.out +err=$tst.err +expout=$tst.expout +experr=$tst.experr +expexit=$1 + +trap "rm -f $tst $src $inp $out $err $expout $experr" EXIT + +cat >$src || exit 127 +echo -n "$2" >$inp +echo -n "$3" >$expout || exit 127 +echo -n "$4" >$experr || exit 127 +shift 4 + +${CC:-cc} -o $tst $CFLAGS $LDFLAGS $src $LIBS >&2 || exit 127 +# NB: in the case of a compile error we can't tell why it occurred. +# the code under test might not expose an expected API. +# or the test could be faulty, the compiler missing, or some other issue. + +pass=true +<$inp >$out 2>$err $tst "$@" +exit=$? +diff -u $expout $out >&2 || pass=false +diff -u $experr $err >&2 || pass=false +if [ "$exit" -ne "$expexit" ] +then + echo "exit code $exit - expected $expexit" >&2 + pass=false +fi +$pass blob - /dev/null blob + b194ce3a4cbd59d332488cb21836f7abd272606b (mode 755) --- /dev/null +++ tests/helpers/assert-c-abort @@ -0,0 +1,51 @@ +#!/bin/sh +# +# similar to assert-c but for to exits due to abort(3), including assert(3). +# requires the exit code to be (any value) greater than or equal to 128. +# requires (only) a prefix of stderr to match the given expectation. + +if [ $# -lt 3 ] +then + echo "usage: assert-c-abort stdin stdout stderr [arg ...]" >&2 + exit 127 +fi + +tst=${tst:-/tmp/assert-c.$$} +src=$tst.c +inp=$tst.inp +out=$tst.out +err=$tst.err +expout=$tst.expout +experr=$tst.experr +errpre=$tst.errpre +core=$(basename "$tst").core + +trap "rm -f $tst $src $inp $out $err $expout $experr $errpre $core" EXIT + +cat >$src || exit 127 +echo -n "$1" >$inp +echo -n "$2" >$expout || exit 127 +echo -n "$3" >$experr || exit 127 +shift 3 + +${CC:-cc} -o $tst $CFLAGS $LDFLAGS $src $LIBS >&2 || exit 127 +# NB: in the case of a compile error we can't tell why it occurred. +# the code under test might not expose an expected API. +# or the test could be faulty, the compiler missing, or some other issue. + +nerr=$(wc -l <$experr) +[ $? -eq 0 ] || exit 127 +nerr=$(echo $nerr) # strips whitespace + +pass=true +<$inp >$out 2>$err $tst "$@" +exit=$? +head -n $nerr $err >$errpre || exit 127 +diff -u $expout $out >&2 || pass=false +diff -u $experr $errpre >&2 || pass=false +if [ "$exit" -lt 128 ] +then + echo "exit code $exit - expected 128 or greater" >&2 + pass=false +fi +$pass blob - /dev/null blob + e357e755fde21db1d3fdefe8daa426d1109757c9 (mode 755) --- /dev/null +++ tests/lang/c/RUNT-argcv.t @@ -0,0 +1,39 @@ +#!/bin/sh + +unset D V K X +export CFLAGS=-I../../lang/c +exec ./assert-c 0 \ + "" \ + "foo()\tOK\nbar()\tOK\n" \ + "foo called\nbar called\n" \ +<<-EOF + #include + #include "test.h" + + void + foo(void) + { + fputs("foo called\n", stderr); + } + + void + bar(void) + { + fputs("bar called\n", stderr); + } + + void + runtests(void) + { + /* argc, argv not needed */ + RUNT(foo); + RUNT(bar); + } + + int + main(int argc, char *argv[]) + { + runtests(); + return 0; + } +EOF blob - /dev/null blob + 58bff5ea7a6d512ffd048b2920b4eca2c71f94b5 (mode 755) --- /dev/null +++ tests/lang/c/RUNT-args.t @@ -0,0 +1,32 @@ +#!/bin/sh + +unset D V K X +export CFLAGS=-I../../lang/c +exec ./assert-c 0 \ + "" \ + "foo(0x01)\tOK\nbar(\"x y z\")\tOK\n" \ + "foo(1) called\nbar(\"x y z\") called\n" \ +<<-EOF + #include + #include "test.h" + + void + foo(int i) + { + fprintf(stderr, "foo(%d) called\n", i); + } + + void + bar(const char *s) + { + fprintf(stderr, "bar(\"%s\") called\n", s); + } + + int + main(int argc, char *argv[]) + { + RUNT(foo, 0x01); + RUNT(bar, "x y z"); + return 0; + } +EOF blob - /dev/null blob + 7d9884a039ea032514ba31232c306b7d7d563653 (mode 755) --- /dev/null +++ tests/lang/c/RUNT-dryrun.t @@ -0,0 +1,33 @@ +#!/bin/sh + +unset D V K X +export CFLAGS=-I../../lang/c +export D=1 +exec ./assert-c 0 \ + "" \ + "foo()\nbar()\n" \ + "" \ +<<-EOF + #include + #include "test.h" + + void + foo(void) + { + fputs("foo called\n", stderr); + } + + void + bar(void) + { + fputs("bar called\n", stderr); + } + + int + main(int argc, char *argv[]) + { + RUNT(foo); + RUNT(bar); + return 0; + } +EOF blob - /dev/null blob + d970873a45d9d23aacd58a1a66be094a60f21c83 (mode 755) --- /dev/null +++ tests/lang/c/RUNT.t @@ -0,0 +1,32 @@ +#!/bin/sh + +unset D V K X +export CFLAGS=-I../../lang/c +exec ./assert-c 0 \ + "" \ + "foo()\tOK\nbar()\tOK\n" \ + "foo called\nbar called\n" \ +<<-EOF + #include + #include "test.h" + + void + foo(void) + { + fputs("foo called\n", stderr); + } + + void + bar(void) + { + fputs("bar called\n", stderr); + } + + int + main(int argc, char *argv[]) + { + RUNT(foo); + RUNT(bar); + return 0; + } +EOF blob - /dev/null blob + 45f6e7c571ed29a759209fc16c59532c62793cb4 (mode 755) --- /dev/null +++ tests/lang/c/TEST-args.t @@ -0,0 +1,32 @@ +#!/bin/sh + +unset D V K X +export CFLAGS=-I../../lang/c +exec ./assert-c 0 \ + "" \ + "foo(0x01)\tOK\nbar(\"x y z\")\tOK\n" \ + "foo(1) called\nbar(\"x y z\") called\n" \ +<<-EOF + #include + #include "test.h" + + void + foo(int i) + { + fprintf(stderr, "foo(%d) called\n", i); + } + + void + bar(const char *s) + { + fprintf(stderr, "bar(\"%s\") called\n", s); + } + + int + main(int argc, char *argv[]) + { + TEST(foo, 0x01); + TEST(bar, "x y z"); + return 0; + } +EOF blob - /dev/null blob + 11481d6b28d81268043e638f9e94c1abce9a2514 (mode 755) --- /dev/null +++ tests/lang/c/TEST-dryrun.t @@ -0,0 +1,33 @@ +#!/bin/sh + +unset D V K X +export CFLAGS=-I../../lang/c +export D=1 +exec ./assert-c 0 \ + "" \ + "foo()\nbar()\n" \ + "" \ +<<-EOF + #include + #include "test.h" + + void + foo(void) + { + fputs("foo called\n", stderr); + } + + void + bar(void) + { + fputs("bar called\n", stderr); + } + + int + main(int argc, char *argv[]) + { + TEST(foo); + TEST(bar); + return 0; + } +EOF blob - /dev/null blob + 03de7bd387b8fcc262304d6c1365caee21384e2b (mode 755) --- /dev/null +++ tests/lang/c/TEST-select.t @@ -0,0 +1,33 @@ +#!/bin/sh + +unset D V K X +export CFLAGS=-I../../lang/c +exec ./assert-c 0 \ + "" \ + "foo()\tOK\n" \ + "foo called\n" \ + fo \ +<<-EOF + #include + #include "test.h" + + void + foo(void) + { + fputs("foo called\n", stderr); + } + + void + bar(void) + { + fputs("bar called\n", stderr); + } + + int + main(int argc, char *argv[]) + { + TEST(foo); + TEST(bar); + return 0; + } +EOF blob - /dev/null blob + e0d67b096ffb78d29056ddf35fa025624ea4ef0d (mode 755) --- /dev/null +++ tests/lang/c/TEST-stdin.t @@ -0,0 +1,32 @@ +#!/bin/sh + +unset D V K X +export CFLAGS=-I../../lang/c +exec ./assert-c 0 \ + "xxxxxxxx\n" \ + "foo()\tOK\nbar()\tOK\n" \ + "foo called\nbar called\n" \ +<<-EOF + #include + #include "test.h" + + void + foo(void) + { + fputs("foo called\n", stderr); + } + + void + bar(void) + { + fputs("bar called\n", stderr); + } + + int + main(int argc, char *argv[]) + { + TEST(foo); + TEST(bar); + return 0; + } +EOF blob - /dev/null blob + 0b3fd763f04c730593d1414e2814da5face5e036 (mode 755) --- /dev/null +++ tests/lang/c/TEST-type.t @@ -0,0 +1,34 @@ +#!/bin/sh + +unset D V K X +export CFLAGS=-I../../lang/c +exec ./assert-c 0 \ + "" \ + "foo()\tOK\nbar()\tOK\n" \ + "foo called\nbar called\n" \ +<<-EOF + #include + #include "test.h" + + int + foo(void) + { + fputs("foo called\n", stderr); + return 23; + } + + const char * + bar(void) + { + fputs("bar called\n", stderr); + return "hallo"; + } + + int + main(int argc, char *argv[]) + { + TEST(foo); + TEST(bar); + return 0; + } +EOF blob - /dev/null blob + 3e218cea7fc6c5d087c507b878114e11e439678b (mode 755) --- /dev/null +++ tests/lang/c/TEST-verbose.t @@ -0,0 +1,34 @@ +#!/bin/sh + +unset D V K X +export CFLAGS=-I../../lang/c +export V=1 +exec ./assert-c 0 \ + "" \ + "foo()\tOK\nbar()\tskipped\n" \ + "foo called\n" \ + fo \ +<<-EOF + #include + #include "test.h" + + void + foo(void) + { + fputs("foo called\n", stderr); + } + + void + bar(void) + { + fputs("bar called\n", stderr); + } + + int + main(int argc, char *argv[]) + { + TEST(foo); + TEST(bar); + return 0; + } +EOF blob - /dev/null blob + 0653cd8bf21dde49f881b2427d9199224dea06dc (mode 755) --- /dev/null +++ tests/lang/c/TEST.t @@ -0,0 +1,32 @@ +#!/bin/sh + +unset D V K X +export CFLAGS=-I../../lang/c +exec ./assert-c 0 \ + "" \ + "foo()\tOK\nbar()\tOK\n" \ + "foo called\nbar called\n" \ +<<-EOF + #include + #include "test.h" + + void + foo(void) + { + fputs("foo called\n", stderr); + } + + void + bar(void) + { + fputs("bar called\n", stderr); + } + + int + main(int argc, char *argv[]) + { + TEST(foo); + TEST(bar); + return 0; + } +EOF blob - /dev/null blob + 73a4d13e5fd005108bd97ac8064d23c3d9e4bf4c (mode 755) --- /dev/null +++ tests/lang/c/expect-abort.t @@ -0,0 +1,34 @@ +#!/bin/sh + +unset D V K X +export tst=/tmp/$(basename "$0").$$ +export CFLAGS=-I../../lang/c +export X=1 +exec ./assert-c-abort \ + "" \ + "" \ + "$tst.c:7: condition failed: 2 == 3\n" \ +<<-EOF + #include + #include "test.h" + + void + foo(void) + { + expect(2 == 3); /* aborts with X set */ + fputs("foo running\n", stderr); /* should not print */ + } + + void + bar(void) + { + } + + int + main(int argc, char *argv[]) + { + TEST(foo); /* expected to fail and abort */ + TEST(bar); /* will not execute */ + return 0; + } +EOF blob - /dev/null blob + 19144d3739a05efa84e9de14c155923838db56b2 (mode 755) --- /dev/null +++ tests/lang/c/expect-false.t @@ -0,0 +1,32 @@ +#!/bin/sh + +unset D V K X +export tst=/tmp/fail.t.$$ +export CFLAGS=-I../../lang/c +exec ./assert-c 1 \ + "" \ + "foo()\tFAIL\n" \ + "$tst.c:7: condition failed: 2 == 3\n" \ +<<-EOF + #include + #include "test.h" + + void + foo(void) + { + expect(2 == 3); + } + + void + bar(void) + { + } + + int + main(int argc, char *argv[]) + { + TEST(foo); /* expected to fail */ + TEST(bar); /* will not execute without K set */ + return 0; + } +EOF blob - /dev/null blob + 755833d5d4a854fa699a33f6e045488f751fc6c8 (mode 755) --- /dev/null +++ tests/lang/c/expect-noabort.t @@ -0,0 +1,34 @@ +#!/bin/sh + +unset D V K X +export tst=/tmp/fail.t.$$ +export CFLAGS=-I../../lang/c +exec ./assert-c 1 \ + "" \ + "foo()\tFAIL\n" \ + "$tst.c:7: condition failed: 2 == 3\n$tst.c:9: condition failed: 0\n" \ +<<-EOF + #include + #include "test.h" + + void + foo(void) + { + expect(2 == 3); /* will print an error */ + expect(3 == 3); + expect(0); /* will print an error */ + } + + void + bar(void) + { + } + + int + main(int argc, char *argv[]) + { + TEST(foo); /* expected to fail */ + TEST(bar); /* will not execute without K set */ + return 0; + } +EOF blob - /dev/null blob + 875b6868d0a2d61a534b8fcfecf33a9e4d275222 (mode 755) --- /dev/null +++ tests/lang/c/expect-true.t @@ -0,0 +1,31 @@ +#!/bin/sh + +unset D V K X +export CFLAGS=-I../../lang/c +exec ./assert-c 0 \ + "" \ + "foo()\tOK\nbar()\tOK\n" \ + "" \ +<<-EOF + #include + #include "test.h" + + void + foo(void) + { + expect(2 == 2); + } + + void + bar(void) + { + } + + int + main(int argc, char *argv[]) + { + TEST(foo); + TEST(bar); + return 0; + } +EOF blob - /dev/null blob + 4f7ae2be169da60e8c3f4fbf9acff7ab190e1b7d (mode 755) --- /dev/null +++ tests/lang/c/fail-abort.t @@ -0,0 +1,34 @@ +#!/bin/sh + +unset D V K X +export tst=/tmp/$(basename "$0").$$ +export CFLAGS=-I../../lang/c +export X=1 +exec ./assert-c-abort \ + "" \ + "" \ + "$tst.c:7: foo failed\n" \ +<<-EOF + #include + #include "test.h" + + void + foo(void) + { + fail("foo failed"); /* aborts with X set */ + fputs("foo running\n", stderr); /* should not print */ + } + + void + bar(void) + { + } + + int + main(int argc, char *argv[]) + { + TEST(foo); /* expected to fail and abort */ + TEST(bar); /* will not execute */ + return 0; + } +EOF blob - /dev/null blob + 8b8a650c57ea1d7c6ba6e9615c3d0ee99a18d024 (mode 755) --- /dev/null +++ tests/lang/c/fail-fmt.t @@ -0,0 +1,32 @@ +#!/bin/sh + +unset D V K X +export tst=/tmp/fail.t.$$ +export CFLAGS=-I../../lang/c +exec ./assert-c 1 \ + "" \ + "foo(23)\tFAIL\n" \ + "$tst.c:7: foo(23) failed\n" \ +<<-EOF + #include + #include "test.h" + + void + foo(int i) + { + fail("foo(%d) failed", i); + } + + void + bar(void) + { + } + + int + main(int argc, char *argv[]) + { + TEST(foo, 23); /* expected to fail */ + TEST(bar); /* will not execute without K set */ + return 0; + } +EOF blob - /dev/null blob + 354f0380a47f2d49b04acf91b6fdd39cb163aa7b (mode 755) --- /dev/null +++ tests/lang/c/fail-keepgoing.t @@ -0,0 +1,33 @@ +#!/bin/sh + +unset D V K X +export tst=/tmp/fail.t.$$ +export CFLAGS=-I../../lang/c +export K=1 +exec ./assert-c 0 \ + "" \ + "foo()\tFAIL\nbar()\tOK\n" \ + "$tst.c:7: foo failed\n" \ +<<-EOF + #include + #include "test.h" + + void + foo(void) + { + fail("foo failed"); + } + + void + bar(void) + { + } + + int + main(int argc, char *argv[]) + { + TEST(foo); /* expected to fail */ + TEST(bar); /* will still execute with K set */ + return 0; /* with K, we will exit 0! */ + } +EOF blob - /dev/null blob + 73f938d42271af687fd144b80740691fd9dea0b5 (mode 755) --- /dev/null +++ tests/lang/c/fail-noabort.t @@ -0,0 +1,33 @@ +#!/bin/sh + +unset D V K X +export tst=/tmp/fail.t.$$ +export CFLAGS=-I../../lang/c +exec ./assert-c 1 \ + "" \ + "foo()\tFAIL\n" \ + "$tst.c:7: foo failed\nfoo running\n" \ +<<-EOF + #include + #include "test.h" + + void + foo(void) + { + fail("foo failed"); /* does not abort */ + fputs("foo running\n", stderr); /* this should still print */ + } + + void + bar(void) + { + } + + int + main(int argc, char *argv[]) + { + TEST(foo); /* expected to fail */ + TEST(bar); /* will not execute without K set */ + return 0; + } +EOF blob - /dev/null blob + bffaa1fb384fb56ece9a72f01bd1eb1519469744 (mode 755) --- /dev/null +++ tests/lang/c/fail.t @@ -0,0 +1,32 @@ +#!/bin/sh + +unset D V K X +export tst=/tmp/fail.t.$$ +export CFLAGS=-I../../lang/c +exec ./assert-c 1 \ + "" \ + "foo()\tFAIL\n" \ + "$tst.c:7: foo failed\n" \ +<<-EOF + #include + #include "test.h" + + void + foo(void) + { + fail("foo failed"); + } + + void + bar(void) + { + } + + int + main(int argc, char *argv[]) + { + TEST(foo); /* expected to fail */ + TEST(bar); /* will not execute without K set */ + return 0; + } +EOF