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

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