In the command-line client, forbid
[svn.git] / subversion / tests / libsvn_subr / string-test.c
blob52f7ccf9589e59ee92cd1a6afe898c2fb430f2d6
1 /*
2 * string-test.c: a collection of libsvn_string tests
4 * ====================================================================
5 * Copyright (c) 2000-2004 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
19 /* ====================================================================
20 To add tests, look toward the bottom of this file.
26 #include <stdio.h>
27 #include <string.h>
29 #include <apr_pools.h>
30 #include <apr_file_io.h>
32 #include "svn_io.h"
33 #include "svn_error.h"
34 #include "svn_string.h" /* This includes <apr_*.h> */
36 #include "../svn_test.h"
39 /* A quick way to create error messages. */
40 static svn_error_t *
41 fail(apr_pool_t *pool, const char *fmt, ...)
43 va_list ap;
44 char *msg;
46 va_start(ap, fmt);
47 msg = apr_pvsprintf(pool, fmt, ap);
48 va_end(ap);
50 return svn_error_create(SVN_ERR_TEST_FAILED, 0, msg);
54 /* Some of our own global variables, for simplicity. Yes,
55 simplicity. */
56 svn_stringbuf_t *a = NULL, *b = NULL, *c = NULL;
57 const char *phrase_1 = "hello, ";
58 const char *phrase_2 = "a longish phrase of sorts, longer than 16 anyway";
63 static svn_error_t *
64 test1(const char **msg,
65 svn_boolean_t msg_only,
66 svn_test_opts_t *opts,
67 apr_pool_t *pool)
69 *msg = "make svn_stringbuf_t from cstring";
71 if (msg_only)
72 return SVN_NO_ERROR;
74 a = svn_stringbuf_create(phrase_1, pool);
76 /* Test that length, data, and null-termination are correct. */
77 if ((a->len == strlen(phrase_1)) && ((strcmp(a->data, phrase_1)) == 0))
78 return SVN_NO_ERROR;
79 else
80 return fail(pool, "test failed");
84 static svn_error_t *
85 test2(const char **msg,
86 svn_boolean_t msg_only,
87 svn_test_opts_t *opts,
88 apr_pool_t *pool)
90 *msg = "make svn_stringbuf_t from substring of cstring";
92 if (msg_only)
93 return SVN_NO_ERROR;
95 b = svn_stringbuf_ncreate(phrase_2, 16, pool);
97 /* Test that length, data, and null-termination are correct. */
98 if ((b->len == 16) && ((strncmp(b->data, phrase_2, 16)) == 0))
99 return SVN_NO_ERROR;
100 else
101 return fail(pool, "test failed");
105 static svn_error_t *
106 test3(const char **msg,
107 svn_boolean_t msg_only,
108 svn_test_opts_t *opts,
109 apr_pool_t *pool)
111 char *tmp;
112 size_t old_len;
114 *msg = "append svn_stringbuf_t to svn_stringbuf_t";
116 if (msg_only)
117 return SVN_NO_ERROR;
119 a = svn_stringbuf_create(phrase_1, pool);
120 b = svn_stringbuf_ncreate(phrase_2, 16, pool);
122 tmp = apr_palloc(pool, (a->len + b->len + 1));
123 strcpy(tmp, a->data);
124 strcat(tmp, b->data);
125 old_len = a->len;
126 svn_stringbuf_appendstr(a, b);
128 /* Test that length, data, and null-termination are correct. */
129 if ((a->len == (old_len + b->len)) && ((strcmp(a->data, tmp)) == 0))
130 return SVN_NO_ERROR;
131 else
132 return fail(pool, "test failed");
136 static svn_error_t *
137 test4(const char **msg,
138 svn_boolean_t msg_only,
139 svn_test_opts_t *opts,
140 apr_pool_t *pool)
142 *msg = "append C string to svn_stringbuf_t";
144 if (msg_only)
145 return SVN_NO_ERROR;
147 a = svn_stringbuf_create(phrase_1, pool);
148 svn_stringbuf_appendcstr(a, "new bytes to append");
150 /* Test that length, data, and null-termination are correct. */
151 if (svn_stringbuf_compare
152 (a, svn_stringbuf_create("hello, new bytes to append", pool)))
153 return SVN_NO_ERROR;
154 else
155 return fail(pool, "test failed");
159 static svn_error_t *
160 test5(const char **msg,
161 svn_boolean_t msg_only,
162 svn_test_opts_t *opts,
163 apr_pool_t *pool)
165 *msg = "append bytes, then compare two strings";
167 if (msg_only)
168 return SVN_NO_ERROR;
170 a = svn_stringbuf_create(phrase_1, pool);
171 svn_stringbuf_appendbytes(a, "new bytes to append", 9);
173 /* Test that length, data, and null-termination are correct. */
174 if (svn_stringbuf_compare
175 (a, svn_stringbuf_create("hello, new bytes", pool)))
176 return SVN_NO_ERROR;
177 else
178 return fail(pool, "test failed");
182 static svn_error_t *
183 test6(const char **msg,
184 svn_boolean_t msg_only,
185 svn_test_opts_t *opts,
186 apr_pool_t *pool)
188 *msg = "dup two strings, then compare";
190 if (msg_only)
191 return SVN_NO_ERROR;
193 a = svn_stringbuf_create(phrase_1, pool);
194 b = svn_stringbuf_create(phrase_2, pool);
195 c = svn_stringbuf_dup(a, pool);
197 /* Test that length, data, and null-termination are correct. */
198 if ((svn_stringbuf_compare(a, c)) && (! svn_stringbuf_compare(b, c)))
199 return SVN_NO_ERROR;
200 else
201 return fail(pool, "test failed");
205 static svn_error_t *
206 test7(const char **msg,
207 svn_boolean_t msg_only,
208 svn_test_opts_t *opts,
209 apr_pool_t *pool)
211 char *tmp;
212 size_t tmp_len;
214 *msg = "chopping a string";
216 if (msg_only)
217 return SVN_NO_ERROR;
219 c = svn_stringbuf_create(phrase_2, pool);
221 tmp_len = c->len;
222 tmp = apr_palloc(pool, c->len + 1);
223 strcpy(tmp, c->data);
225 svn_stringbuf_chop(c, 11);
227 if ((c->len == (tmp_len - 11))
228 && (strncmp(tmp, c->data, c->len) == 0)
229 && (c->data[c->len] == '\0'))
230 return SVN_NO_ERROR;
231 else
232 return fail(pool, "test failed");
236 static svn_error_t *
237 test8(const char **msg,
238 svn_boolean_t msg_only,
239 svn_test_opts_t *opts,
240 apr_pool_t *pool)
242 *msg = "emptying a string";
244 if (msg_only)
245 return SVN_NO_ERROR;
247 c = svn_stringbuf_create(phrase_2, pool);
249 svn_stringbuf_setempty(c);
251 if ((c->len == 0) && (c->data[0] == '\0'))
252 return SVN_NO_ERROR;
253 else
254 return fail(pool, "test failed");
258 static svn_error_t *
259 test9(const char **msg,
260 svn_boolean_t msg_only,
261 svn_test_opts_t *opts,
262 apr_pool_t *pool)
264 *msg = "fill string with hashmarks";
266 if (msg_only)
267 return SVN_NO_ERROR;
269 a = svn_stringbuf_create(phrase_1, pool);
271 svn_stringbuf_fillchar(a, '#');
273 if ((strcmp(a->data, "#######") == 0)
274 && ((strncmp(a->data, "############", a->len - 1)) == 0)
275 && (a->data[(a->len - 1)] == '#')
276 && (a->data[(a->len)] == '\0'))
277 return SVN_NO_ERROR;
278 else
279 return fail(pool, "test failed");
284 static svn_error_t *
285 test10(const char **msg,
286 svn_boolean_t msg_only,
287 svn_test_opts_t *opts,
288 apr_pool_t *pool)
290 svn_stringbuf_t *s, *t;
291 size_t len_1 = 0;
292 size_t len_2 = 0;
293 size_t block_len_1 = 0;
294 size_t block_len_2 = 0;
296 *msg = "block initialization and growth";
298 if (msg_only)
299 return SVN_NO_ERROR;
301 s = svn_stringbuf_create("a small string", pool);
302 len_1 = (s->len);
303 block_len_1 = (s->blocksize);
305 t = svn_stringbuf_create(", plus a string more than twice as long", pool);
306 svn_stringbuf_appendstr(s, t);
307 len_2 = (s->len);
308 block_len_2 = (s->blocksize);
310 /* Test that:
311 * - The initial block was just the right fit.
312 * - The block more than doubled (because second string so long).
313 * - The block grew by a power of 2.
315 if ((len_1 == (block_len_1 - 1))
316 && ((block_len_2 / block_len_1) > 2)
317 && (((block_len_2 / block_len_1) % 2) == 0))
318 return SVN_NO_ERROR;
319 else
320 return fail(pool, "test failed");
324 static svn_error_t *
325 test11(const char **msg,
326 svn_boolean_t msg_only,
327 svn_test_opts_t *opts,
328 apr_pool_t *pool)
330 svn_stringbuf_t *s;
332 *msg = "formatting strings from varargs";
334 if (msg_only)
335 return SVN_NO_ERROR;
337 s = svn_stringbuf_createf(pool,
338 "This %s is used in test %d.",
339 "string",
340 12);
342 if (strcmp(s->data, "This string is used in test 12.") == 0)
343 return SVN_NO_ERROR;
344 else
345 return fail(pool, "test failed");
348 static svn_error_t *
349 check_string_contents(svn_stringbuf_t *string,
350 const char *ftext,
351 apr_size_t ftext_len,
352 int repeat,
353 apr_pool_t *pool)
355 const char *data;
356 apr_size_t len;
357 int i;
359 data = string->data;
360 len = string->len;
361 for (i = 0; i < repeat; ++i)
363 if (len < ftext_len || memcmp(ftext, data, ftext_len))
364 return fail(pool, "comparing failed");
365 data += ftext_len;
366 len -= ftext_len;
368 if (len < 1 || memcmp(data, "\0", 1))
369 return fail(pool, "comparing failed");
370 data += 1;
371 len -= 1;
372 for (i = 0; i < repeat; ++i)
374 if (len < ftext_len || memcmp(ftext, data, ftext_len))
375 return fail(pool, "comparing failed");
376 data += ftext_len;
377 len -= ftext_len;
380 if (len)
381 return fail(pool, "comparing failed");
383 return SVN_NO_ERROR;
387 static svn_error_t *
388 test12(const char **msg,
389 svn_boolean_t msg_only,
390 svn_test_opts_t *opts,
391 apr_pool_t *pool)
393 svn_stringbuf_t *s;
394 const char fname[] = "string-test.tmp";
395 apr_file_t *file;
396 apr_status_t status;
397 apr_size_t len;
398 int i, repeat;
399 const char ftext[] =
400 "Just some boring text. Avoiding newlines 'cos I don't know"
401 "if any of the Subversion platfoms will mangle them! There's no"
402 "need to test newline handling here anyway, it's not relevant.";
404 *msg = "create string from file";
406 if (msg_only)
407 return SVN_NO_ERROR;
409 status = apr_file_open(&file, fname, APR_WRITE | APR_TRUNCATE | APR_CREATE,
410 APR_OS_DEFAULT, pool);
411 if (status)
412 return fail(pool, "opening file");
414 repeat = 100;
416 /* Some text */
417 for (i = 0; i < repeat; ++i)
419 status = apr_file_write_full(file, ftext, sizeof(ftext) - 1, &len);
420 if (status)
421 return fail(pool, "writing file");
424 /* A null byte, I don't *think* any of our platforms mangle these */
425 status = apr_file_write_full(file, "\0", 1, &len);
426 if (status)
427 return fail(pool, "writing file");
429 /* Some more text */
430 for (i = 0; i < repeat; ++i)
432 status = apr_file_write_full(file, ftext, sizeof(ftext) - 1, &len);
433 if (status)
434 return fail(pool, "writing file");
437 status = apr_file_close(file);
438 if (status)
439 return fail(pool, "closing file");
441 SVN_ERR(svn_stringbuf_from_file(&s, fname, pool));
442 SVN_ERR(check_string_contents(s, ftext, sizeof(ftext) - 1, repeat, pool));
444 /* Reset to avoid false positives */
445 s = NULL;
447 status = apr_file_open(&file, fname, APR_READ, APR_OS_DEFAULT, pool);
448 if (status)
449 return fail(pool, "opening file");
451 SVN_ERR(svn_stringbuf_from_aprfile(&s, file, pool));
452 SVN_ERR(check_string_contents(s, ftext, sizeof(ftext) - 1, repeat, pool));
454 status = apr_file_close(file);
455 if (status)
456 return fail(pool, "closing file");
458 return SVN_NO_ERROR;
461 /* Helper function for checking correctness of find_char_backward */
462 static svn_error_t *
463 test_find_char_backward(const char* data,
464 apr_size_t len,
465 char ch,
466 apr_size_t pos,
467 svn_boolean_t msg_only,
468 apr_pool_t *pool)
470 apr_size_t i;
472 if (msg_only)
473 return SVN_NO_ERROR;
475 a = svn_stringbuf_create(data, pool);
476 i = svn_stringbuf_find_char_backward(a, ch);
478 if (i == pos)
479 return SVN_NO_ERROR;
480 else
481 return fail(pool, "test failed");
484 static svn_error_t *
485 test13(const char **msg,
486 svn_boolean_t msg_only,
487 svn_test_opts_t *opts,
488 apr_pool_t *pool)
490 *msg = "find_char_backward; middle case";
491 a = svn_stringbuf_create("test, test", pool);
493 return
494 test_find_char_backward(a->data, a->len, ',', 4, msg_only, pool);
497 static svn_error_t *
498 test14(const char **msg,
499 svn_boolean_t msg_only,
500 svn_test_opts_t *opts,
501 apr_pool_t *pool)
503 *msg = "find_char_backward; 0 case";
505 a = svn_stringbuf_create(",test test", pool);
507 return
508 test_find_char_backward(a->data, a->len, ',', 0, msg_only, pool);
511 static svn_error_t *
512 test15(const char **msg,
513 svn_boolean_t msg_only,
514 svn_test_opts_t *opts,
515 apr_pool_t *pool)
517 *msg = "find_char_backward; strlen - 1 case";
519 a = svn_stringbuf_create("testing,", pool);
521 return test_find_char_backward(a->data,
522 a->len,
523 ',',
524 a->len - 1,
525 msg_only,
526 pool);
529 static svn_error_t *
530 test16(const char **msg,
531 svn_boolean_t msg_only,
532 svn_test_opts_t *opts,
533 apr_pool_t *pool)
535 *msg = "find_char_backward; len = 0 case";
537 a = svn_stringbuf_create("", pool);
539 return
540 test_find_char_backward(a->data, a->len, ',', 0, msg_only, pool);
543 static svn_error_t *
544 test17(const char **msg,
545 svn_boolean_t msg_only,
546 svn_test_opts_t *opts,
547 apr_pool_t *pool)
549 *msg = "find_char_backward; no occurence case";
551 a = svn_stringbuf_create("test test test", pool);
553 return test_find_char_backward(a->data,
554 a->len,
555 ',',
556 a->len,
557 msg_only,
558 pool);
561 static svn_error_t *
562 test_first_non_whitespace(const char *str,
563 const apr_size_t pos,
564 svn_boolean_t msg_only,
565 apr_pool_t *pool)
567 apr_size_t i;
569 if (msg_only)
570 return SVN_NO_ERROR;
572 a = svn_stringbuf_create(str, pool);
574 i = svn_stringbuf_first_non_whitespace(a);
576 if (i == pos)
577 return SVN_NO_ERROR;
578 else
579 return fail(pool, "test failed");
582 static svn_error_t *
583 test18(const char **msg,
584 svn_boolean_t msg_only,
585 svn_test_opts_t *opts,
586 apr_pool_t *pool)
588 *msg = "check whitespace removal; common case";
590 return test_first_non_whitespace(" \ttest", 4, msg_only, pool);
593 static svn_error_t *
594 test19(const char **msg,
595 svn_boolean_t msg_only,
596 svn_test_opts_t *opts,
597 apr_pool_t *pool)
599 *msg = "check whitespace removal; no whitespace case";
601 return test_first_non_whitespace("test", 0, msg_only, pool);
604 static svn_error_t *
605 test20(const char **msg,
606 svn_boolean_t msg_only,
607 svn_test_opts_t *opts,
608 apr_pool_t *pool)
610 *msg = "check whitespace removal; all whitespace case";
612 return test_first_non_whitespace(" ", 3, msg_only, pool);
615 static svn_error_t *
616 test21(const char **msg,
617 svn_boolean_t msg_only,
618 svn_test_opts_t *opts,
619 apr_pool_t *pool)
621 *msg = "check that whitespace will be stripped correctly";
623 if (msg_only)
624 return SVN_NO_ERROR;
626 a = svn_stringbuf_create(" \ttest\t\t \t ", pool);
627 b = svn_stringbuf_create("test", pool);
629 svn_stringbuf_strip_whitespace(a);
631 if (svn_stringbuf_compare(a, b) == TRUE)
632 return SVN_NO_ERROR;
633 else
634 return fail(pool, "test failed");
637 static svn_error_t *
638 test_stringbuf_unequal(const char* str1,
639 const char* str2,
640 svn_boolean_t msg_only,
641 apr_pool_t *pool)
643 if (msg_only)
644 return SVN_NO_ERROR;
646 a = svn_stringbuf_create(str1, pool);
647 b = svn_stringbuf_create(str2, pool);
649 if (svn_stringbuf_compare(a, b))
650 return fail(pool, "test failed");
651 else
652 return SVN_NO_ERROR;
655 static svn_error_t *
656 test22(const char **msg,
657 svn_boolean_t msg_only,
658 svn_test_opts_t *opts,
659 apr_pool_t *pool)
661 *msg = "compare stringbufs; different lengths";
663 return test_stringbuf_unequal("abc", "abcd", msg_only, pool);
666 static svn_error_t *
667 test23(const char **msg,
668 svn_boolean_t msg_only,
669 svn_test_opts_t *opts,
670 apr_pool_t *pool)
672 *msg = "compare stringbufs; same length, different content";
674 return test_stringbuf_unequal("abc", "abb", msg_only, pool);
678 ====================================================================
679 If you add a new test to this file, update this array.
681 (These globals are required by our included main())
684 /* An array of all test functions */
685 struct svn_test_descriptor_t test_funcs[] =
687 SVN_TEST_NULL,
688 SVN_TEST_PASS(test1),
689 SVN_TEST_PASS(test2),
690 SVN_TEST_PASS(test3),
691 SVN_TEST_PASS(test4),
692 SVN_TEST_PASS(test5),
693 SVN_TEST_PASS(test6),
694 SVN_TEST_PASS(test7),
695 SVN_TEST_PASS(test8),
696 SVN_TEST_PASS(test9),
697 SVN_TEST_PASS(test10),
698 SVN_TEST_PASS(test11),
699 SVN_TEST_PASS(test12),
700 SVN_TEST_PASS(test13),
701 SVN_TEST_PASS(test14),
702 SVN_TEST_PASS(test15),
703 SVN_TEST_PASS(test16),
704 SVN_TEST_PASS(test17),
705 SVN_TEST_PASS(test18),
706 SVN_TEST_PASS(test19),
707 SVN_TEST_PASS(test20),
708 SVN_TEST_PASS(test21),
709 SVN_TEST_PASS(test22),
710 SVN_TEST_PASS(test23),
711 SVN_TEST_NULL