-
Notifications
You must be signed in to change notification settings - Fork 0
/
tinobsy_test.cpp
153 lines (135 loc) · 3.88 KB
/
tinobsy_test.cpp
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
148
149
150
151
152
153
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <setjmp.h>
#define TINOBSY_DEBUG
#include "tinobsy.hpp"
using namespace tinobsy;
object_type cons_type("cons", markcons, NULL, NULL);
class MyVM : public vm {
public:
object* stack;
void mark_globals() {
this->markobject(this->stack);
}
void push(object* thing, object*& stack) {
object* cell = this->alloc(&cons_type);
cell->car = thing;
cell->cdr = stack;
stack = cell;
}
void push(object* thing) {
push(thing, this->stack);
}
};
MyVM* VM;
const int times = 10;
size_t fails = 0;
#define TEST(cond, ...) do { \
if (!(cond)) { \
DBG("Test failed: %s", #cond); \
DBG(__VA_ARGS__); \
fprintf(stderr, "Test failed %s\n", #cond); \
fails++; \
} else { \
DBG("Test succeeded: %s", #cond); \
} \
} while(0)
void divider();
inline void divider() {
printf("\n-------------------------------------------------------------\n\n");
}
void free_string(object* self) {
free(self->as_chars);
}
object_type nothing_type("nil", NULL, NULL, NULL);
object_type atom_type("atom", NULL, free_string, NULL);
void test_sweep() {
DBG("test mark-sweep collector: objects are swept when not put into a thread");
size_t oldobj = VM->freespace;
VM->alloc(¬hing_type);
VM->alloc(¬hing_type);
VM->alloc(¬hing_type);
VM->alloc(¬hing_type);
VM->alloc(¬hing_type);
VM->alloc(¬hing_type);
VM->alloc(¬hing_type);
DBG("Begin sweep of everything");
VM->gc();
TEST(VM->freespace == oldobj, "did not sweep right objects %zu %zu", VM->freespace, oldobj);
}
void test_mark_no_sweep() {
DBG("test mark-sweep collector: objects aren't swept when marked on globals");
for (int i = 0; i < times; i++) {
object* foo = VM->alloc(¬hing_type);
VM->push(foo);
}
size_t oldobj = VM->freespace;
VM->gc();
TEST(VM->freespace == oldobj, "swept some by mistake");
}
char randchar() {
return "qwertyuiopasdfghjklzxcvbnm"[rand() % 26];
}
void test_freeing_things() {
DBG("Test owned pointers are freed");
char buffer[64] = { 0 };
for (int i = 0; i < times; i++) {
for (int j = 0; j < 63; j++) buffer[j] = randchar();
DBG("Random atom is %s", buffer);
object* foo = VM->alloc(&atom_type);
foo->as_chars = strdup(buffer);
}
VM->gc();
DBG("Check Valgrind output to make sure stuff was freed");
}
void test_reference_cycle() {
DBG("Test unreachable reference cycle gets collected");
size_t oldobj = VM->freespace;
object* a = VM->alloc(&cons_type);
car(a) = cdr(a) = a;
VM->gc();
TEST(VM->freespace == oldobj, "a was not collected");
}
const object_type Integer("int", NULL, NULL, NULL);
object* makeint(vm* vm, int64_t z) {
INTERN(vm, int64_t, &Integer, z);
object* x = vm->alloc(&Integer);
x->as_big_int = z;
return x;
}
void test_interning() {
DBG("Test primitives are interned");
int64_t foo = 47;
object* a = makeint(VM, foo);
ASSERT(a->as_big_int == 47, "did not copy right");
for (int i = 0; i < times; i++) {
object* b = makeint(VM, foo);
TEST(a == b, "not interned");
}
}
typedef void (*test)();
test tests[] = {
test_sweep,
test_mark_no_sweep,
test_freeing_things,
test_reference_cycle,
test_interning,
};
const int num_tests = sizeof(tests) / sizeof(tests[0]);
int main() {
srand(time(NULL));
DBG("Begin Tinobsy test suite");
DBG("sizeof(object) = %zu, sizeof(vm) = %zu, sizeof(chunk) = %zu", sizeof(object), sizeof(vm), sizeof(chunk));
VM = new MyVM();
for (int i = 0; i < num_tests; i++) {
divider();
tests[i]();
}
divider();
DBG("end of tests. Total %zu fails", fails);
fprintf(stderr, "%zu tests failed\n", fails);
delete VM;
return 0;
}