/
suspect.h
147 lines (136 loc) · 4.01 KB
/
suspect.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/* * * * * * * * * * * * * * * * * * * * * * * * *
*
* Automatic Test Case Iteration
*
* * * * * * * * * * * * * * * * * * * * * * * * */
typedef struct TestCase {
char* name;
struct TestCase* next;
} TestCase;
typedef struct TestSuite {
char* name;
struct TestCase* first;
struct TestCase* last;
} TestSuite;
int append_test_case(TestSuite* ts, char* case_name) {
TestCase* tc = (TestCase*)malloc(sizeof(TestCase));
tc->name = case_name;
tc->next = NULL;
if (ts->first == NULL) {
// Assume ts is empty
ts->first = tc;
ts->last = tc;
} else {
// Appending to nonempty ts
ts->last->next = tc;
ts->last = tc;
}
return 0;
}
TestSuite* create_test_suite(char* name) {
TestSuite* ts = (TestSuite*)malloc(sizeof(TestSuite));
ts->name = name;
ts->first = NULL;
ts->last = NULL;
}
void print_test_name(TestCase* tc) {
printf("We have a test named '%s'\n", tc->name);
}
char* string_builder(char* format, ...) {
va_list ap1;
va_start(ap1, format);
va_list ap2;
va_copy(ap2,ap1);
char* empty_string = "";
size_t size_of_empty_string = 0;
int num_chars_needed = vsnprintf(empty_string, size_of_empty_string, format, ap1);
va_end(ap1);
size_t output_region_size = sizeof(char) * (num_chars_needed + 1); //Include room for \0 character
char* safe_output_region = (char*)malloc(output_region_size);
vsprintf(safe_output_region, format, ap2);
va_end(ap2);
return safe_output_region;
}
static int num_failures = 0;
char* test_executable_path;
// ANSI Color stuff stolen gleefully from http://stackoverflow.com/questions/3219393/stdlib-and-colored-output-in-c
// Many thanks to Andrejs Cainikovs (http://stackoverflow.com/users/147407/andrejs-cainikovs)
#define ANSI_COLOR_GREEN "\x1b[32m"
#define ANSI_COLOR_RED "\x1b[31m"
#define ANSI_COLOR_RESET "\x1b[0m"
void run_test(TestCase* tc) {
char test_command[256];
int test_status;
printf("\t%s ",tc->name);
sprintf(test_command, "%s \"%s\"", test_executable_path, tc->name);
test_status = system(test_command);
if(test_status != 0) {
num_failures++;
printf(ANSI_COLOR_RED "Fail" ANSI_COLOR_RESET "\n");
} else {
printf(ANSI_COLOR_GREEN "Pass" ANSI_COLOR_RESET "\n");
}
}
#define iterate_suite(ts, method)\
do {\
TestCase* tc = ts->first;\
while(tc != NULL) {\
method(tc);\
tc = tc->next;\
}\
} while(0);
/* * * * * * * * * * * * * * * * * * * * * * * * *
*
* suspect API
*
* * * * * * * * * * * * * * * * * * * * * * * * */
#define NOPE 0
#define YUP 1
#define TEST_NAME argv[1]
#define suspect_context(description, tests) \
int main(int argc, const char** argv) {\
int test_exists = NOPE;\
int test_passed = NOPE;\
int driver = NOPE;\
TestSuite* ts = NULL;\
if (argc < 2) {\
printf("%s\n", description);\
ts = create_test_suite(description);\
test_executable_path = (char*)malloc(strlen(argv[0]) * sizeof(char));\
strcpy(test_executable_path,argv[0]);\
driver = YUP;\
}\
char* exit_msg = "No Message Set";\
if (NOPE == YUP) {}\
tests\
if(driver == YUP) {\
iterate_suite(ts,run_test);\
printf("%d tests failed.\n",num_failures);\
return (num_failures > 0) ? 0 : 1;\
}\
if(test_exists == NOPE) {\
printf("No test named '%s' exists\n", TEST_NAME);\
return 1;\
}\
if(test_passed == NOPE) {\
printf("\t\t%s\n", exit_msg);\
return 1;\
}\
return 0;\
}
#define suspect_test(description, body)\
else if(driver == YUP && append_test_case(ts, description) != 0) {}\
else if(driver == NOPE && test_exists == NOPE && strcmp(TEST_NAME,description) == 0) {\
test_exists = YUP;\
test_passed = YUP;\
body\
}
#define suspect_assert(message, expr) do { if (!(expr)) { test_passed = NOPE; exit_msg = message;}} while (0);
#define suspect_epsilon(actual, epsilon, target)\
do {\
if (!((actual >= target - epsilon) && (actual <= target + epsilon))) {\
test_passed = NOPE;\
char* exit_msg_format = "Expected "#actual" in B_{"#epsilon"}("#target"), but %f \\notin [%f,%f]";\
exit_msg = string_builder(exit_msg_format,actual,target - epsilon, target + epsilon);\
}\
} while(0);