Permalink
Browse files

restored to working version

  • Loading branch information...
mcandre committed Sep 26, 2011
1 parent 05634d0 commit 4b220af8221cc3057549d927b4e3b59b48325543
Showing with 105 additions and 48 deletions.
  1. +17 −14 example.c
  2. +80 −26 qc.c
  3. +8 −8 qc.h
View
@@ -4,14 +4,15 @@
#include <stdlib.h>
#include <stdio.h>
-int gen_odd() {
- int i = gen_int();
+void gen_odd(blob data) {
+ int i;
+ gen_int(&i);
if (i % 2 == 0) {
i++;
}
- return i;
+ qc_return(int, i);
}
bool is_odd(blob data) {
@@ -28,22 +29,24 @@ bool both_less_than(blob data) {
return a < c && b < c;
}
-char gen_digit_char() {
- int i = gen_int();
+void gen_digit_char(blob data) {
+ int i;
+ gen_int(&i);
i %= 10;
char c = '0' + (char) i;
- return c;
+ qc_return(char, c);
}
-int gen_digit() {
- int i = gen_int();
+void gen_digit(blob data) {
+ int i;
+ gen_int(&i);
i %= 10;
- return i;
+ qc_return(int, i);
}
bool does_not_parse_to(blob data) {
@@ -62,32 +65,32 @@ bool does_not_have_an_h(blob data) {
int main() {
qc_init();
- gen gs[] = { (gen) gen_odd };
+ gen gs[] = { gen_odd };
print ps[] = { print_int };
// Are all odd numbers odd?
for_all(is_odd, 1, gs, ps, int);
- gen gs2[] = { (gen) gen_int };
+ gen gs2[] = { gen_int };
print ps2[] = { print_int };
// Are all integers odd?
for_all(is_odd, 1, gs2, ps2, int);
- gen gs3[] = { (gen) gen_int, (gen) gen_int, (gen) gen_int };
+ gen gs3[] = { gen_int, gen_int, gen_int };
print ps3[] = { print_int, print_int, print_int };
// Are any two integers less than a third integer?
for_all(both_less_than, 3, gs3, ps3, int);
- gen gs4[] = { (gen) gen_digit_char, (gen) gen_digit };
+ gen gs4[] = { gen_digit_char, gen_digit };
print ps4[] = { print_char, print_int };
// Do any characters parse to a matching integer?
for_all(does_not_parse_to, 2, gs4, ps4, int);
- gen gs5[] = { (gen) gen_string };
+ gen gs5[] = { gen_string };
print ps5[] = { print_string };
// Do any string pairs match?
View
106 qc.c
@@ -11,45 +11,47 @@ void qc_init() {
QC_INITIALIZED = true;
}
-bool gen_bool() {
+void gen_bool(blob data) {
bool b = rand() % 2 == 0;
- return b;
+ qc_return(bool, b);
}
-int gen_int() {
+void gen_int(blob data) {
int i = rand();
- return i;
+ qc_return(int, i);
}
-char gen_char() {
+void gen_char(blob data) {
char c = (char) (rand() % 128);
- return c;
+ qc_return(char, c);
}
-blob* _gen_array(gen g, size_t size) {
+void _gen_array(blob data, gen g, size_t size) {
int len = rand() % 100;
- blob* arr = GC_MALLOC(len * size);
+ blob arr = GC_MALLOC(len * size);
int i;
for (i = 0; i < len; i++) {
- *(arr + i * size) = g();
+ g(arr + i * size);
}
- return arr;
+ qc_return(blob, arr);
}
-char* gen_string() {
- char* s = (char*) gen_array(gen_char, char);
+void gen_string(blob data) {
+ char* s;
- return s;
+ gen_array(&s, gen_char, char);
+
+ qc_return(char*, s);
}
void print_bool(blob data) {
- bool b = qc_args(bool, 0, bool);
+ bool b = (* (bool*) data);
if (b) {
printf("true");
@@ -60,51 +62,103 @@ void print_bool(blob data) {
}
void print_int(blob data) {
- int i = qc_args(int, 0, int);
+ int i = qc_args(int, 0, sizeof(int));
printf("%d", i);
}
void print_char(blob data) {
- char c = qc_args(char, 0, char);
+ char c = qc_args(char, 0, sizeof(char));
printf("\'%c\'", c);
}
void print_string(blob data) {
- char* s = qc_args(char*, 0, char*);
+ char* s = qc_args(char*, 0, sizeof(char*));
printf("%s", s);
}
+// Syntax:
+//
+// For simplicity, _for_all is called using the for_all macro (see qc.h).
+//
+// In this example, for_all is testing whether all integers are odd (they are not).
+//
+// Every for_all call begins with a property function. For example, is_odd takes
+// an int and returns a bool.
+//
+// bool is_odd(void *data);
+//
+// In order to handle arbitrarily-typed property functions, qc uses a special
+// protocol, qc_args, to pass test values to the property function.
+//
+// bool is_odd(void *data) {
+// int n = qc_args(int, 0, sizeof(int));
+//
+// return n % 2 == 1;
+// }
+//
+// qc_args' first argument is a type: int, char, int*, char*, int**, char**, ...
+// The second argument is the index (qc internally stores all test cases in a
+// single array).
+// The final argument is the maximum byte size of the property's input types. For
+// example, is_equal(short, int)'s maximum byte size would be sizeof(int).
+
+//
+// for_all's first argument is the name of such a property function. The next
+// argument is an array of generator functions. The is_odd property
+// function has a single argument, an integer. Thus each test case consists of a
+// random integer to be passed to the is_odd property function. More complicated
+// property functions (e.g. cmp(int, int)) may have multiple arguments, and
+// therefore require multiple generators.
+//
+// gen gs[] = { gen_int };
+//
+// When a test case fails, the values for which the property returns false will be
+// printed. For each generator, a corresponding printer function is necessary.
+// for_all is designed to test properties of arbitrary numbers of arbitrary types;
+// because C has no universal print(some_object) function, the framework user must
+// specify printer functions for each generator function. More complicated types,
+// such as trees, graphs, and linked lists require the framework user to write
+// custom printer functions, but the syntax remains the same.
+//
+// print ps[] = { print_int };
+//
+// Finally, for_all requires the maximum byte size of the types to be passed to the
+// property function. This information helps for_all hold all test values in a single array,
+// which it passes to the test property.
+//
+// for_all(is_odd, 1, gs, ps, sizeof(int));
+
void _for_all(prop property, int arglen, gen gs[], print ps[], size_t max_size) {
- int i, j, k;
+ int i, j;
// Because GC_MALLOC will segfault if GC_INIT() is not called beforehand.
if (!QC_INITIALIZED) {
printf("*** Error: Run qc_init() before calling for_all().\n");
return;
}
- blob* test_case = GC_MALLOC(arglen * max_size);
+ blob values = GC_MALLOC(arglen * max_size);
- for (i = 0; i < 1/*00*/; i++) {
+ for (i = 0; i < 100; i++) {
for (j = 0; j < arglen; j++) {
- *(test_case + j * max_size) = gs[j]();
+ gs[j](values + j * max_size);
}
- bool holds = property(test_case);
+ bool holds = property(values);
- // if (!holds) {
+ if (!holds) {
printf("*** Failed!\n");
- for (k = 0; k < arglen; k++) {
- ps[k](test_case + k * max_size);
+ for (j = 0; j < arglen; j++) {
+ ps[j](values + j * max_size);
printf("\n");
}
return;
- // }
+ }
}
printf("+++ OK, passed 100 tests.\n");
View
16 qc.h
@@ -17,24 +17,24 @@ bool QC_INITIALIZED;
void qc_init();
-// #define qc_return(type, value) ((* (type*) data) = value)
+#define qc_return(type, value) ((* (type*) data) = value)
#define qc_args(type, n, max_class) ((* (type*) (data + n * sizeof(max_class))))
typedef void* blob;
-typedef blob (*gen)();
+typedef void (*gen)(blob);
typedef void (*print)(blob);
typedef bool (*prop)(blob);
-bool gen_bool();
-int gen_int();
-char gen_char();
+void gen_bool(blob data);
+void gen_int(blob data);
+void gen_char(blob data);
-blob* _gen_array(gen g, size_t size);
+void _gen_array(blob data, gen g, size_t size);
-#define gen_array(g, class) (_gen_array((gen) g, sizeof(class)))
+#define gen_array(data, g, class) (_gen_array(data, (gen) g, sizeof(class)))
-char* gen_string();
+void gen_string(blob data);
void print_bool(blob data);
void print_int(blob data);

0 comments on commit 4b220af

Please sign in to comment.