Initial import.
[profile/ivi/apr.git] / test / teststr.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "testutil.h"
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22
23 #if APR_HAVE_LIMITS_H
24 #include <limits.h>
25 #endif
26
27 #include "apr_general.h"
28 #include "apr_strings.h"
29 #include "apr_errno.h"
30
31 /* I haven't bothered to check for APR_ENOTIMPL here, AFAIK, all string
32  * functions exist on all platforms.
33  */
34
35 static void test_strtok(abts_case *tc, void *data)
36 {
37     struct {
38         char *input;
39         char *sep;
40     }
41     cases[] = {
42         {
43             "",
44             "Z"
45         },
46         {
47             "      asdf jkl; 77889909            \r\n\1\2\3Z",
48             " \r\n\3\2\1"
49         },
50         {
51             NULL,  /* but who cares if apr_strtok() segfaults? */
52             " \t"
53         },
54 #if 0     /* don't do this... you deserve to segfault */
55         {
56             "a b c              ",
57             NULL
58         },
59 #endif
60         {
61             "   a       b        c   ",
62             ""
63         },
64         {
65             "a              b c         ",
66             " "
67         }
68     };
69     int curtc;
70
71     for (curtc = 0; curtc < sizeof cases / sizeof cases[0]; curtc++) {
72         char *retval1, *retval2;
73         char *str1, *str2;
74         char *state;
75
76         str1 = apr_pstrdup(p, cases[curtc].input);
77         str2 = apr_pstrdup(p, cases[curtc].input);
78
79         do {
80             retval1 = apr_strtok(str1, cases[curtc].sep, &state);
81             retval2 = strtok(str2, cases[curtc].sep);
82
83             if (!retval1) {
84                 ABTS_TRUE(tc, retval2 == NULL);
85             }
86             else {
87                 ABTS_TRUE(tc, retval2 != NULL);
88                 ABTS_STR_EQUAL(tc, retval2, retval1);
89             }
90
91             str1 = str2 = NULL; /* make sure we pass NULL on subsequent calls */
92         } while (retval1);
93     }
94 }
95
96 static void snprintf_noNULL(abts_case *tc, void *data)
97 {
98     char buff[100];
99     char *testing = apr_palloc(p, 10);
100
101     testing[0] = 't';
102     testing[1] = 'e';
103     testing[2] = 's';
104     testing[3] = 't';
105     testing[4] = 'i';
106     testing[5] = 'n';
107     testing[6] = 'g';
108     
109     /* If this test fails, we are going to seg fault. */
110     apr_snprintf(buff, sizeof(buff), "%.*s", 7, testing);
111     ABTS_STR_NEQUAL(tc, buff, testing, 7);
112 }
113
114 static void snprintf_0NULL(abts_case *tc, void *data)
115 {
116     int rv;
117
118     rv = apr_snprintf(NULL, 0, "%sBAR", "FOO");
119     ABTS_INT_EQUAL(tc, 6, rv);
120 }
121
122 static void snprintf_0nonNULL(abts_case *tc, void *data)
123 {
124     int rv;
125     char *buff = "testing";
126
127     rv = apr_snprintf(buff, 0, "%sBAR", "FOO");
128     ABTS_INT_EQUAL(tc, 6, rv);
129     ABTS_ASSERT(tc, "buff unmangled", strcmp(buff, "FOOBAR") != 0);
130 }
131
132 static void snprintf_underflow(abts_case *tc, void *data)
133 {
134     char buf[20];
135     int rv;
136
137     rv = apr_snprintf(buf, sizeof buf, "%.2f", (double)0.0001);
138     ABTS_INT_EQUAL(tc, 4, rv);
139     ABTS_STR_EQUAL(tc, "0.00", buf);
140     
141     rv = apr_snprintf(buf, sizeof buf, "%.2f", (double)0.001);
142     ABTS_INT_EQUAL(tc, 4, rv);
143     ABTS_STR_EQUAL(tc, "0.00", buf);
144     
145     rv = apr_snprintf(buf, sizeof buf, "%.2f", (double)0.01);
146     ABTS_INT_EQUAL(tc, 4, rv);
147     ABTS_STR_EQUAL(tc, "0.01", buf);
148 }
149
150 static void string_error(abts_case *tc, void *data)
151 {
152      char buf[128], *rv;
153      apr_status_t n;
154
155      buf[0] = '\0';
156      rv = apr_strerror(APR_ENOENT, buf, sizeof buf);
157      ABTS_PTR_EQUAL(tc, buf, rv);
158      ABTS_TRUE(tc, strlen(buf) > 0);
159
160      rv = apr_strerror(APR_TIMEUP, buf, sizeof buf);
161      ABTS_PTR_EQUAL(tc, buf, rv);
162      ABTS_STR_EQUAL(tc, "The timeout specified has expired", buf);
163      
164      /* throw some randomish numbers at it to check for robustness */
165      for (n = 1; n < 1000000; n *= 2) {
166          apr_strerror(n, buf, sizeof buf);
167      }
168 }
169
170 #define SIZE 180000
171 static void string_long(abts_case *tc, void *data)
172 {
173     char s[SIZE + 1];
174
175     memset(s, 'A', SIZE);
176     s[SIZE] = '\0';
177
178     apr_psprintf(p, "%s", s);
179 }
180
181 /* ### FIXME: apr.h/apr_strings.h should provide these! */
182 #define MY_LLONG_MAX (APR_INT64_C(9223372036854775807))
183 #define MY_LLONG_MIN (-MY_LLONG_MAX - APR_INT64_C(1))
184
185 static void string_strtoi64(abts_case *tc, void *data)
186 {
187     static const struct {
188         int errnum, base;
189         const char *in, *end;
190         apr_int64_t result;
191     } ts[] = {
192         
193         /* base 10 tests */
194         { 0, 10, "123545", NULL, APR_INT64_C(123545) },
195         { 0, 10, "   123545", NULL, APR_INT64_C(123545) },
196         { 0, 10, "   +123545", NULL, APR_INT64_C(123545) },
197         { 0, 10, "-123545", NULL, APR_INT64_C(-123545) },
198         { 0, 10, "   00000123545", NULL, APR_INT64_C(123545) },
199         { 0, 10, "123545ZZZ", "ZZZ", APR_INT64_C(123545) },
200         { 0, 10, "   123545   ", "   ", APR_INT64_C(123545) },
201
202         /* base 16 tests */
203         { 0, 16, "1E299", NULL, APR_INT64_C(123545) },
204         { 0, 16, "1e299", NULL, APR_INT64_C(123545) },
205         { 0, 16, "0x1e299", NULL, APR_INT64_C(123545) },
206         { 0, 16, "0X1E299", NULL, APR_INT64_C(123545) },
207         { 0, 16, "+1e299", NULL, APR_INT64_C(123545) },
208         { 0, 16, "-1e299", NULL, APR_INT64_C(-123545) },
209         { 0, 16, "   -1e299", NULL, APR_INT64_C(-123545) },
210
211         /* automatic base detection tests */
212         { 0, 0, "123545", NULL, APR_INT64_C(123545) },
213         { 0, 0, "0x1e299", NULL, APR_INT64_C(123545) },
214         { 0, 0, "  0x1e299", NULL, APR_INT64_C(123545) },
215         { 0, 0, "+0x1e299", NULL, APR_INT64_C(123545) },
216         { 0, 0, "-0x1e299", NULL, APR_INT64_C(-123545) },
217
218         /* large number tests */
219         { 0, 10, "8589934605", NULL, APR_INT64_C(8589934605) },
220         { 0, 10, "-8589934605", NULL, APR_INT64_C(-8589934605) },
221         { 0, 16, "0x20000000D", NULL, APR_INT64_C(8589934605) },
222         { 0, 16, "-0x20000000D", NULL, APR_INT64_C(-8589934605) },
223         { 0, 16, "   0x20000000D", NULL, APR_INT64_C(8589934605) },
224         { 0, 16, "   0x20000000D", NULL, APR_INT64_C(8589934605) },
225
226         /* error cases */
227         { ERANGE, 10, "999999999999999999999999999999999", "", MY_LLONG_MAX },
228         { ERANGE, 10, "-999999999999999999999999999999999", "", MY_LLONG_MIN },
229
230 #if 0
231         /* C99 doesn't require EINVAL for an invalid range. */
232         { EINVAL, 99, "", (void *)-1 /* don't care */, 0 },
233 #endif
234
235         /* some strtoll implementations give EINVAL when no conversion
236          * is performed. */
237         { -1 /* don't care */, 10, "zzz", "zzz", APR_INT64_C(0) },
238         { -1 /* don't care */, 10, "", NULL, APR_INT64_C(0) }
239
240     };
241     int n;
242
243     for (n = 0; n < sizeof(ts)/sizeof(ts[0]); n++) {
244         char *end = "end ptr not changed";
245         apr_int64_t result;
246         int errnum;
247         
248         errno = 0;
249         result = apr_strtoi64(ts[n].in, &end, ts[n].base);
250         errnum = errno;
251
252         ABTS_ASSERT(tc,
253                  apr_psprintf(p, "for '%s': result was %" APR_INT64_T_FMT 
254                               " not %" APR_INT64_T_FMT, ts[n].in,
255                               result, ts[n].result),
256                  result == ts[n].result);
257         
258         if (ts[n].errnum != -1) {
259             ABTS_ASSERT(tc,
260                      apr_psprintf(p, "for '%s': errno was %d not %d", ts[n].in,
261                                   errnum, ts[n].errnum),
262                      ts[n].errnum == errnum);
263         }
264
265         if (ts[n].end == NULL) {
266             /* end must point to NUL terminator of .in */
267             ABTS_PTR_EQUAL(tc, ts[n].in + strlen(ts[n].in), end);
268         } else if (ts[n].end != (void *)-1) {
269             ABTS_ASSERT(tc,
270                      apr_psprintf(p, "for '%s', end was '%s' not '%s'",
271                                   ts[n].in, end, ts[n].end),
272                      strcmp(ts[n].end, end) == 0);
273         }
274     }
275 }
276
277 static void string_strtoff(abts_case *tc, void *data)
278 {
279     apr_off_t off;
280
281     ABTS_ASSERT(tc, "strtoff fails on out-of-range integer",
282                 apr_strtoff(&off, "999999999999999999999999999999",
283                             NULL, 10) != APR_SUCCESS);
284
285     ABTS_ASSERT(tc, "strtoff failed for 1234",
286                 apr_strtoff(&off, "1234", NULL, 10) == APR_SUCCESS);
287
288     ABTS_ASSERT(tc, "strtoff failed to parse 1234", off == 1234);
289 }
290
291 /* random-ish checks for strfsize buffer overflows */
292 static void overflow_strfsize(abts_case *tc, void *data)
293 {
294     apr_off_t off;
295     char buf[7];
296
297     buf[5] = '$';
298     buf[6] = '@';
299
300     for (off = -9999; off < 20000; off++) {
301         apr_strfsize(off, buf);
302     }
303     for (; off < 9999999; off += 9) {
304         apr_strfsize(off, buf);
305     }
306     for (; off < 999999999; off += 999) {
307         apr_strfsize(off, buf);
308     }
309     for (off = 1; off < LONG_MAX && off > 0; off *= 2) {
310         apr_strfsize(off, buf);
311         apr_strfsize(off + 1, buf);
312         apr_strfsize(off - 1, buf);
313     }
314
315     ABTS_ASSERT(tc, "strfsize overflowed", buf[5] == '$');
316     ABTS_ASSERT(tc, "strfsize overflowed", buf[6] == '@');
317 }
318
319 static void string_strfsize(abts_case *tc, void *data)
320 {
321     static const struct {
322         apr_off_t size;
323         const char *buf;
324     } ts[] = {
325         { -1,   "  - " },
326         { 0,    "  0 " },
327         { 666,  "666 " },
328         { 1024, "1.0K" },
329         { 1536, "1.5K" },
330         { 2048, "2.0K" },
331         { 1293874, "1.2M" },
332         { 9999999, "9.5M" },
333         { 103809024, " 99M" },
334         { 1047527424, "1.0G" } /* "999M" would be more correct */
335     };
336     apr_size_t n;
337
338     for (n = 0; n < sizeof(ts)/sizeof(ts[0]); n++) {
339         char buf[6], *ret;
340         
341         buf[5] = '%';
342
343         ret = apr_strfsize(ts[n].size, buf);
344         ABTS_ASSERT(tc, "strfsize returned wrong buffer", ret == buf);
345         ABTS_ASSERT(tc, "strfsize overflowed", buf[5] == '%');
346
347         ABTS_STR_EQUAL(tc, ts[n].buf, ret);
348     }
349 }
350
351 static void string_cpystrn(abts_case *tc, void *data)
352 {
353     char buf[6], *ret;
354     
355     buf[5] = 'Z';
356
357     ret = apr_cpystrn(buf, "123456", 5);
358
359     ABTS_STR_EQUAL(tc, "1234", buf);
360     ABTS_PTR_EQUAL(tc, buf + 4, ret);
361     ABTS_TRUE(tc, *ret == '\0');
362     ABTS_TRUE(tc, ret[1] == 'Z');
363 }
364
365 static void snprintf_overflow(abts_case *tc, void *data)
366 {
367     char buf[4];
368     int rv;
369     
370     buf[2] = '4';
371     buf[3] = '2';
372
373     rv = apr_snprintf(buf, 2, "%s", "a");
374     ABTS_INT_EQUAL(tc, 1, rv);
375
376     rv = apr_snprintf(buf, 2, "%s", "abcd");
377     ABTS_INT_EQUAL(tc, 1, rv);
378
379     ABTS_STR_EQUAL(tc, "a", buf);
380
381     /* Check the buffer really hasn't been overflowed. */
382     ABTS_TRUE(tc, buf[2] == '4' && buf[3] == '2');
383 }
384
385 abts_suite *teststr(abts_suite *suite)
386 {
387     suite = ADD_SUITE(suite)
388
389     abts_run_test(suite, snprintf_0NULL, NULL);
390     abts_run_test(suite, snprintf_0nonNULL, NULL);
391     abts_run_test(suite, snprintf_noNULL, NULL);
392     abts_run_test(suite, snprintf_underflow, NULL);
393     abts_run_test(suite, test_strtok, NULL);
394     abts_run_test(suite, string_error, NULL);
395     abts_run_test(suite, string_long, NULL);
396     abts_run_test(suite, string_strtoi64, NULL);
397     abts_run_test(suite, string_strtoff, NULL);
398     abts_run_test(suite, overflow_strfsize, NULL);
399     abts_run_test(suite, string_strfsize, NULL);
400     abts_run_test(suite, string_cpystrn, NULL);
401     abts_run_test(suite, snprintf_overflow, NULL);
402
403     return suite;
404 }
405