/* * string-test.c: a collection of libsvn_string tests * * ==================================================================== * Copyright (c) 2000-2004 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== */ /* ==================================================================== To add tests, look toward the bottom of this file. */ #include #include #include #include #include "svn_io.h" #include "svn_error.h" #include "svn_string.h" /* This includes */ #include "../svn_test.h" /* A quick way to create error messages. */ static svn_error_t * fail(apr_pool_t *pool, const char *fmt, ...) { va_list ap; char *msg; va_start(ap, fmt); msg = apr_pvsprintf(pool, fmt, ap); va_end(ap); return svn_error_create(SVN_ERR_TEST_FAILED, 0, msg); } /* Some of our own global variables, for simplicity. Yes, simplicity. */ svn_stringbuf_t *a = NULL, *b = NULL, *c = NULL; const char *phrase_1 = "hello, "; const char *phrase_2 = "a longish phrase of sorts, longer than 16 anyway"; static svn_error_t * test1(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "make svn_stringbuf_t from cstring"; if (msg_only) return SVN_NO_ERROR; a = svn_stringbuf_create(phrase_1, pool); /* Test that length, data, and null-termination are correct. */ if ((a->len == strlen(phrase_1)) && ((strcmp(a->data, phrase_1)) == 0)) return SVN_NO_ERROR; else return fail(pool, "test failed"); } static svn_error_t * test2(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "make svn_stringbuf_t from substring of cstring"; if (msg_only) return SVN_NO_ERROR; b = svn_stringbuf_ncreate(phrase_2, 16, pool); /* Test that length, data, and null-termination are correct. */ if ((b->len == 16) && ((strncmp(b->data, phrase_2, 16)) == 0)) return SVN_NO_ERROR; else return fail(pool, "test failed"); } static svn_error_t * test3(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { char *tmp; size_t old_len; *msg = "append svn_stringbuf_t to svn_stringbuf_t"; if (msg_only) return SVN_NO_ERROR; a = svn_stringbuf_create(phrase_1, pool); b = svn_stringbuf_ncreate(phrase_2, 16, pool); tmp = apr_palloc(pool, (a->len + b->len + 1)); strcpy(tmp, a->data); strcat(tmp, b->data); old_len = a->len; svn_stringbuf_appendstr(a, b); /* Test that length, data, and null-termination are correct. */ if ((a->len == (old_len + b->len)) && ((strcmp(a->data, tmp)) == 0)) return SVN_NO_ERROR; else return fail(pool, "test failed"); } static svn_error_t * test4(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "append C string to svn_stringbuf_t"; if (msg_only) return SVN_NO_ERROR; a = svn_stringbuf_create(phrase_1, pool); svn_stringbuf_appendcstr(a, "new bytes to append"); /* Test that length, data, and null-termination are correct. */ if (svn_stringbuf_compare (a, svn_stringbuf_create("hello, new bytes to append", pool))) return SVN_NO_ERROR; else return fail(pool, "test failed"); } static svn_error_t * test5(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "append bytes, then compare two strings"; if (msg_only) return SVN_NO_ERROR; a = svn_stringbuf_create(phrase_1, pool); svn_stringbuf_appendbytes(a, "new bytes to append", 9); /* Test that length, data, and null-termination are correct. */ if (svn_stringbuf_compare (a, svn_stringbuf_create("hello, new bytes", pool))) return SVN_NO_ERROR; else return fail(pool, "test failed"); } static svn_error_t * test6(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "dup two strings, then compare"; if (msg_only) return SVN_NO_ERROR; a = svn_stringbuf_create(phrase_1, pool); b = svn_stringbuf_create(phrase_2, pool); c = svn_stringbuf_dup(a, pool); /* Test that length, data, and null-termination are correct. */ if ((svn_stringbuf_compare(a, c)) && (! svn_stringbuf_compare(b, c))) return SVN_NO_ERROR; else return fail(pool, "test failed"); } static svn_error_t * test7(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { char *tmp; size_t tmp_len; *msg = "chopping a string"; if (msg_only) return SVN_NO_ERROR; c = svn_stringbuf_create(phrase_2, pool); tmp_len = c->len; tmp = apr_palloc(pool, c->len + 1); strcpy(tmp, c->data); svn_stringbuf_chop(c, 11); if ((c->len == (tmp_len - 11)) && (strncmp(tmp, c->data, c->len) == 0) && (c->data[c->len] == '\0')) return SVN_NO_ERROR; else return fail(pool, "test failed"); } static svn_error_t * test8(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "emptying a string"; if (msg_only) return SVN_NO_ERROR; c = svn_stringbuf_create(phrase_2, pool); svn_stringbuf_setempty(c); if ((c->len == 0) && (c->data[0] == '\0')) return SVN_NO_ERROR; else return fail(pool, "test failed"); } static svn_error_t * test9(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "fill string with hashmarks"; if (msg_only) return SVN_NO_ERROR; a = svn_stringbuf_create(phrase_1, pool); svn_stringbuf_fillchar(a, '#'); if ((strcmp(a->data, "#######") == 0) && ((strncmp(a->data, "############", a->len - 1)) == 0) && (a->data[(a->len - 1)] == '#') && (a->data[(a->len)] == '\0')) return SVN_NO_ERROR; else return fail(pool, "test failed"); } static svn_error_t * test10(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { svn_stringbuf_t *s, *t; size_t len_1 = 0; size_t len_2 = 0; size_t block_len_1 = 0; size_t block_len_2 = 0; *msg = "block initialization and growth"; if (msg_only) return SVN_NO_ERROR; s = svn_stringbuf_create("a small string", pool); len_1 = (s->len); block_len_1 = (s->blocksize); t = svn_stringbuf_create(", plus a string more than twice as long", pool); svn_stringbuf_appendstr(s, t); len_2 = (s->len); block_len_2 = (s->blocksize); /* Test that: * - The initial block was just the right fit. * - The block more than doubled (because second string so long). * - The block grew by a power of 2. */ if ((len_1 == (block_len_1 - 1)) && ((block_len_2 / block_len_1) > 2) && (((block_len_2 / block_len_1) % 2) == 0)) return SVN_NO_ERROR; else return fail(pool, "test failed"); } static svn_error_t * test11(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { svn_stringbuf_t *s; *msg = "formatting strings from varargs"; if (msg_only) return SVN_NO_ERROR; s = svn_stringbuf_createf(pool, "This %s is used in test %d.", "string", 12); if (strcmp(s->data, "This string is used in test 12.") == 0) return SVN_NO_ERROR; else return fail(pool, "test failed"); } static svn_error_t * check_string_contents(svn_stringbuf_t *string, const char *ftext, apr_size_t ftext_len, int repeat, apr_pool_t *pool) { const char *data; apr_size_t len; int i; data = string->data; len = string->len; for (i = 0; i < repeat; ++i) { if (len < ftext_len || memcmp(ftext, data, ftext_len)) return fail(pool, "comparing failed"); data += ftext_len; len -= ftext_len; } if (len < 1 || memcmp(data, "\0", 1)) return fail(pool, "comparing failed"); data += 1; len -= 1; for (i = 0; i < repeat; ++i) { if (len < ftext_len || memcmp(ftext, data, ftext_len)) return fail(pool, "comparing failed"); data += ftext_len; len -= ftext_len; } if (len) return fail(pool, "comparing failed"); return SVN_NO_ERROR; } static svn_error_t * test12(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { svn_stringbuf_t *s; const char fname[] = "string-test.tmp"; apr_file_t *file; apr_status_t status; apr_size_t len; int i, repeat; const char ftext[] = "Just some boring text. Avoiding newlines 'cos I don't know" "if any of the Subversion platfoms will mangle them! There's no" "need to test newline handling here anyway, it's not relevant."; *msg = "create string from file"; if (msg_only) return SVN_NO_ERROR; status = apr_file_open(&file, fname, APR_WRITE | APR_TRUNCATE | APR_CREATE, APR_OS_DEFAULT, pool); if (status) return fail(pool, "opening file"); repeat = 100; /* Some text */ for (i = 0; i < repeat; ++i) { status = apr_file_write_full(file, ftext, sizeof(ftext) - 1, &len); if (status) return fail(pool, "writing file"); } /* A null byte, I don't *think* any of our platforms mangle these */ status = apr_file_write_full(file, "\0", 1, &len); if (status) return fail(pool, "writing file"); /* Some more text */ for (i = 0; i < repeat; ++i) { status = apr_file_write_full(file, ftext, sizeof(ftext) - 1, &len); if (status) return fail(pool, "writing file"); } status = apr_file_close(file); if (status) return fail(pool, "closing file"); SVN_ERR(svn_stringbuf_from_file(&s, fname, pool)); SVN_ERR(check_string_contents(s, ftext, sizeof(ftext) - 1, repeat, pool)); /* Reset to avoid false positives */ s = NULL; status = apr_file_open(&file, fname, APR_READ, APR_OS_DEFAULT, pool); if (status) return fail(pool, "opening file"); SVN_ERR(svn_stringbuf_from_aprfile(&s, file, pool)); SVN_ERR(check_string_contents(s, ftext, sizeof(ftext) - 1, repeat, pool)); status = apr_file_close(file); if (status) return fail(pool, "closing file"); return SVN_NO_ERROR; } /* Helper function for checking correctness of find_char_backward */ static svn_error_t * test_find_char_backward(const char* data, apr_size_t len, char ch, apr_size_t pos, svn_boolean_t msg_only, apr_pool_t *pool) { apr_size_t i; if (msg_only) return SVN_NO_ERROR; a = svn_stringbuf_create(data, pool); i = svn_stringbuf_find_char_backward(a, ch); if (i == pos) return SVN_NO_ERROR; else return fail(pool, "test failed"); } static svn_error_t * test13(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "find_char_backward; middle case"; a = svn_stringbuf_create("test, test", pool); return test_find_char_backward(a->data, a->len, ',', 4, msg_only, pool); } static svn_error_t * test14(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "find_char_backward; 0 case"; a = svn_stringbuf_create(",test test", pool); return test_find_char_backward(a->data, a->len, ',', 0, msg_only, pool); } static svn_error_t * test15(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "find_char_backward; strlen - 1 case"; a = svn_stringbuf_create("testing,", pool); return test_find_char_backward(a->data, a->len, ',', a->len - 1, msg_only, pool); } static svn_error_t * test16(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "find_char_backward; len = 0 case"; a = svn_stringbuf_create("", pool); return test_find_char_backward(a->data, a->len, ',', 0, msg_only, pool); } static svn_error_t * test17(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "find_char_backward; no occurence case"; a = svn_stringbuf_create("test test test", pool); return test_find_char_backward(a->data, a->len, ',', a->len, msg_only, pool); } static svn_error_t * test_first_non_whitespace(const char *str, const apr_size_t pos, svn_boolean_t msg_only, apr_pool_t *pool) { apr_size_t i; if (msg_only) return SVN_NO_ERROR; a = svn_stringbuf_create(str, pool); i = svn_stringbuf_first_non_whitespace(a); if (i == pos) return SVN_NO_ERROR; else return fail(pool, "test failed"); } static svn_error_t * test18(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "check whitespace removal; common case"; return test_first_non_whitespace(" \ttest", 4, msg_only, pool); } static svn_error_t * test19(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "check whitespace removal; no whitespace case"; return test_first_non_whitespace("test", 0, msg_only, pool); } static svn_error_t * test20(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "check whitespace removal; all whitespace case"; return test_first_non_whitespace(" ", 3, msg_only, pool); } static svn_error_t * test21(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "check that whitespace will be stripped correctly"; if (msg_only) return SVN_NO_ERROR; a = svn_stringbuf_create(" \ttest\t\t \t ", pool); b = svn_stringbuf_create("test", pool); svn_stringbuf_strip_whitespace(a); if (svn_stringbuf_compare(a, b) == TRUE) return SVN_NO_ERROR; else return fail(pool, "test failed"); } static svn_error_t * test_stringbuf_unequal(const char* str1, const char* str2, svn_boolean_t msg_only, apr_pool_t *pool) { if (msg_only) return SVN_NO_ERROR; a = svn_stringbuf_create(str1, pool); b = svn_stringbuf_create(str2, pool); if (svn_stringbuf_compare(a, b)) return fail(pool, "test failed"); else return SVN_NO_ERROR; } static svn_error_t * test22(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "compare stringbufs; different lengths"; return test_stringbuf_unequal("abc", "abcd", msg_only, pool); } static svn_error_t * test23(const char **msg, svn_boolean_t msg_only, svn_test_opts_t *opts, apr_pool_t *pool) { *msg = "compare stringbufs; same length, different content"; return test_stringbuf_unequal("abc", "abb", msg_only, pool); } /* ==================================================================== If you add a new test to this file, update this array. (These globals are required by our included main()) */ /* An array of all test functions */ struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS(test1), SVN_TEST_PASS(test2), SVN_TEST_PASS(test3), SVN_TEST_PASS(test4), SVN_TEST_PASS(test5), SVN_TEST_PASS(test6), SVN_TEST_PASS(test7), SVN_TEST_PASS(test8), SVN_TEST_PASS(test9), SVN_TEST_PASS(test10), SVN_TEST_PASS(test11), SVN_TEST_PASS(test12), SVN_TEST_PASS(test13), SVN_TEST_PASS(test14), SVN_TEST_PASS(test15), SVN_TEST_PASS(test16), SVN_TEST_PASS(test17), SVN_TEST_PASS(test18), SVN_TEST_PASS(test19), SVN_TEST_PASS(test20), SVN_TEST_PASS(test21), SVN_TEST_PASS(test22), SVN_TEST_PASS(test23), SVN_TEST_NULL };