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
|
/** @file 410user/progs/score.c
*
* @author Ryan Chen (ryanc1)
* @author Urvi Agrawal (urvia)
*
* @brief Runs batches of scoreboard tests based on flags provided in argv
* @public yes
* @for p3
* @covers argc/argv, fork(), exec(), new_pages(), remove_pages()
*
* @bug None known
*/
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include "syscall.h"
#include "simics.h"
#include "string.h"
// These tests will be run if no other test suite is specified in argv.
// @covers Loading, getpid(), exec(), fork(), print()
char *default_tests[] = {
"getpid_test1",
"loader_test1",
"loader_test2",
"exec_basic",
"exec_nonexist",
"fork_test1",
"print_basic",
NULL,
};
// Run these tests by adding "memory" to argv.
// @covers new_pages(), remove_pages(), page fault handler,
// zeroed allocations/ZFOD
char *memory_tests[] = {
"new_pages",
"remove_pages_test1",
"mem_permissions",
NULL,
};
typedef struct {
char *name;
char **programs;
} TestSuite;
// Array mapping strings potentially in argv[1] to test tables
TestSuite suites[] = {
{"memory", memory_tests},
{NULL, default_tests},
};
// You know how in kindergarten you didn't actually sleep during
// naptime so you just counted the number of tiles on the ceiling?
// No? Just me?
#define FAKE_SLEEP_DELAY 8096
int num_tiles_gcc_please_I_want_to_live = 0;
static void spin_delay() {
for (int i = 0; i < FAKE_SLEEP_DELAY; i++) {
++num_tiles_gcc_please_I_want_to_live;
}
}
// Returns 0 if x == NULL, y == NULL
// Returns some unspecified non-zero value if only one of x or y is NULL
// Otherwise, returns strcmp(x, y)
int safe_strcmp(char *x, char *y) {
if (x == NULL && y == NULL) {
return 0;
} else if (x == NULL) {
return -42;
} else if (y == NULL) {
return -42;
} else {
return strcmp(x, y);
}
}
// Mass fork()/exec() all the tests in the named test suite.
void fork_test_suite(TestSuite *test_suite) {
if (test_suite->name == NULL) {
lprintf("score: Running default test suite.");
} else {
lprintf("score: Running test suite '%s'", test_suite->name);
}
int program_num = 0;
while (test_suite->programs[program_num] != NULL) {
int pid = fork();
char *testname = test_suite->programs[program_num];
if (pid < 0) {
lprintf("score: fork() failed while launching %s", testname);
spin_delay();
} else if (pid == 0) {
char *args[2];
args[0] = testname;
args[1] = NULL;
exec(testname, args);
lprintf("score: exec(%s) failed..?", testname);
} else { // pid > 0
++program_num;
}
}
}
void run_suite(char *suite_name) {
int num_suites_loaded = sizeof(suites) / sizeof(suites[0]);
for (int i = 0; i < num_suites_loaded; i++) {
if (safe_strcmp(suite_name, suites[i].name) == 0) {
fork_test_suite(&suites[i]);
return;
}
}
lprintf("score: test suite '%s' not found.", suite_name);
}
int main(int argc, char **argv) {
if (argc == 0) { // Maybe argv is not correct?
lprintf("score: argc == 0??");
} else {
run_suite(NULL); // Always run the default suite.
if (argc >= 2) {
run_suite(argv[1]); // Additionally, run a named test suite
}
}
// Since this test is meant to be run instead of init (before the shell is
// functional), this program must be persistent.
int sheep = 0;
while (true) {
++sheep;
spin_delay();
}
lprintf("score: escaped infinite loop???");
return -42; // Hopefully not.
}
|