#LDFLAGS += -pg
# GCC/Clang Coverage
-#CFLAGS += -g -O0 --coverage
-#LDFLAGS += -g -O0 --coverage
+CFLAGS += -g -O0 --coverage
+LDFLAGS += -g -O0 --coverage
/**
- @brief A minimalistic unit testing framework for C.
- @author Michael D. Lowis
- @license BSD 2-clause License
+ Aardvark Test Framework - A minimalistic unit testing framework for C.
+
+ Copyright 2014 Michael D. Lowis
+
+ Permission to use, copy, modify, and/or 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.
*/
#ifndef ATF_H
#define ATF_H
#include <stddef.h>
#include <stdbool.h>
+#include <setjmp.h>
+#include <assert.h>
extern char* Curr_Test;
void atf_init(int argc, char** argv);
#define CHECK(expr) \
if(atf_test_assert((expr), #expr, __FILE__, __LINE__)) break
+#define CHECK_EXITCODE(code) \
+ CHECK(ExitCode == code)
+
#define TEST_SUITE(name) \
void name(void)
#define RUN_EXTERN_TEST_SUITE(name) \
do { extern TEST_SUITE(name); RUN_TEST_SUITE(name); } while(0)
-#define PRINT_TEST_RESULTS \
- atf_print_results
+#define EXPECT_EXIT \
+ if ((ExitExpected = true, 0 == setjmp(ExitPad)))
/* Function Definitions
*****************************************************************************/
unsigned int Curr_Line = 0;
static unsigned int Total = 0;
static unsigned int Failed = 0;
+bool ExitExpected;
+int ExitCode;
+jmp_buf ExitPad;
#ifndef NO_SIGNALS
static void handle_signal(int sig) {
return Failed;
}
-#undef INCLUDE_DEFS
+void exit(int code) {
+ if (ExitExpected) {
+ ExitCode = code;
+ ExitExpected = false;
+ longjmp(ExitPad, 1);
+ } else {
+ assert(!"Unexpected exit. Something went wrong");
+ }
+}
#endif
#endif /* ATF_H */
--- /dev/null
+/**
+ QCheck - A minimalistic property based testing framework.
+
+ Copyright 2019 Michael D. Lowis
+
+ Permission to use, copy, modify, and/or 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.
+*/
+#ifndef QCHECK_H
+#define QCHECK_H
+
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+
+typedef struct QCValue {
+ void (*showfn)(struct QCValue* val);
+ void (*freefn)(struct QCValue* val);
+ long ndata;
+ long data[];
+} QCValue;
+
+typedef struct {
+ int status;
+ int nvals;
+ QCValue** vals;
+} QCResult;
+
+typedef int (*QCProp)(int nvals, QCValue** vals);
+
+typedef QCValue* (*QCGenFn)(void);
+
+#define VAL(v, type) ((type)((v)->data[0]))
+
+void qcinit(int seed);
+void qcntrials(int ntrials);
+QCValue* qcalloc(size_t sz, void* data);
+long qcrandr(long from, long to);
+long qcrand(void);
+void qcfree(int nvals, QCValue** vals);
+void qcshow(int nvals, QCValue** vals);
+QCResult vqcheck(QCProp prop, int nvals, va_list vals);
+int qcheck(char* desc, QCProp prop, int nvals, ...);
+
+void ShowLong(QCValue* val);
+void ShowBool(QCValue* val);
+void ShowChar(QCValue* val);
+
+QCValue* MkLong(long val, void (*showfn)(QCValue* val));
+QCValue* GenLongR(long from, long to);
+QCValue* GenLong(void);
+QCValue* GenU8(void);
+QCValue* GenU16(void);
+QCValue* GenU32(void);
+QCValue* GenBool(void);
+QCValue* GenByte(void);
+QCValue* GenAsciiChar(void);
+QCValue* GenAsciiString(void);
+
+/* Function Definitions
+ *****************************************************************************/
+#ifdef INCLUDE_DEFS
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static int Seed = 0, NTrials = 1000;
+
+void qcinit(int seed) {
+ Seed = (seed ? seed : time(NULL));
+ srand(Seed);
+}
+
+void qcntrials(int ntrials) {
+ NTrials = ntrials;
+}
+
+QCValue* qcalloc(size_t sz, void* data) {
+ QCValue* value = calloc(1, sizeof(QCValue) + sz);
+ if (data) memcpy(value->data, data, sz);
+ value->ndata = 1;
+ return value;
+}
+
+long qcrandr(long from, long to) {
+ return ((rand() % (to - from + 1)) + from);
+}
+
+long qcrand(void) {
+ return qcrandr(0, RAND_MAX);
+}
+
+void qcfree(int nvals, QCValue** vals) {
+ for (int i = 0; i < nvals; i++) {
+ if (vals[i]->freefn) vals[i]->freefn(vals[i]);
+ free(vals[i]);
+ }
+ free(vals);
+}
+
+void qcshow(int nvals, QCValue** vals) {
+ for (int i = 0; i < nvals; i++) {
+ printf("Argument %d: ", i);
+ vals[i]->showfn(vals[i]);
+ }
+}
+
+QCResult vqcheck(QCProp prop, int nvals, va_list vals) {
+ /* generate the input values */
+ QCValue** values = NULL;
+ if (nvals) {
+ values = malloc(sizeof(QCValue*) * nvals);
+ for (int i = 0; i < nvals; i++)
+ values[i] = (va_arg(vals, QCGenFn))();
+ }
+ /* run the test and get the result */
+ QCResult result = { .status = 0 };
+ result.status = prop(nvals, values);
+ result.nvals = nvals;
+ result.vals = values;
+ return result;
+}
+
+int qcheck(char* desc, QCProp prop, int nvals, ...) {
+ int passed = 0;
+ QCResult result;
+ va_list vals;
+ for (int i = 0; i < NTrials; i++) {
+ va_start(vals, nvals);
+ result = vqcheck(prop, nvals, vals);
+ va_end(vals);
+ if (!result.status) break;
+ qcfree(result.nvals, result.vals);
+ passed++;
+ }
+ /* show 'em the results */
+ if (passed == NTrials) {
+ printf("%d tests passed for property: %s\n", passed, desc);
+ } else if (!result.status) {
+ printf("Property: %s\nFalsifiable after %d tests (seed: %d)\n", desc, passed+1, Seed);
+ qcshow(result.nvals, result.vals);
+ qcfree(result.nvals, result.vals);
+ return 0;
+ }
+ return 1;
+}
+
+void ShowLong(QCValue* val) {
+ printf("%ld\n", (val->data[0]));
+}
+
+void ShowBool(QCValue* val) {
+ printf("%s\n", (val->data[0] ? "true" : "false"));
+}
+
+void ShowChar(QCValue* val) {
+ printf("'%c'\n", (char)(val->data[0]));
+}
+
+void ShowByte(QCValue* val) {
+ printf("0x%02x\n", (char)(val->data[0]));
+}
+
+void ShowString(QCValue* val) {
+ printf("'%s'\n", (char*)(val->data));
+}
+
+QCValue* MkLong(long val, void (*showfn)(QCValue* val)) {
+ QCValue* value = qcalloc(sizeof(long), &val);
+ value->showfn = showfn;
+ return value;
+}
+
+QCValue* MkArray(size_t nelems, size_t elemsz, void (*showfn)(QCValue* val)) {
+ QCValue* value = qcalloc(nelems * elemsz, NULL);
+ value->showfn = showfn;
+ return value;
+}
+
+QCValue* GenLongR(long from, long to) {
+ return MkLong(qcrandr(from, to), ShowLong);
+}
+
+QCValue* GenLong(void) {
+ return MkLong(qcrand(), ShowLong);
+}
+
+QCValue* GenU8(void) {
+ return GenLongR(0, UINT8_MAX);
+}
+
+QCValue* GenU16(void) {
+ return GenLongR(0, UINT16_MAX);
+}
+
+QCValue* GenU32(void) {
+ return GenLongR(0, UINT32_MAX);
+}
+
+QCValue* GenBool(void) {
+ return MkLong(qcrandr(0, 1), ShowBool);
+}
+
+QCValue* GenByte(void) {
+ return MkLong(qcrandr(0, 255), ShowByte);
+}
+
+QCValue* GenAsciiChar(void) {
+ return MkLong(qcrandr(32, 127), ShowChar);
+}
+
+QCValue* GenAsciiString(void) {
+ size_t nelem = qcrandr(1, 1024);
+ QCValue* value = MkArray(nelem+1, 1, ShowString);
+ char* string = (char*)value->data;
+ for (size_t i = 0; i < nelem; i++)
+ *(string++) = qcrandr(32,127);
+ return value;
+}
+
+#endif
+
+#endif /* QCHECK_H */
#include <atf.h>
+#include <qcheck.h>
#include <stdc.h>
#include <utf.h>
#include <edit.h>
buf_puts(&TestBuf, str);
}
-/*
-static bool buf_text_eq(char* str) {
- buf_selall(&TestBuf);
- char* bstr = buf_gets(&TestBuf);
- int ret = strcmp(str, bstr);
- free(bstr);
- return (ret == 0);
+#define QCHECK(desc, prop, ...) \
+ CHECK(qcheck(desc, prop, __VA_ARGS__))
+
+int getc_returns_putc(int nvals, QCValue** vals) {
+ (void)nvals;
+ Buf buf = {0};
+ buf_init(&buf);
+ buf_putc(&buf, vals[0]->data[0]);
+ buf.selection.end = buf.selection.beg = 0;
+ return (vals[0]->data[0] == buf_getc(&buf));
+}
+
+int gets_returns_puts(int nvals, QCValue** vals) {
+ (void)nvals;
+ Buf buf = {0};
+ buf_init(&buf);
+ char* input = (char*)(vals[0]->data);
+ buf_puts(&buf, input);
+ buf.selection.beg = 0;
+ buf.selection.end = buf_end(&buf);
+ char* output = buf_gets(&buf);
+ return (!strcmp(input,output));
}
-*/
TEST_SUITE(BufferTests) {
+ TEST(buf should adhere to specific properties) {
+ QCHECK("getc should return the same printable ascii value inserted with putc",
+ getc_returns_putc, 1, GenAsciiChar);
+ QCHECK("gets should return the same printable ascii string inserted with puts",
+ gets_returns_puts, 1, GenAsciiString);
+ }
+
/* Initializing
*************************************************************************/
TEST(buf_init should initialize an empty buffer) {
#include <stdc.h>
#include <utf.h>
#include <edit.h>
+
#define INCLUDE_DEFS
#include <atf.h>
-#define INCLUDE_DEFS
+#include <qcheck.h>
#include "config.h"
int main(int argc, char** argv) {
- atf_init(argc,argv);
+ qcinit(argc >= 2 ? strtol(argv[1], 0, 0) : 0);
+ atf_init(argc, argv);
RUN_EXTERN_TEST_SUITE(BufferTests);
RUN_EXTERN_TEST_SUITE(Utf8Tests);
return atf_print_results();
-#include <time.h>
-
#define TEST
#include "src/tide.c"
-typedef struct QCValue QCValue;
-struct QCValue {
- void (*showfn)(QCValue* val);
- void (*freefn)(QCValue* val);
- long ndata;
- long data[];
-};
-
-typedef struct {
- int status;
- int nvals;
- QCValue** vals;
-} QCResult;
-
-typedef int (*QCProp)(int nvals, QCValue** vals);
-
-typedef QCValue* (*QCGenFn)(void);
-
-int Seed = 0, NTrials = 10000;
-
-void qcinit(int seed) {
- Seed = (seed ? seed : time(NULL));
- srandom(Seed);
-}
-
-void qcntrials(int ntrials) {
- NTrials = ntrials;
-}
-
-QCValue* qcalloc(size_t sz, void* data) {
- QCValue* value = calloc(1, sizeof(QCValue) + sz);
- memcpy(value->data, data, sz);
- return value;
-}
-
-long qcrandr(long from, long to) {
- return ((random() % (to - from + 1)) + from);
-}
-
-long qcrand(void) {
- return qcrandr(0, RAND_MAX);
-}
-
-void qcfree(int nvals, QCValue** vals) {
- for (int i = 0; i < nvals; i++) {
- if (vals[i]->freefn) vals[i]->freefn(vals[i]);
- free(vals[i]);
- }
- free(vals);
-}
-
-void qcshow(int nvals, QCValue** vals) {
- for (int i = 0; i < nvals; i++) {
- printf("Argument %d: ", i);
- vals[i]->showfn(vals[i]);
- }
-}
-
-QCResult vqcheck(QCProp prop, int nvals, va_list vals) {
- /* generate the input values */
- QCValue** values = NULL;
- if (nvals) {
- values = malloc(sizeof(QCValue*) * nvals);
- for (int i = 0; i < nvals; i++)
- values[i] = (va_arg(vals, QCGenFn))();
- }
- /* run the test and get the result */
- QCResult result = { .status = 0 };
- result.status = prop(nvals, values);
- result.nvals = nvals;
- result.vals = values;
- return result;
-}
-
-int qcheck(char* desc, QCProp prop, int nvals, ...) {
- int passed = 0;
- QCResult result;
- va_list vals;
- for (int i = 0; i < NTrials; i++) {
- va_start(vals, nvals);
- result = vqcheck(prop, nvals, vals);
- va_end(vals);
- if (!result.status) break;
- qcfree(result.nvals, result.vals);
- passed++;
- }
- /* show 'em the results */
- if (passed == NTrials) {
- printf("%d tests passed for property: %s\n", passed, desc);
- } else if (!result.status) {
- printf("Property: %s\nFalsifiable after %d tests (seed: %d)\n", desc, passed+1, Seed);
- qcshow(result.nvals, result.vals);
- /* should investigate shrinking input here as well */
- qcfree(result.nvals, result.vals);
- return 0;
- }
- return 1;
-}
-
-/************************************************/
-
-void ShowLong(QCValue* val) {
- printf("%ld\n", (val->data[0]));
-}
-
-void ShowBool(QCValue* val) {
- printf("%s\n", (val->data[0] ? "true" : "false"));
-}
-
-void ShowChar(QCValue* val) {
- printf("'%c'\n", (char)(val->data[0]));
-}
-
-QCValue* MkLong(long val, void (*showfn)(QCValue* val)) {
- QCValue* value = qcalloc(sizeof(long), &val);
- value->showfn = showfn;
- return value;
-}
-
-QCValue* GenLongR(long from, long to) {
- return MkLong(qcrandr(from, to), ShowLong);
-}
-
-QCValue* GenLong(void) {
- return MkLong(qcrand(), ShowLong);
-}
-
-QCValue* GenU8(void) {
- return GenLongR(0, UINT8_MAX);
-}
-
-QCValue* GenU16(void) {
- return GenLongR(0, UINT16_MAX);
-}
-
-QCValue* GenU32(void) {
- return GenLongR(0, UINT32_MAX);
-}
-
-QCValue* GenBool(void) {
- return MkLong(qcrandr(0, 1), ShowBool);
-}
-
-QCValue* GenChar(void) {
- return MkLong(qcrandr(0, 127), ShowChar);
-}
+#define INCLUDE_DEFS
+#include "qcheck.h"
/************************************************/
// int pid = fork();
// /* test the resize event */
// if (pid == 0) {
- XEvent e = {0};
- e.xconfigure.width = vals[0]->data[0];
- e.xconfigure.height = vals[1]->data[0];
- tide_init();
- (X.eventfns[ConfigureNotify])(&X, &e);
- xupdate(NULL);
+// XEvent e = {0};
+// e.xconfigure.width = vals[0]->data[0];
+// e.xconfigure.height = vals[1]->data[0];
+// tide_init();
+// (X.eventfns[ConfigureNotify])(&X, &e);
+// xupdate(NULL);
// }
// switch (fork()) {
// case 0:
}
int main(int argc, char** argv) {
- (void)argc, (void)argv, (void)usage;
+ (void)usage;
- qcinit(0);
+ qcinit(argc >= 2 ? strtol(argv[1], 0, 0) : 0);
qcheck("all numbers are divisible by 2", divisible_by_two, 1, GenLong);
- qcheck("resizing should not crash the app",
- resizing_should_not_crash, 2, GenU16, GenU16);
return 0;
}