1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2 /* vi: set expandtab shiftwidth=4 tabstop=4: */
3 
4 #include "modp_numtoa.h"
5 #include <stdio.h>
6 #include <limits.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include "minunit.h"
10 
11 /* Need only for INFINITY and optionally NAN macros */
12 /* We do not link with -lm */
13 #include <math.h>
14 
testITOA()15 static char* testITOA()
16 {
17     char buf1[100];
18     char buf2[100];
19     int i;
20     for (i = 0; i < 100000; ++i) {
21         sprintf(buf1, "%d", i);
22         modp_itoa10(i, buf2);
23         mu_assert_str_equals(buf1, buf2);
24 
25         sprintf(buf1, "%d", -i);
26         modp_itoa10(-i, buf2);
27         mu_assert_str_equals(buf1, buf2);
28 
29         sprintf(buf1, "%d", INT_MAX - i);
30         modp_itoa10(INT_MAX - i, buf2);
31         mu_assert_str_equals(buf1, buf2);
32 
33         sprintf(buf1, "%d", -(INT_MAX - i));
34         modp_itoa10(-(INT_MAX - i), buf2);
35         mu_assert_str_equals(buf1, buf2);
36     }
37     return 0;
38 }
39 
testUITOA()40 static char* testUITOA()
41 {
42     char buf1[100];
43     char buf2[100];
44     uint32_t i;
45     for (i = 0; i < 1000000; ++i) {
46         sprintf(buf1, "%u", i);
47         modp_uitoa10(i, buf2);
48         mu_assert_str_equals(buf1, buf2);
49     }
50 
51     for (i = 0; i < 1000000; ++i) {
52         sprintf(buf1, "%u", 0xFFFFFFFFu - i);
53         modp_uitoa10(0xFFFFFFFFu -i, buf2);
54         mu_assert_str_equals(buf1, buf2);
55     }
56     return 0;
57 }
58 
testLITOA()59 static char* testLITOA()
60 {
61     char buf1[100];
62     char buf2[100];
63     long int i;
64     for (i = 0; i < 100000; ++i) {
65         sprintf(buf1, "%ld", i);
66         modp_litoa10(i, buf2);
67         mu_assert_str_equals(buf1, buf2);
68 
69         sprintf(buf1, "%ld", -i);
70         modp_litoa10(-i, buf2);
71         mu_assert_str_equals(buf1, buf2);
72 
73         sprintf(buf1, "%ld", LONG_MAX - i);
74         modp_litoa10(LONG_MAX - i, buf2);
75         mu_assert_str_equals(buf1, buf2);
76 
77         sprintf(buf1, "%ld", -(LONG_MAX - i));
78         modp_litoa10(-(LONG_MAX - i), buf2);
79         mu_assert_str_equals(buf1, buf2);
80     }
81     return 0;
82 }
83 
testULITOA()84 static char* testULITOA()
85 {
86     char buf1[100];
87     char buf2[100];
88     long long unsigned int i;
89     for (i = 0; i < 1000000; ++i) {
90         sprintf(buf1, "%llu", i);
91         modp_ulitoa10(i, buf2);
92         mu_assert_str_equals(buf1, buf2);
93     }
94 
95     for (i = 0; i < 1000000; ++i) {
96         sprintf(buf1, "%llu", 0xFFFFFFFFFFFFFFFFllu - i);
97         modp_ulitoa10(0xFFFFFFFFFFFFFFFFull -i, buf2);
98         mu_assert_str_equals(buf1, buf2);
99     }
100     return 0;
101 }
102 
testDoubleToA()103 static char* testDoubleToA()
104 {
105     char buf1[100];
106     char buf2[100];
107     char msg[200];
108     double d;
109 
110     /* test each combination of whole number + fraction,
111        at every precision */
112     /* and test negative version */
113     double wholes[] = {0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,
114                        67.0,101.0, 10000, 99999};
115     double frac[] = {0.0, 0.1, 0.2, 0.3, 0.4, 0.49, 0.5, 0.51, 0.6, 0.7,
116                      0.9, 0.01, 0.25, 0.125, 0.05, 0.005, 0.0005, 0.00005,
117                      0.001, 0.00001, 0.99, 0.999, 0.9999};
118     const char* formats[] = {"%.0f", "%.1f", "%.2f", "%.3f", "%.4f", "%.5f",
119                              "%.6f", "%.7f", "%.8f", "%.9f"};
120 
121     int imax = sizeof(wholes)/sizeof(double);
122     int jmax = sizeof(frac)/sizeof(double);
123     int kmax = sizeof(formats)/sizeof(const char*);
124 
125     int i,j,k;
126     for (i = 0; i < imax; ++i) {
127         for (j = 0; j < jmax; ++j) {
128             for (k = 0; k < kmax; ++k) {
129                 d = wholes[i] + frac[j];
130 
131                 sprintf(msg, "whole=%f, frac=%f, prec=%d -- ",
132                         wholes[i], frac[j], k);
133                 sprintf(buf1, formats[k], d);
134                 modp_dtoa(d, buf2, k);
135                 mu_assert_str_equals_msg(msg,buf1, buf2);
136 
137                 if (d != 0) {
138                     sprintf(msg, "whole=%f, frac=%f, prec=%d -- ",
139                             -wholes[i], frac[j], k);
140                     /* not dealing with "-0" issues */
141                     d = -d;
142                     sprintf(buf1, formats[k], d);
143                     modp_dtoa(d, buf2, k);
144                     mu_assert_str_equals_msg(msg,buf1, buf2);
145                 }
146 
147             }
148         }
149     }
150 
151     /* test very large positive number */
152     d = 1.0e200;
153     modp_dtoa(d, buf2, 6);
154     mu_assert_str_equals("1.000000e+200", buf2);
155 
156     /* test very large negative number */
157     d = -1.0e200;
158     modp_dtoa(d, buf2, 6);
159     mu_assert_str_equals("-1.000000e+200", buf2);
160 
161     /* test very small positive number */
162     d = 1e-10;
163     sprintf(buf1, "%.6f", d);
164     modp_dtoa(d, buf2, 6);
165     mu_assert_str_equals(buf1, buf2);
166 
167     /* test very small negative number */
168     d = -1e-10;
169     sprintf(buf1, "%.6f", d);
170     modp_dtoa(d, buf2, 6);
171     mu_assert_str_equals(buf1, buf2);
172 
173     return 0;
174 }
175 
176 // Helper function
177 //  Removes trailing zeros
178 // this is horible but it's just for testing.
stripTrailingZeros(char * buf)179 static void stripTrailingZeros(char* buf)
180 {
181     size_t i;
182     int hasdot = 0;
183     for (i = 0; i < strlen(buf); ++i) {
184         if (buf[i] == '.') {
185             hasdot = 1;
186             break;
187         }
188     }
189 
190     // it's just an integer
191     if (!hasdot) {
192         return;
193     }
194 
195     i = strlen(buf);
196     if (i == 0) {
197         return;
198     }
199     --i;
200 
201     while (i > 0 && (buf[i] == '0' || buf[i] == '.')) {
202         if (buf[i] == '.') {
203             buf[i] = '\0';
204             break;
205         } else {
206             buf[i] = '\0';
207             --i;
208         }
209     }
210 }
211 
testDoubleToA2()212 static char* testDoubleToA2()
213 {
214     char buf1[100];
215     char buf2[100];
216     char msg[200];
217     double d;
218 
219     /* test each combination of whole number + fraction,
220        at every precision */
221     /* and test negative version */
222     double wholes[] = {0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,
223                        67.0,101.0, 10000, 99999};
224     double frac[] = {0.0, 0.1, 0.2, 0.3, 0.4, 0.49, 0.5, 0.51, 0.6, 0.7,
225                      0.9, 0.01, 0.25, 0.125, 0.05, 0.005, 0.0005, 0.00005,
226                      0.001, 0.00001, 0.99, 0.999, 0.9999};
227     const char* formats[] = {"%.0f", "%.1f", "%.2f", "%.3f", "%.4f", "%.5f",
228                              "%.6f", "%.7f", "%.8f", "%.9f"};
229 
230     int imax = sizeof(wholes)/sizeof(double);
231     int jmax = sizeof(frac)/sizeof(double);
232     int kmax = sizeof(formats)/sizeof(const char*);
233 
234     int i,j,k;
235     for (i = 0; i < imax; ++i) {
236         for (j = 0; j < jmax; ++j) {
237             for (k = 0; k < kmax; ++k) {
238                 d = wholes[i] + frac[j];
239 
240                 sprintf(msg, "whole=%f, frac=%f, prec=%d -- ",
241                         wholes[i], frac[j], k);
242 
243                 sprintf(buf1, formats[k], d);
244                 stripTrailingZeros(buf1);
245                 modp_dtoa2(d, buf2, k);
246                 mu_assert_str_equals_msg(msg,buf1, buf2);
247 
248                 if (d != 0) {
249                     sprintf(msg, "whole=%f, frac=%f, prec=%d -- ",
250                             -wholes[i], frac[j], k);
251                     /* not dealing with "-0" issues */
252                     d = -d;
253                     sprintf(buf1, formats[k], d);
254                     stripTrailingZeros(buf1);
255 
256                     modp_dtoa2(d, buf2, k);
257                     mu_assert_str_equals_msg(msg,buf1, buf2);
258                 }
259 
260             }
261         }
262     }
263 
264     /* test very large positive number */
265     d = 1.0e200;
266     modp_dtoa2(d, buf2, 6);
267     mu_assert_str_equals("1.000000e+200", buf2);
268 
269     /* test very large negative number */
270     d = -1.0e200;
271     modp_dtoa2(d, buf2, 6);
272     mu_assert_str_equals("-1.000000e+200", buf2);
273 
274     /* test very small positive number */
275     d = 1e-10;
276     sprintf(buf1, "%.6f", d);
277     stripTrailingZeros(buf1);
278 
279     modp_dtoa2(d, buf2, 6);
280     mu_assert_str_equals(buf1, buf2);
281 
282     /* test very small negative number */
283     d = -1e-10;
284     sprintf(buf1, "%.6f", d);
285     stripTrailingZeros(buf1);
286 
287     modp_dtoa2(d, buf2, 6);
288     mu_assert_str_equals(buf1, buf2);
289 
290     // test bad precision values
291     d = 1.1;
292     modp_dtoa(d, buf2, -1);
293     mu_assert_str_equals("1", buf2);
294     modp_dtoa2(d, buf2, 10);
295     mu_assert_str_equals("1.1", buf2);
296     return 0;
297 }
298 
299 /* From Issue 7  -- http://code.google.com/p/stringencoders/issues/detail?id=7
300  * thanks to http://code.google.com/u/simhasana/
301  */
testOverflowLITOA()302 static char* testOverflowLITOA() {
303     char buf1[100];
304     char buf2[100];
305 
306     long long int longmin = LONG_MIN;
307     sprintf(buf1, "%lld", longmin);
308     modp_litoa10(longmin, buf2);
309     mu_assert_str_equals(buf1, buf2);
310 
311     long long int longmax = LONG_MAX;
312     sprintf(buf1, "%lld", longmax);
313     modp_litoa10(longmax, buf2);
314     mu_assert_str_equals(buf1, buf2);
315 
316     return 0;
317 }
318 
testOverflowITOA()319 static char* testOverflowITOA() {
320     char buf1[100];
321     char buf2[100];
322 
323     int32_t intmin = INT_MIN;
324     sprintf(buf1, "%d", intmin);
325     modp_itoa10(intmin, buf2);
326     mu_assert_str_equals(buf1, buf2);
327 
328     int32_t intmax = INT_MAX;
329     sprintf(buf1, "%d", intmax);
330     modp_itoa10(intmax, buf2);
331     mu_assert_str_equals(buf1, buf2);
332 
333     return 0;
334 }
335 
336 // Test NaN and Infinity behavior
testDTOANonFinite()337 static char* testDTOANonFinite() {
338     char buf1[100];
339     char buf2[100];
340     double d;
341 
342     // down below are some IFDEFs that may or may not exist.
343     // depending on compiler settings "buf1" might not be used
344     // and halt compilation.  The next line touches buf1 so this
345     // doesn't happen
346     (void)buf1;
347 
348     /* Test for inf */
349     d = 1e200 * 1e200;
350     // NOTE!!! next line will core dump!
351     //sprintf(buf1, "%.6f", d);
352     buf2[0] = '\0';
353     modp_dtoa2(d, buf2, 6);
354     mu_assert_str_equals("inf", buf2);
355 
356     /* INFINITY should be standard. Defined in <math.h> */
357     /* http://www.gnu.org/s/libc/manual/html_node/Infinity-and-NaN.html */
358 #ifdef INFINITY
359     d = INFINITY;
360 
361     // test libc support
362     sprintf(buf1, "%f", d);
363     mu_assert_str_equals("inf", buf1);
364 
365     buf2[0] = '\0';
366     modp_dtoa(d, buf2, 6);
367     mu_assert_str_equals("inf", buf2);
368 
369     buf2[0] = '\0';
370     modp_dtoa2(d, buf2, 6);
371     mu_assert_str_equals("inf", buf2);
372 #endif
373 
374     /* NAN is a GNU extension, defined in <math.h> */
375     /* http://www.gnu.org/s/libc/manual/html_node/Infinity-and-NaN.html */
376 #ifdef NAN
377     d = NAN;
378 
379     // test libc support
380     sprintf(buf1, "%f", d);
381     mu_assert_str_equals("nan", buf1);
382 
383     // now test ours
384     buf2[0] = '\0';
385     modp_dtoa(d, buf2, 6);
386     mu_assert_str_equals("nan", buf2);
387     buf2[0] = '\0';
388     modp_dtoa2(d, buf2, 6);
389     mu_assert_str_equals("nan", buf2);
390 #endif
391 
392     return 0;
393 
394 }
395 
all_tests()396 static char* all_tests() {
397     mu_run_test(testITOA);
398     mu_run_test(testUITOA);
399     mu_run_test(testLITOA);
400     mu_run_test(testULITOA);
401     mu_run_test(testDoubleToA);
402     mu_run_test(testDoubleToA2);
403     mu_run_test(testOverflowLITOA);
404     mu_run_test(testOverflowITOA);
405     mu_run_test(testDTOANonFinite);
406     return 0;
407 }
408 
409 UNITTESTS
410