struct QCValue {
void (*showfn)(QCValue* val);
void (*freefn)(QCValue* val);
+ long ndata;
long data[];
};
QCValue** vals;
} QCResult;
-typedef int (*QCProp)(QCValue** vals, int nvals);
+typedef int (*QCProp)(int nvals, QCValue** vals);
typedef QCValue* (*QCGenFn)(void);
NTrials = ntrials;
}
-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(values, nvals);
- result.nvals = nvals;
- result.vals = values;
- return result;
+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(QCValue** vals, int nvals) {
+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(QCValue** vals, int nvals) {
+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;
result = vqcheck(prop, nvals, vals);
va_end(vals);
if (!result.status) break;
- qcfree(result.vals, result.nvals);
+ qcfree(result.nvals, result.vals);
passed++;
}
/* show 'em the results */
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.vals, result.nvals);
+ qcshow(result.nvals, result.vals);
/* should investigate shrinking input here as well */
- qcfree(result.vals, result.nvals);
+ qcfree(result.nvals, result.vals);
return 0;
}
return 1;
}
-QCValue* qcalloc(size_t sz, void* data) {
- QCValue* value = calloc(1, sizeof(QCValue) + sz);
- memcpy(value->data, data, sz);
- return value;
-}
-
/************************************************/
void ShowLong(QCValue* val) {
printf("'%c'\n", (char)(val->data[0]));
}
-QCValue* GenLongR(long from, long to) {
- long val = ((random() % (to - from + 1)) + from);
+QCValue* MkLong(long val, void (*showfn)(QCValue* val)) {
QCValue* value = qcalloc(sizeof(long), &val);
- value->showfn = ShowLong;
+ value->showfn = showfn;
return value;
}
+QCValue* GenLongR(long from, long to) {
+ return MkLong(qcrandr(from, to), ShowLong);
+}
+
QCValue* GenLong(void) {
- return GenLongR(0, RAND_MAX);
+ return MkLong(qcrand(), ShowLong);
}
QCValue* GenU8(void) {
}
QCValue* GenBool(void) {
- QCValue* val = GenLongR(0, 1);
- val->showfn = ShowBool;
- return val;
+ return MkLong(qcrandr(0, 1), ShowBool);
}
QCValue* GenChar(void) {
- QCValue* val = GenU8();
- val->showfn = ShowChar;
- return val;
+ return MkLong(qcrandr(0, 127), ShowChar);
}
/************************************************/
/************************************************/
-int divisible_by_two(QCValue** vals, int nvals) {
+int divisible_by_two(int nvals, QCValue** vals) {
(void)nvals;
return ((vals[0]->data[0] % 2) == 0);
}
+int resizing_should_not_crash(int nvals, QCValue** vals) {
+// 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);
+// }
+// switch (fork()) {
+// case 0:
+// tide_init();
+// break;
+// default:
+// /* wait for pid to exit */
+// break;
+// }
+ return ((void)vals, (void)nvals, 1);
+}
+
int main(int argc, char** argv) {
(void)argc, (void)argv, (void)usage;
qcinit(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;
}