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