1 | #include "mycpp/gc_mylib.h"
|
2 |
|
3 | #include <unistd.h>
|
4 |
|
5 | #include "mycpp/gc_alloc.h" // gHeap
|
6 | #include "mycpp/gc_str.h"
|
7 | #include "vendor/greatest.h"
|
8 |
|
9 | TEST split_once_test() {
|
10 | log("split_once()");
|
11 |
|
12 | BigStr* s = nullptr;
|
13 | BigStr* delim = nullptr;
|
14 | StackRoots _roots1({&s, &delim});
|
15 |
|
16 | s = StrFromC("foo=bar");
|
17 | delim = StrFromC("=");
|
18 | Tuple2<BigStr*, BigStr*> t = mylib::split_once(s, delim);
|
19 |
|
20 | auto t0 = t.at0();
|
21 | auto t1 = t.at1();
|
22 |
|
23 | log("t %p %p", t0, t1);
|
24 |
|
25 | BigStr* foo = nullptr;
|
26 | StackRoots _roots2({&t0, &t1, &foo});
|
27 | foo = StrFromC("foo");
|
28 |
|
29 | // TODO: We lack rooting in the cases below!
|
30 | PASS();
|
31 |
|
32 | Tuple2<BigStr*, BigStr*> u =
|
33 | mylib::split_once(StrFromC("foo="), StrFromC("="));
|
34 | ASSERT(str_equals(u.at0(), StrFromC("foo")));
|
35 | ASSERT(str_equals(u.at1(), StrFromC("")));
|
36 |
|
37 | Tuple2<BigStr*, BigStr*> v =
|
38 | mylib::split_once(StrFromC("foo="), StrFromC("Z"));
|
39 | ASSERT(str_equals(v.at0(), StrFromC("foo=")));
|
40 | ASSERT(v.at1() == nullptr);
|
41 |
|
42 | Tuple2<BigStr*, BigStr*> w = mylib::split_once(StrFromC(""), StrFromC("Z"));
|
43 | ASSERT(str_equals(w.at0(), StrFromC("")));
|
44 | ASSERT(w.at1() == nullptr);
|
45 |
|
46 | PASS();
|
47 | }
|
48 |
|
49 | TEST int_to_str_test() {
|
50 | int int_min = INT_MIN;
|
51 | BigStr* int_str;
|
52 |
|
53 | int_str = mylib::hex_lower(15);
|
54 | ASSERT(str_equals0("f", int_str));
|
55 | print(int_str);
|
56 | print(mylib::hex_lower(int_min));
|
57 |
|
58 | int_str = mylib::hex_upper(15);
|
59 | ASSERT(str_equals0("F", int_str));
|
60 | print(mylib::hex_upper(int_min));
|
61 |
|
62 | int_str = mylib::octal(15);
|
63 | ASSERT(str_equals0("17", int_str));
|
64 | print(mylib::octal(int_min));
|
65 |
|
66 | PASS();
|
67 | }
|
68 |
|
69 | TEST funcs_test() {
|
70 | BigStr* int_str = nullptr;
|
71 |
|
72 | StackRoots _roots({&int_str});
|
73 |
|
74 | BigStr* fooEqualsBar = nullptr;
|
75 | BigStr* foo = nullptr;
|
76 | BigStr* bar = nullptr;
|
77 | BigStr* fooEquals = nullptr;
|
78 |
|
79 | BigStr* equals = nullptr;
|
80 | BigStr* Z = nullptr;
|
81 | BigStr* emptyStr = nullptr;
|
82 |
|
83 | StackRoots _roots2(
|
84 | {&fooEqualsBar, &foo, &bar, &fooEquals, &equals, &Z, &emptyStr});
|
85 |
|
86 | fooEqualsBar = StrFromC("foo=bar");
|
87 | foo = StrFromC("foo");
|
88 | bar = StrFromC("bar");
|
89 | fooEquals = StrFromC("foo=");
|
90 |
|
91 | equals = StrFromC("=");
|
92 | Z = StrFromC("Z");
|
93 | emptyStr = StrFromC("");
|
94 |
|
95 | log("split_once()");
|
96 | Tuple2<BigStr*, BigStr*> t = mylib::split_once(fooEqualsBar, equals);
|
97 | ASSERT(str_equals(t.at0(), foo));
|
98 | ASSERT(str_equals(t.at1(), bar));
|
99 |
|
100 | Tuple2<BigStr*, BigStr*> u = mylib::split_once(fooEquals, equals);
|
101 | ASSERT(str_equals(u.at0(), foo));
|
102 | ASSERT(str_equals(u.at1(), emptyStr));
|
103 |
|
104 | Tuple2<BigStr*, BigStr*> v = mylib::split_once(fooEquals, Z);
|
105 | ASSERT(str_equals(v.at0(), fooEquals));
|
106 | ASSERT(v.at1() == nullptr);
|
107 |
|
108 | Tuple2<BigStr*, BigStr*> w = mylib::split_once(emptyStr, Z);
|
109 | ASSERT(str_equals(w.at0(), emptyStr));
|
110 | ASSERT(w.at1() == nullptr);
|
111 |
|
112 | PASS();
|
113 | }
|
114 |
|
115 | #if 0
|
116 | TEST writeln_test() {
|
117 | mylib::writeln(StrFromC("stdout"));
|
118 | mylib::writeln(StrFromC("stderr"), mylib::kStderr);
|
119 |
|
120 | PASS();
|
121 | }
|
122 | #endif
|
123 |
|
124 | TEST BufWriter_test() {
|
125 | mylib::BufWriter* writer = nullptr;
|
126 | BigStr* s = nullptr;
|
127 | BigStr* foo = nullptr;
|
128 | BigStr* bar = nullptr;
|
129 | StackRoots _roots({&writer, &s, &foo, &bar});
|
130 |
|
131 | foo = StrFromC("foo");
|
132 | bar = StrFromC("bar");
|
133 |
|
134 | writer = Alloc<mylib::BufWriter>();
|
135 | s = writer->getvalue();
|
136 | ASSERT_EQ(kEmptyString, s);
|
137 |
|
138 | // Create a new BufWriter to call getvalue() again
|
139 | writer = Alloc<mylib::BufWriter>();
|
140 | writer->write(foo);
|
141 | s = writer->getvalue();
|
142 | ASSERT(str_equals0("foo", s));
|
143 |
|
144 | // Create a new BufWriter to call getvalue() again
|
145 | writer = Alloc<mylib::BufWriter>();
|
146 | writer->write(foo);
|
147 | writer->write_spaces(3);
|
148 | writer->write_spaces(0);
|
149 | writer->write(bar);
|
150 |
|
151 | s = writer->getvalue();
|
152 | ASSERT(str_equals0("foo bar", s));
|
153 | log("result = %s", s->data());
|
154 |
|
155 | writer->clear();
|
156 | writer->write(bar);
|
157 | s = writer->getvalue();
|
158 | ASSERT(str_equals0("bar", s));
|
159 |
|
160 | PASS();
|
161 | }
|
162 |
|
163 | using mylib::BufLineReader;
|
164 |
|
165 | TEST BufLineReader_test() {
|
166 | BigStr* s = StrFromC("foo\nbar\nleftover");
|
167 | auto reader = Alloc<BufLineReader>(s);
|
168 |
|
169 | ASSERT_EQ(false, reader->isatty());
|
170 |
|
171 | log("BufLineReader");
|
172 |
|
173 | BigStr* line = nullptr;
|
174 | line = reader->readline();
|
175 | log("1 [%s]", line->data_);
|
176 | ASSERT(str_equals0("foo\n", line));
|
177 |
|
178 | line = reader->readline();
|
179 | log("2 [%s]", line->data_);
|
180 | ASSERT(str_equals0("bar\n", line));
|
181 |
|
182 | line = reader->readline();
|
183 | log("3 [%s]", line->data_);
|
184 | ASSERT(str_equals0("leftover", line));
|
185 |
|
186 | line = reader->readline();
|
187 | log("4 [%s]", line->data_);
|
188 | ASSERT(str_equals0("", line));
|
189 |
|
190 | // Optimization we want
|
191 | ASSERT_EQ(kEmptyString, line);
|
192 |
|
193 | // Read again
|
194 | line = reader->readline();
|
195 | log("5 [%s]", line->data_);
|
196 | // Optimization we want
|
197 | ASSERT_EQ(kEmptyString, line);
|
198 |
|
199 | reader->close();
|
200 |
|
201 | //
|
202 | // Empty
|
203 | //
|
204 |
|
205 | reader = Alloc<BufLineReader>(kEmptyString);
|
206 | line = reader->readline();
|
207 | ASSERT_EQ(kEmptyString, line);
|
208 |
|
209 | BigStr* one_line = StrFromC("one line");
|
210 | reader = Alloc<BufLineReader>(one_line);
|
211 | line = reader->readline();
|
212 | ASSERT(str_equals(one_line, line));
|
213 |
|
214 | // Optimization: pointers should be equal too!
|
215 | ASSERT_EQ(one_line, line);
|
216 |
|
217 | line = reader->readline();
|
218 | ASSERT_EQ(kEmptyString, line);
|
219 |
|
220 | PASS();
|
221 | }
|
222 |
|
223 | TEST files_test() {
|
224 | mylib::Writer* stdout_ = mylib::Stdout();
|
225 | log("stdout isatty() = %d", stdout_->isatty());
|
226 |
|
227 | mylib::LineReader* stdin_ = mylib::Stdin();
|
228 | log("stdin isatty() = %d", stdin_->isatty());
|
229 |
|
230 | FILE* f = fopen("README.md", "r");
|
231 |
|
232 | mylib::CFile* r = nullptr;
|
233 | BigStr* filename = nullptr;
|
234 | BigStr* filename2 = nullptr;
|
235 | StackRoots _roots({&r, &filename, &filename2});
|
236 |
|
237 | r = Alloc<mylib::CFile>(f);
|
238 | filename = StrFromC("README.md");
|
239 | filename2 = StrFromC("README.md ");
|
240 | // auto r = mylib::Stdin();
|
241 |
|
242 | log("files_test");
|
243 | int i = 0;
|
244 | while (true) {
|
245 | BigStr* s = r->readline();
|
246 | if (len(s) == 0) {
|
247 | break;
|
248 | }
|
249 | if (i < 5) {
|
250 | mylib::print_stderr(s);
|
251 | }
|
252 | ++i;
|
253 | }
|
254 | r->close();
|
255 | log("files_test DONE");
|
256 |
|
257 | auto f2 = mylib::open(filename);
|
258 | ASSERT(f2 != nullptr);
|
259 |
|
260 | // See if we can strip a space and still open it. Underlying fopen() call
|
261 | // works.
|
262 | auto f3 = mylib::open(filename2->strip());
|
263 | ASSERT(f3 != nullptr);
|
264 |
|
265 | auto w = Alloc<mylib::CFile>(stdout);
|
266 | w->write(StrFromC("stdout"));
|
267 | w->flush();
|
268 |
|
269 | PASS();
|
270 | }
|
271 |
|
272 | TEST for_test_coverage() {
|
273 | mylib::MaybeCollect(); // trivial wrapper for translation
|
274 |
|
275 | auto writer = mylib::Stderr();
|
276 | writer->write(kEmptyString);
|
277 |
|
278 | // Methods we're not really using? Refactoring types could eliminate these
|
279 | auto w = Alloc<mylib::BufWriter>();
|
280 | ASSERT_EQ(false, w->isatty());
|
281 | w->flush();
|
282 |
|
283 | // Initializes the heap
|
284 | mylib::InitCppOnly();
|
285 |
|
286 | PASS();
|
287 | }
|
288 |
|
289 | TEST getc_demo() {
|
290 | // CPython fileobject.c appears to use getc? Is it buffered?
|
291 | // Oh yeah I see a syscall read(0, "hi123")
|
292 | // OK maybe I should just use getc instead of getline()?
|
293 | // getline() has different buffering perhaps?
|
294 |
|
295 | int fd[2];
|
296 | ::pipe(fd);
|
297 |
|
298 | ::dup2(fd[0], 0);
|
299 |
|
300 | write(fd[1], "hi", 3);
|
301 |
|
302 | int c = getc(stdin);
|
303 | log("c = %c", c);
|
304 |
|
305 | c = getc(stdin);
|
306 | log("c = %c", c);
|
307 |
|
308 | PASS();
|
309 | }
|
310 |
|
311 | GREATEST_MAIN_DEFS();
|
312 |
|
313 | int main(int argc, char** argv) {
|
314 | gHeap.Init();
|
315 |
|
316 | GREATEST_MAIN_BEGIN();
|
317 |
|
318 | RUN_TEST(split_once_test);
|
319 | RUN_TEST(int_to_str_test);
|
320 | RUN_TEST(funcs_test);
|
321 |
|
322 | // RUN_TEST(writeln_test);
|
323 | RUN_TEST(BufWriter_test);
|
324 | RUN_TEST(BufLineReader_test);
|
325 | RUN_TEST(files_test);
|
326 | RUN_TEST(for_test_coverage);
|
327 |
|
328 | RUN_TEST(getc_demo);
|
329 |
|
330 | gHeap.CleanProcessExit();
|
331 |
|
332 | GREATEST_MAIN_END(); /* display results */
|
333 |
|
334 | return 0;
|
335 | }
|