OILS / mycpp / gc_builtins_test.cc View on Github | oilshell.org

386 lines, 245 significant
1#include "mycpp/gc_builtins.h"
2
3#include <assert.h>
4#include <limits.h> // INT_MAX
5#include <math.h> // INFINITY
6#include <stdarg.h> // va_list, etc.
7#include <stdio.h> // vprintf
8
9#include "mycpp/gc_dict.h"
10#include "mycpp/gc_list.h"
11#include "mycpp/gc_tuple.h"
12#include "vendor/greatest.h"
13
14GLOBAL_STR(kStrFood, "food");
15GLOBAL_STR(kWithNull, "foo\0bar");
16GLOBAL_STR(kSpace, " ");
17
18TEST print_test() {
19 print(kStrFood);
20 print(kWithNull); // truncates
21
22 PASS();
23}
24
25TEST repr_test() {
26 print(repr(StrFromC("")));
27 print(repr(StrFromC("hi\n")));
28
29 // Hm we're not printing \y00 here, could do that I suppose.
30 // This function is used for error messages.
31 print(repr(StrFromC("\x02 foo bar \xff \xfe \t")));
32
33 // Uses double quotes
34 print(repr(StrFromC("this isn't cool")));
35
36 PASS();
37}
38
39TEST bool_test() {
40 ASSERT_EQ(false, to_bool(kEmptyString));
41 ASSERT_EQ(true, to_bool(StrFromC("a")));
42
43 ASSERT_EQ(true, to_bool(42));
44 ASSERT_EQ(true, to_bool(1));
45 ASSERT_EQ(false, to_bool(0));
46 ASSERT_EQ(true, to_bool(-42));
47
48 PASS();
49}
50
51TEST int_test() {
52 ASSERT_EQ(1, to_int(true));
53 ASSERT_EQ(0, to_int(false));
54
55 PASS();
56}
57
58TEST float_test() {
59 ASSERT_EQ(0.0f, to_float(0));
60 ASSERT_EQ(1.0f, to_float(1));
61 ASSERT_EQ(42.0f, to_float(42));
62 ASSERT_EQ(-42.0f, to_float(-42));
63
64 ASSERT_EQ(0.0f, to_float(StrFromC("0.0")));
65
66 ASSERT_EQ(0.25f, to_float(StrFromC("0.25")));
67 ASSERT_EQ(0.5f, to_float(StrFromC("0.5")));
68 ASSERT_EQ(99.0f, to_float(StrFromC("99")));
69
70 ASSERT_EQ(-0.25f, to_float(StrFromC("-0.25")));
71 ASSERT_EQ(-0.5f, to_float(StrFromC("-0.5")));
72 ASSERT_EQ(-99.0f, to_float(StrFromC("-99")));
73
74 // Note: strtod supports hexadecimal and NaN
75
76 bool caught;
77
78 caught = false;
79 try {
80 (void)to_float(kEmptyString);
81 } catch (ValueError* e) {
82 caught = true;
83 }
84 ASSERT(caught);
85
86 caught = false;
87 try {
88 (void)to_float(StrFromC("x"));
89 } catch (ValueError* e) {
90 caught = true;
91 }
92 ASSERT(caught);
93
94 BigStr* huge = str_repeat(StrFromC("123456789"), 100);
95 double d = to_float(huge);
96 ASSERT_EQ(INFINITY, d);
97
98 double d2 = to_float(StrFromC("-1e309"));
99 ASSERT_EQ(-INFINITY, d2);
100
101 BigStr* zeros = str_repeat(StrFromC("00000000"), 100);
102 BigStr* tiny = str_concat3(StrFromC("0."), zeros, StrFromC("1"));
103 double d3 = to_float(tiny);
104 log("d3 = %.17g", d3);
105 ASSERT_EQ(0.0f, d3);
106
107 BigStr* neg_tiny = str_concat3(StrFromC("-0."), zeros, StrFromC("1"));
108 double d4 = to_float(neg_tiny);
109 log("d4 = %.17g", d4);
110 ASSERT_EQ(-0.0f, d4);
111
112 PASS();
113}
114
115// Wrapper for testing
116bool _StringToInt64(BigStr* s, int64_t* result, int base) {
117 return StringToInt64(s->data_, len(s), base, result);
118}
119
120TEST StringToInteger_test() {
121 int64_t i;
122 bool ok;
123
124 // Empirically this is 4 4 8 on 32-bit and 4 8 8 on 64-bit
125 // We want the bigger numbers
126#if 0
127 log("sizeof(int) = %d", sizeof(int));
128 log("sizeof(long) = %ld", sizeof(long));
129 log("sizeof(long long) = %ld", sizeof(long long));
130 log("");
131 log("LONG_MAX = %ld", LONG_MAX);
132 log("LLONG_MAX = %lld", LLONG_MAX);
133#endif
134
135 ok = _StringToInt64(StrFromC("345"), &i, 10);
136 ASSERT(ok);
137 ASSERT_EQ_FMT((int64_t)345, i, "%ld");
138
139 // Hack to test slicing. Truncated "345" at "34".
140 ok = _StringToInt64(StrFromC("345", 2), &i, 10);
141 ASSERT(ok);
142 ASSERT_EQ_FMT((int64_t)34, i, "%ld");
143
144 ok = _StringToInt64(StrFromC("12345678909"), &i, 10);
145 ASSERT(ok);
146 ASSERT_EQ_FMT((int64_t)12345678909, i, "%ld");
147
148 // overflow
149 ok = _StringToInt64(StrFromC("12345678901234567890"), &i, 10);
150 ASSERT(!ok);
151
152 // underflow
153 ok = _StringToInt64(StrFromC("-12345678901234567890"), &i, 10);
154 ASSERT(!ok);
155
156 // negative
157 ok = _StringToInt64(StrFromC("-123"), &i, 10);
158 ASSERT(ok);
159 ASSERT(i == -123);
160
161 // Leading space is OK!
162 ok = _StringToInt64(StrFromC("\n\t -123"), &i, 10);
163 ASSERT(ok);
164 ASSERT(i == -123);
165
166 // Trailing space is OK!
167 ok = _StringToInt64(StrFromC(" -123 \t\n"), &i, 10);
168 ASSERT(ok);
169 ASSERT(i == -123);
170
171 // \v is not space
172 ok = _StringToInt64(StrFromC(" -123 \v"), &i, 10);
173 ASSERT(!ok);
174
175 // Empty string isn't an integer
176 ok = _StringToInt64(StrFromC(""), &i, 10);
177 ASSERT(!ok);
178
179 ok = _StringToInt64(StrFromC("xx"), &i, 10);
180 ASSERT(!ok);
181
182 // Trailing garbage
183 ok = _StringToInt64(StrFromC("42a"), &i, 10);
184 ASSERT(!ok);
185
186 PASS();
187}
188
189TEST str_to_int_test() {
190 int i;
191
192 i = to_int(StrFromC("ff"), 16);
193 ASSERT(i == 255);
194
195 // strtol allows 0x prefix
196 i = to_int(StrFromC("0xff"), 16);
197 ASSERT(i == 255);
198
199 // TODO: test ValueError here
200 // i = to_int(StrFromC("0xz"), 16);
201
202 i = to_int(StrFromC("0"), 16);
203 ASSERT(i == 0);
204
205 i = to_int(StrFromC("077"), 8);
206 ASSERT_EQ_FMT(63, i, "%d");
207
208 bool caught = false;
209 try {
210 i = to_int(StrFromC("zzz"));
211 } catch (ValueError* e) {
212 caught = true;
213 }
214 ASSERT(caught);
215
216 PASS();
217}
218
219TEST int_to_str_test() {
220 BigStr* int_str;
221 int_str = str(INT_MAX);
222 ASSERT(str_equals0("2147483647", int_str));
223
224 int_str = str(-INT_MAX);
225 ASSERT(str_equals0("-2147483647", int_str));
226
227 int int_min = INT_MIN;
228 int_str = str(int_min);
229 ASSERT(str_equals0("-2147483648", int_str));
230
231 // Wraps with - sign. Is this well-defined behavior?
232 int_str = str(1 << 31);
233 log("i = %s", int_str->data_);
234
235 PASS();
236}
237
238TEST float_to_str_test() {
239 BigStr* s = str(3.0);
240 ASSERT(str_equals0("3.0", s));
241 log("s = %s", s->data_);
242
243 double f = 3.5;
244 s = str(f);
245 ASSERT(str_equals0("3.5", s));
246 log("s = %s", s->data_);
247
248 PASS();
249}
250
251TEST comparators_test() {
252 log("maybe_str_equals()");
253 ASSERT(maybe_str_equals(kEmptyString, kEmptyString));
254 ASSERT(!maybe_str_equals(kEmptyString, nullptr));
255 ASSERT(maybe_str_equals(nullptr, nullptr));
256
257 // TODO: check for this bug elsewhere
258 log("Tuple2<BigStr*, int> are_equal()");
259 auto t1 = Alloc<Tuple2<BigStr*, int>>(StrFromC("42"), 42);
260 auto t2 = Alloc<Tuple2<BigStr*, int>>(StrFromC("42"), 42);
261 auto t3 = Alloc<Tuple2<BigStr*, int>>(StrFromC("99"), 99);
262
263 ASSERT(are_equal(t1, t2));
264 ASSERT(!are_equal(t2, t3));
265
266 PASS();
267}
268
269TEST exceptions_test() {
270 auto v1 = Alloc<ValueError>();
271 ASSERT_EQ(HeapTag::FixedSize, ObjHeader::FromObject(v1)->heap_tag);
272
273 auto v2 = Alloc<ValueError>(kEmptyString);
274 ASSERT_EQ(HeapTag::FixedSize, ObjHeader::FromObject(v2)->heap_tag);
275
276 IndexError* other;
277 bool caught = false;
278 try {
279 throw Alloc<IndexError>();
280 } catch (IndexError* e) {
281 log("e %p", e);
282 other = e;
283 caught = true;
284 }
285
286 log("other %p", other);
287 ASSERT(caught);
288
289 caught = false;
290 try {
291 throw Alloc<OSError>(99);
292 } catch (IOError_OSError* e) {
293 caught = true;
294 }
295 ASSERT(caught);
296
297 // TODO: Make this work with return value rooting
298 RuntimeError* r = nullptr;
299 BigStr* message = nullptr;
300 StackRoots _roots2({&r, &message});
301 message = StrFromC("libc::regex_match");
302
303 caught = false;
304 try {
305 r = Alloc<RuntimeError>(message);
306 throw r;
307
308 } catch (RuntimeError* e) {
309 caught = true;
310
311 log("RuntimeError %s", e->message->data());
312 }
313 ASSERT(caught);
314
315 auto u = Alloc<UnicodeError>(StrFromC("libc"));
316 (void)u;
317
318 auto i = Alloc<IOError>(0);
319 (void)i;
320
321 PASS();
322}
323
324TEST hash_str_test() {
325 // two strings known not to collide ahead of time
326 BigStr* a = StrFromC("foobarbaz");
327 BigStr* b = StrFromC("123456789");
328 ASSERT(hash(a) != hash(b));
329
330 PASS();
331}
332
333TEST intern_test() {
334 BigStr* s = StrFromC("foo");
335 BigStr* t = intern(s);
336
337 ASSERT(str_equals(s, t));
338
339 PASS();
340}
341
342TEST max_test() {
343 ASSERT(max(-1, 0) == 0);
344 ASSERT(max(0, -1) == max(-1, 0));
345 ASSERT(max(42, 13) == 42);
346
347 auto* ints = NewList<int>(std::initializer_list<int>{13, 0, 42, -1});
348 ASSERT(max(ints) == 42);
349
350 PASS();
351}
352
353GREATEST_MAIN_DEFS();
354
355int main(int argc, char** argv) {
356 gHeap.Init();
357
358 GREATEST_MAIN_BEGIN();
359
360 RUN_TEST(print_test);
361 RUN_TEST(repr_test);
362
363 RUN_TEST(bool_test);
364 RUN_TEST(int_test);
365 RUN_TEST(float_test);
366
367 RUN_TEST(StringToInteger_test);
368 RUN_TEST(str_to_int_test);
369 RUN_TEST(int_to_str_test);
370 RUN_TEST(float_to_str_test);
371
372 RUN_TEST(comparators_test);
373
374 RUN_TEST(exceptions_test);
375
376 RUN_TEST(hash_str_test);
377 RUN_TEST(intern_test);
378
379 RUN_TEST(max_test);
380
381 gHeap.CleanProcessExit();
382
383 GREATEST_MAIN_END(); /* display results */
384
385 return 0;
386}