diff options
Diffstat (limited to 'subversion/tests/libsvn_subr')
33 files changed, 4400 insertions, 1703 deletions
diff --git a/subversion/tests/libsvn_subr/auth-test.c b/subversion/tests/libsvn_subr/auth-test.c index 9d7d866..bbe7933 100644 --- a/subversion/tests/libsvn_subr/auth-test.c +++ b/subversion/tests/libsvn_subr/auth-test.c @@ -63,13 +63,14 @@ test_platform_specific_auth_providers(apr_pool_t *pool) number_of_providers += 2; #endif #if defined(WIN32) && !defined(__MINGW32__) - number_of_providers += 2; + number_of_providers += 4; #endif if (providers->nelts != number_of_providers) return svn_error_createf (SVN_ERR_TEST_FAILED, NULL, "svn_auth_get_platform_specific_client_providers should return " \ - "an array of %d providers", number_of_providers); + "an array of %d providers, but returned %d providers", + number_of_providers, providers->nelts); /* Test Keychain auth providers */ #ifdef SVN_HAVE_KEYCHAIN_SERVICES @@ -219,8 +220,8 @@ cleanup_callback(svn_boolean_t *delete_cred, { svn_auth_baton_t *b = walk_baton; - SVN_TEST_ASSERT(strcmp(cred_kind, SVN_AUTH_CRED_SIMPLE) == 0); - SVN_TEST_ASSERT(strcmp(realmstring, "<http://my.host> My realm") == 0); + SVN_TEST_STRING_ASSERT(cred_kind, SVN_AUTH_CRED_SIMPLE); + SVN_TEST_STRING_ASSERT(realmstring, "<http://my.host> My realm"); SVN_ERR(svn_auth_forget_credentials(b, cred_kind, realmstring, scratch_pool)); @@ -271,7 +272,7 @@ test_auth_clear(apr_pool_t *pool) pool)); creds = credentials; - SVN_TEST_ASSERT(strcmp(creds->username, "jrandom") == 0); + SVN_TEST_STRING_ASSERT(creds->username, "jrandom"); SVN_TEST_ASSERT(creds->may_save); /* And tell that they are ok and can be saved */ @@ -291,7 +292,7 @@ test_auth_clear(apr_pool_t *pool) SVN_TEST_ASSERT(credentials); creds = credentials; - SVN_TEST_ASSERT(strcmp(creds->username, "jrandom") == 0); + SVN_TEST_STRING_ASSERT(creds->username, "jrandom"); SVN_TEST_ASSERT(creds->may_save); /* Use our walker function to delete credentials (and forget them @@ -314,18 +315,16 @@ test_auth_clear(apr_pool_t *pool) /* The test table. */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_platform_specific_auth_providers, "test retrieving platform-specific auth providers"), -#ifndef SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE SVN_TEST_PASS2(test_auth_clear, "test svn_auth_clear()"), -#else - SVN_TEST_WIMP(test_auth_clear, - "test svn_auth_clear()", - "Needs testing with SVN_DISABLE_PLAINTEXT_PASSWORD_STORAGE"), -#endif SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/bit-array-test.c b/subversion/tests/libsvn_subr/bit-array-test.c new file mode 100644 index 0000000..e6fe528 --- /dev/null +++ b/subversion/tests/libsvn_subr/bit-array-test.c @@ -0,0 +1,140 @@ +/* + * bit-array-test.c: a collection of svn_bit_array__* tests + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + +/* ==================================================================== + To add tests, look toward the bottom of this file. + +*/ + + + +#include <stdio.h> +#include <string.h> +#include <apr_pools.h> + +#include "../svn_test.h" + +#include "svn_error.h" +#include "svn_string.h" /* This includes <apr_*.h> */ +#include "private/svn_subr_private.h" + +static svn_error_t * +test_zero_defaults(apr_pool_t *pool) +{ + svn_bit_array__t *array = svn_bit_array__create(0, pool); + + /* Test (default) allocation boundaries */ + SVN_TEST_ASSERT(svn_bit_array__get(array, 0x7ffff) == 0); + SVN_TEST_ASSERT(svn_bit_array__get(array, 0x80000) == 0); + + /* Test address boundaries */ + SVN_TEST_ASSERT(svn_bit_array__get(array, 0) == 0); + SVN_TEST_ASSERT(svn_bit_array__get(array, APR_SIZE_MAX) == 0); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_get_set(apr_pool_t *pool) +{ + svn_bit_array__t *array = svn_bit_array__create(0, pool); + apr_size_t i, min = 0x7ff00, max = 0x7ff00 + 1025; + + /* All values default to 0. */ + for (i = min; i < max; ++i) + SVN_TEST_ASSERT(svn_bit_array__get(array, i) == 0); + + /* Create a pattern, setting every other bit. Array will also auto-grow. */ + for (i = min; i < max; ++i) + if (i % 2) + svn_bit_array__set(array, i, 1); + + /* Verify pattern */ + for (i = min; i < max; ++i) + SVN_TEST_ASSERT(svn_bit_array__get(array, i) == i % 2); + + /* Zero the zeros in the pattern -> should be no change. */ + for (i = min; i < max; ++i) + if (i % 2 == 0) + svn_bit_array__set(array, i, 0); + + /* Verify pattern */ + for (i = min; i < max; ++i) + SVN_TEST_ASSERT(svn_bit_array__get(array, i) == i % 2); + + /* Write an inverted pattern while verifying the old one. */ + for (i = min; i < max; ++i) + { + SVN_TEST_ASSERT(svn_bit_array__get(array, i) == i % 2); + svn_bit_array__set(array, i, 1 - (i % 2)); + } + + /* Verify pattern */ + for (i = min; i < max; ++i) + SVN_TEST_ASSERT(svn_bit_array__get(array, i) == 1 - (i % 2)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_sparse(apr_pool_t *pool) +{ + svn_bit_array__t *array = svn_bit_array__create(0, pool); + apr_size_t i, k, min = 0x7ff00, max = 0x7ff00 + 1025, SCALE = 0x10000000; + + /* All values default to 0. */ + for (i = 0; i < 15; ++i) + for (k = i * SCALE + min; k < i * SCALE + max; ++k) + SVN_TEST_ASSERT(svn_bit_array__get(array, k) == 0); + + /* Create a pattern, setting every other bit. Array will also auto-grow. */ + for (i = 0; i < 15; ++i) + for (k = i * SCALE + min; k < i * SCALE + max; ++k) + if (k % 2) + svn_bit_array__set(array, k, 1); + + /* Verify pattern */ + for (i = 0; i < 15; ++i) + for (k = i * SCALE + min; k < i * SCALE + max; ++k) + SVN_TEST_ASSERT(svn_bit_array__get(array, k) == k % 2); + + return SVN_NO_ERROR; +} + +/* An array of all test functions */ + +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = + { + SVN_TEST_NULL, + SVN_TEST_PASS2(test_zero_defaults, + "check entries to default to zero"), + SVN_TEST_PASS2(test_get_set, + "get / set entries"), + SVN_TEST_PASS2(test_sparse, + "get / set sparse entries"), + SVN_TEST_NULL + }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/cache-test.c b/subversion/tests/libsvn_subr/cache-test.c index 9e7a7b3..1616441 100644 --- a/subversion/tests/libsvn_subr/cache-test.c +++ b/subversion/tests/libsvn_subr/cache-test.c @@ -157,7 +157,8 @@ test_memcache_basic(const svn_test_opts_t *opts, { SVN_ERR(svn_config_read3(&config, opts->config_file, TRUE, FALSE, FALSE, pool)); - SVN_ERR(svn_cache__make_memcache_from_config(&memcache, config, pool)); + SVN_ERR(svn_cache__make_memcache_from_config(&memcache, config, + pool, pool)); } if (! memcache) @@ -193,8 +194,9 @@ test_membuffer_cache_basic(apr_pool_t *pool) deserialize_revnum, APR_HASH_KEY_STRING, "cache:", + SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY, FALSE, - pool)); + pool, pool)); return basic_cache_test(cache, FALSE, pool); } @@ -220,6 +222,16 @@ raise_error_partial_getter_func(void **out, return svn_error_create(APR_EGENERAL, NULL, NULL); } +/* Implements svn_cache__partial_setter_func_t */ +static svn_error_t * +raise_error_partial_setter_func(void **data, + apr_size_t *data_len, + void *baton, + apr_pool_t *result_pool) +{ + return svn_error_create(APR_EGENERAL, NULL, NULL); +} + static svn_error_t * test_membuffer_serializer_error_handling(apr_pool_t *pool) { @@ -239,8 +251,9 @@ test_membuffer_serializer_error_handling(apr_pool_t *pool) raise_error_deserialize_func, APR_HASH_KEY_STRING, "cache:", + SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY, FALSE, - pool)); + pool, pool)); SVN_ERR(svn_cache__set(cache, "twenty", &twenty, pool)); @@ -258,6 +271,30 @@ test_membuffer_serializer_error_handling(apr_pool_t *pool) NULL, pool), APR_EGENERAL); + /* Create a new cache. */ + SVN_ERR(svn_cache__membuffer_cache_create(&membuffer, 10*1024, 1, 0, + TRUE, TRUE, pool)); + SVN_ERR(svn_cache__create_membuffer_cache(&cache, + membuffer, + serialize_revnum, + deserialize_revnum, + APR_HASH_KEY_STRING, + "cache:", + SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY, + FALSE, + pool, pool)); + + /* Store one entry in cache. */ + SVN_ERR(svn_cache__set(cache, "twenty", &twenty, pool)); + + /* Test setting data in cache using partial setter that + always raises an error. */ + SVN_TEST_ASSERT_ERROR( + svn_cache__set_partial(cache, "twenty", + raise_error_partial_setter_func, + NULL, pool), + APR_EGENERAL); + return SVN_NO_ERROR; } @@ -286,7 +323,8 @@ test_memcache_long_key(const svn_test_opts_t *opts, { SVN_ERR(svn_config_read3(&config, opts->config_file, TRUE, FALSE, FALSE, pool)); - SVN_ERR(svn_cache__make_memcache_from_config(&memcache, config, pool)); + SVN_ERR(svn_cache__make_memcache_from_config(&memcache, config, + pool, pool)); } if (! memcache) @@ -316,10 +354,80 @@ test_memcache_long_key(const svn_test_opts_t *opts, return SVN_NO_ERROR; } +static svn_error_t * +test_membuffer_cache_clearing(apr_pool_t *pool) +{ + svn_cache__t *cache; + svn_membuffer_t *membuffer; + svn_boolean_t found; + svn_revnum_t *value; + svn_revnum_t valueA = 12345; + svn_revnum_t valueB = 67890; + + /* Create a simple cache for strings, keyed by strings. */ + SVN_ERR(svn_cache__membuffer_cache_create(&membuffer, 10*1024, 1, 0, + TRUE, TRUE, pool)); + SVN_ERR(svn_cache__create_membuffer_cache(&cache, + membuffer, + serialize_revnum, + deserialize_revnum, + APR_HASH_KEY_STRING, + "cache:", + SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY, + FALSE, + pool, pool)); + + /* Initially, the cache is empty. */ + SVN_ERR(svn_cache__get((void **) &value, &found, cache, "key A", pool)); + SVN_TEST_ASSERT(!found); + SVN_ERR(svn_cache__get((void **) &value, &found, cache, "key B", pool)); + SVN_TEST_ASSERT(!found); + SVN_ERR(svn_cache__get((void **) &value, &found, cache, "key C", pool)); + SVN_TEST_ASSERT(!found); + + /* Add entries. */ + SVN_ERR(svn_cache__set(cache, "key A", &valueA, pool)); + SVN_ERR(svn_cache__set(cache, "key B", &valueB, pool)); + + /* Added entries should be cached (too small to get evicted already). */ + SVN_ERR(svn_cache__get((void **) &value, &found, cache, "key A", pool)); + SVN_TEST_ASSERT(found); + SVN_TEST_ASSERT(*value == valueA); + SVN_ERR(svn_cache__get((void **) &value, &found, cache, "key B", pool)); + SVN_TEST_ASSERT(found); + SVN_TEST_ASSERT(*value == valueB); + SVN_ERR(svn_cache__get((void **) &value, &found, cache, "key C", pool)); + SVN_TEST_ASSERT(!found); + + /* Clear the cache. */ + SVN_ERR(svn_cache__membuffer_clear(membuffer)); + + /* The cache is empty again. */ + SVN_ERR(svn_cache__get((void **) &value, &found, cache, "key A", pool)); + SVN_TEST_ASSERT(!found); + SVN_ERR(svn_cache__get((void **) &value, &found, cache, "key B", pool)); + SVN_TEST_ASSERT(!found); + SVN_ERR(svn_cache__get((void **) &value, &found, cache, "key C", pool)); + SVN_TEST_ASSERT(!found); + + /* But still functional: */ + SVN_ERR(svn_cache__set(cache, "key B", &valueB, pool)); + SVN_ERR(svn_cache__has_key(&found, cache, "key A", pool)); + SVN_TEST_ASSERT(!found); + SVN_ERR(svn_cache__has_key(&found, cache, "key B", pool)); + SVN_TEST_ASSERT(found); + SVN_ERR(svn_cache__has_key(&found, cache, "key C", pool)); + SVN_TEST_ASSERT(!found); + + return SVN_NO_ERROR; +} + /* The test table. */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_inprocess_cache_basic, @@ -332,5 +440,9 @@ struct svn_test_descriptor_t test_funcs[] = "basic membuffer svn_cache test"), SVN_TEST_PASS2(test_membuffer_serializer_error_handling, "test for error handling in membuffer svn_cache"), + SVN_TEST_PASS2(test_membuffer_cache_clearing, + "test clearing a membuffer svn_cache"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/checksum-test.c b/subversion/tests/libsvn_subr/checksum-test.c index c5e2409..4c6d993 100644 --- a/subversion/tests/libsvn_subr/checksum-test.c +++ b/subversion/tests/libsvn_subr/checksum-test.c @@ -27,38 +27,47 @@ #include "svn_error.h" #include "svn_io.h" -#include "private/svn_pseudo_md5.h" #include "../svn_test.h" +/* Verify that DIGEST of checksum type KIND can be parsed and + * converted back to a string matching DIGEST. NAME will be used + * to identify the type of checksum in error messages. + */ static svn_error_t * -test_checksum_parse(apr_pool_t *pool) +checksum_parse_kind(const char *digest, + svn_checksum_kind_t kind, + const char *name, + apr_pool_t *pool) { - const char *md5_digest = "8518b76f7a45fe4de2d0955085b41f98"; - const char *sha1_digest = "74d82379bcc6771454377db03b912c2b62704139"; const char *checksum_display; svn_checksum_t *checksum; - SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_md5, md5_digest, pool)); + SVN_ERR(svn_checksum_parse_hex(&checksum, kind, digest, pool)); checksum_display = svn_checksum_to_cstring_display(checksum, pool); - if (strcmp(checksum_display, md5_digest) != 0) + if (strcmp(checksum_display, digest) != 0) return svn_error_createf (SVN_ERR_CHECKSUM_MISMATCH, NULL, - "verify-checksum: md5 checksum mismatch:\n" + "verify-checksum: %s checksum mismatch:\n" " expected: %s\n" - " actual: %s\n", md5_digest, checksum_display); + " actual: %s\n", name, digest, checksum_display); - SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_sha1, sha1_digest, - pool)); - checksum_display = svn_checksum_to_cstring_display(checksum, pool); + return SVN_NO_ERROR; +} - if (strcmp(checksum_display, sha1_digest) != 0) - return svn_error_createf - (SVN_ERR_CHECKSUM_MISMATCH, NULL, - "verify-checksum: sha1 checksum mismatch:\n" - " expected: %s\n" - " actual: %s\n", sha1_digest, checksum_display); +static svn_error_t * +test_checksum_parse(apr_pool_t *pool) +{ + SVN_ERR(checksum_parse_kind("8518b76f7a45fe4de2d0955085b41f98", + svn_checksum_md5, "md5", pool)); + SVN_ERR(checksum_parse_kind("74d82379bcc6771454377db03b912c2b62704139", + svn_checksum_sha1, "sha1", pool)); + SVN_ERR(checksum_parse_kind("deadbeef", + svn_checksum_fnv1a_32, "fnv-1a", pool)); + SVN_ERR(checksum_parse_kind("cafeaffe", + svn_checksum_fnv1a_32x4, + "modified fnv-1a", pool)); return SVN_NO_ERROR; } @@ -66,94 +75,97 @@ test_checksum_parse(apr_pool_t *pool) static svn_error_t * test_checksum_empty(apr_pool_t *pool) { - svn_checksum_t *checksum; - char data = '\0'; - - checksum = svn_checksum_empty_checksum(svn_checksum_md5, pool); - SVN_TEST_ASSERT(svn_checksum_is_empty_checksum(checksum)); - - checksum = svn_checksum_empty_checksum(svn_checksum_sha1, pool); - SVN_TEST_ASSERT(svn_checksum_is_empty_checksum(checksum)); + svn_checksum_kind_t kind; + for (kind = svn_checksum_md5; kind <= svn_checksum_fnv1a_32x4; ++kind) + { + svn_checksum_t *checksum; + char data = '\0'; - SVN_ERR(svn_checksum(&checksum, svn_checksum_md5, &data, 0, pool)); - SVN_TEST_ASSERT(svn_checksum_is_empty_checksum(checksum)); + checksum = svn_checksum_empty_checksum(kind, pool); + SVN_TEST_ASSERT(svn_checksum_is_empty_checksum(checksum)); - SVN_ERR(svn_checksum(&checksum, svn_checksum_sha1, &data, 0, pool)); - SVN_TEST_ASSERT(svn_checksum_is_empty_checksum(checksum)); + SVN_ERR(svn_checksum(&checksum, kind, &data, 0, pool)); + SVN_TEST_ASSERT(svn_checksum_is_empty_checksum(checksum)); + } return SVN_NO_ERROR; } +/* Verify that "zero" checksums work properly for the given checksum KIND. + */ static svn_error_t * -test_pseudo_md5(apr_pool_t *pool) +zero_match_kind(svn_checksum_kind_t kind, apr_pool_t *pool) { - apr_uint32_t input[16] = { 0 }; - apr_uint32_t digest_15[4] = { 0 }; - apr_uint32_t digest_31[4] = { 0 }; - apr_uint32_t digest_63[4] = { 0 }; - svn_checksum_t *checksum; + svn_checksum_t *zero; + svn_checksum_t *A; + svn_checksum_t *B; - /* input is all 0s but the hash shall be different - (due to different input sizes)*/ - svn__pseudo_md5_15(digest_15, input); - svn__pseudo_md5_31(digest_31, input); - svn__pseudo_md5_63(digest_63, input); + zero = svn_checksum_create(kind, pool); + SVN_ERR(svn_checksum_clear(zero)); + SVN_ERR(svn_checksum(&A, kind, "A", 1, pool)); + SVN_ERR(svn_checksum(&B, kind, "B", 1, pool)); - SVN_TEST_ASSERT(memcmp(digest_15, digest_31, sizeof(digest_15))); - SVN_TEST_ASSERT(memcmp(digest_15, digest_63, sizeof(digest_15))); - SVN_TEST_ASSERT(memcmp(digest_31, digest_63, sizeof(digest_15))); + /* Different non-zero don't match. */ + SVN_TEST_ASSERT(!svn_checksum_match(A, B)); - /* the checksums shall also be different from "proper" MD5 */ - SVN_ERR(svn_checksum(&checksum, svn_checksum_md5, input, 15, pool)); - SVN_TEST_ASSERT(memcmp(digest_15, checksum->digest, sizeof(digest_15))); + /* Zero matches anything of the same kind. */ + SVN_TEST_ASSERT(svn_checksum_match(A, zero)); + SVN_TEST_ASSERT(svn_checksum_match(zero, B)); - SVN_ERR(svn_checksum(&checksum, svn_checksum_md5, input, 31, pool)); - SVN_TEST_ASSERT(memcmp(digest_31, checksum->digest, sizeof(digest_15))); + return SVN_NO_ERROR; +} - SVN_ERR(svn_checksum(&checksum, svn_checksum_md5, input, 63, pool)); - SVN_TEST_ASSERT(memcmp(digest_63, checksum->digest, sizeof(digest_15))); +static svn_error_t * +zero_match(apr_pool_t *pool) +{ + svn_checksum_kind_t kind; + for (kind = svn_checksum_md5; kind <= svn_checksum_fnv1a_32x4; ++kind) + SVN_ERR(zero_match_kind(kind, pool)); return SVN_NO_ERROR; } static svn_error_t * -zero_match(apr_pool_t *pool) +zero_cross_match(apr_pool_t *pool) { - svn_checksum_t *zero_md5; - svn_checksum_t *zero_sha1; - svn_checksum_t *A_md5; - svn_checksum_t *B_md5; - svn_checksum_t *A_sha1; - svn_checksum_t *B_sha1; + svn_checksum_kind_t i_kind; + svn_checksum_kind_t k_kind; + for (i_kind = svn_checksum_md5; + i_kind <= svn_checksum_fnv1a_32x4; + ++i_kind) + { + svn_checksum_t *i_zero; + svn_checksum_t *i_A; - zero_md5 = svn_checksum_create(svn_checksum_md5, pool); - SVN_ERR(svn_checksum_clear(zero_md5)); - SVN_ERR(svn_checksum(&A_md5, svn_checksum_md5, "A", 1, pool)); - SVN_ERR(svn_checksum(&B_md5, svn_checksum_md5, "B", 1, pool)); + i_zero = svn_checksum_create(i_kind, pool); + SVN_ERR(svn_checksum_clear(i_zero)); + SVN_ERR(svn_checksum(&i_A, i_kind, "A", 1, pool)); - zero_sha1 = svn_checksum_create(svn_checksum_sha1, pool); - SVN_ERR(svn_checksum_clear(zero_sha1)); - SVN_ERR(svn_checksum(&A_sha1, svn_checksum_sha1, "A", 1, pool)); - SVN_ERR(svn_checksum(&B_sha1, svn_checksum_sha1, "B", 1, pool)); + for (k_kind = svn_checksum_md5; + k_kind <= svn_checksum_fnv1a_32x4; + ++k_kind) + { + svn_checksum_t *k_zero; + svn_checksum_t *k_A; + if (i_kind == k_kind) + continue; - /* Different non-zero don't match. */ - SVN_TEST_ASSERT(!svn_checksum_match(A_md5, B_md5)); - SVN_TEST_ASSERT(!svn_checksum_match(A_sha1, B_sha1)); - SVN_TEST_ASSERT(!svn_checksum_match(A_md5, A_sha1)); - SVN_TEST_ASSERT(!svn_checksum_match(A_md5, B_sha1)); + k_zero = svn_checksum_create(k_kind, pool); + SVN_ERR(svn_checksum_clear(k_zero)); + SVN_ERR(svn_checksum(&k_A, k_kind, "A", 1, pool)); - /* Zero matches anything of the same kind. */ - SVN_TEST_ASSERT(svn_checksum_match(A_md5, zero_md5)); - SVN_TEST_ASSERT(svn_checksum_match(zero_md5, B_md5)); - SVN_TEST_ASSERT(svn_checksum_match(A_sha1, zero_sha1)); - SVN_TEST_ASSERT(svn_checksum_match(zero_sha1, B_sha1)); + /* Different non-zero don't match. */ + SVN_TEST_ASSERT(!svn_checksum_match(i_A, k_A)); + + /* Zero doesn't match anything of a different kind... */ + SVN_TEST_ASSERT(!svn_checksum_match(i_zero, k_A)); + SVN_TEST_ASSERT(!svn_checksum_match(i_A, k_zero)); - /* Zero doesn't match anything of a different kind... */ - SVN_TEST_ASSERT(!svn_checksum_match(zero_md5, A_sha1)); - SVN_TEST_ASSERT(!svn_checksum_match(zero_sha1, A_md5)); - /* ...even another zero. */ - SVN_TEST_ASSERT(!svn_checksum_match(zero_md5, zero_sha1)); + /* ...even another zero. */ + SVN_TEST_ASSERT(!svn_checksum_match(i_zero, k_zero)); + } + } return SVN_NO_ERROR; } @@ -163,12 +175,14 @@ zlib_expansion_test(const svn_test_opts_t *opts, apr_pool_t *pool) { const char *data_path; + const char *srcdir; svn_stringbuf_t *deflated; Byte dst_buffer[256 * 1024]; Byte *src_buffer; - apr_size_t sz; + uInt sz; - data_path = svn_dirent_join(opts->srcdir, "zlib.deflated", pool); + SVN_ERR(svn_test_get_srcdir(&srcdir, opts, pool)); + data_path = svn_dirent_join(srcdir, "zlib.deflated", pool); SVN_ERR(svn_stringbuf_from_file2(&deflated, data_path, pool)); src_buffer = (Byte*)deflated->data; @@ -177,6 +191,7 @@ zlib_expansion_test(const svn_test_opts_t *opts, for (sz = 1; sz < 256; sz++) { z_stream stream; + uLong crc = crc32(0, Z_NULL, 0); memset(&stream, 0, sizeof(stream)); inflateInit2(&stream, -15 /* DEFLATE_WINDOW_SIZE */); @@ -193,12 +208,15 @@ zlib_expansion_test(const svn_test_opts_t *opts, { return svn_error_createf( SVN_ERR_TEST_FAILED, NULL, - "Failure decompressing with blocksize %d", (int)sz); + "Failure decompressing with blocksize %u", sz); } + crc = crc32(crc, dst_buffer, sizeof(dst_buffer) - stream.avail_out); + stream.avail_out = sizeof(dst_buffer); + stream.next_out = dst_buffer; stream.avail_in += sz; } while (stream.next_in + stream.avail_in < src_buffer + deflated->len); - stream.avail_in = (src_buffer + deflated->len) - stream.next_in; + stream.avail_in = (uInt) (deflated->len - stream.total_in); { int zr = inflate(&stream, Z_NO_FLUSH); @@ -207,8 +225,9 @@ zlib_expansion_test(const svn_test_opts_t *opts, { return svn_error_createf( SVN_ERR_TEST_FAILED, NULL, - "Final flush failed with blocksize %d", (int)sz); + "Final flush failed with blocksize %u", sz); } + crc = crc32(crc, dst_buffer, sizeof(dst_buffer) - stream.avail_out); zr = inflateEnd(&stream); @@ -216,42 +235,65 @@ zlib_expansion_test(const svn_test_opts_t *opts, { return svn_error_createf( SVN_ERR_TEST_FAILED, NULL, - "End of stream handling failed with blocksize %d", - (int)sz); + "End of stream handling failed with blocksize %u", + sz); } } - { - apr_uint32_t crc = crc32(0, dst_buffer, stream.total_out); - - if (stream.total_out != 242014 || crc != 0x8f03d934) - { - return svn_error_createf( - SVN_ERR_TEST_FAILED, NULL, - "Decompressed data doesn't match expected size or crc with " - "blocksize %d: Found crc32=0x%08x, size=%d.\n" - "Verify your ZLib installation, as this should never happen", - (int)sz, (unsigned)crc, (int)stream.total_out); - } - } + if (stream.total_out != 242014 || crc != 0x8f03d934) + { + return svn_error_createf( + SVN_ERR_TEST_FAILED, NULL, + "Decompressed data doesn't match expected size or crc with " + "blocksize %u: Found crc32=0x%08lx, size=%lu.\n" + "Verify your ZLib installation, as this should never happen", + sz, crc, stream.total_out); + } } return SVN_NO_ERROR; } +static svn_error_t * +test_serialization(apr_pool_t *pool) +{ + svn_checksum_kind_t kind; + for (kind = svn_checksum_md5; kind <= svn_checksum_fnv1a_32x4; ++kind) + { + const svn_checksum_t *parsed_checksum; + svn_checksum_t *checksum = svn_checksum_empty_checksum(kind, pool); + const char *serialized = svn_checksum_serialize(checksum, pool, pool); + + SVN_ERR(svn_checksum_deserialize(&parsed_checksum, serialized, pool, + pool)); + + SVN_TEST_ASSERT(parsed_checksum->kind == kind); + SVN_TEST_ASSERT(svn_checksum_match(checksum, parsed_checksum)); + } + + return SVN_NO_ERROR; +} + /* An array of all test functions */ -struct svn_test_descriptor_t test_funcs[] = + +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_checksum_parse, "checksum parse"), SVN_TEST_PASS2(test_checksum_empty, "checksum emptiness"), - SVN_TEST_PASS2(test_pseudo_md5, - "pseudo-md5 compatibility"), SVN_TEST_PASS2(zero_match, "zero checksum matching"), SVN_TEST_OPTS_PASS(zlib_expansion_test, "zlib expansion test (zlib regression)"), + SVN_TEST_PASS2(zero_cross_match, + "zero checksum cross-type matching"), + SVN_TEST_PASS2(test_serialization, + "checksum (de-)serialization"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/compat-test.c b/subversion/tests/libsvn_subr/compat-test.c index 9ff8099..8414847 100644 --- a/subversion/tests/libsvn_subr/compat-test.c +++ b/subversion/tests/libsvn_subr/compat-test.c @@ -209,7 +209,10 @@ test_version_at_least(apr_pool_t *pool) } /* An array of all test functions */ -struct svn_test_descriptor_t test_funcs[] = + +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_version_compatibility, @@ -220,3 +223,5 @@ struct svn_test_descriptor_t test_funcs[] = "svn_version__at_least"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/config-test.c b/subversion/tests/libsvn_subr/config-test.c index 8938457..919893e 100644 --- a/subversion/tests/libsvn_subr/config-test.c +++ b/subversion/tests/libsvn_subr/config-test.c @@ -33,48 +33,14 @@ #include <apr_getopt.h> #include <apr_pools.h> +#include "svn_dirent_uri.h" #include "svn_error.h" #include "svn_config.h" +#include "private/svn_subr_private.h" #include "../svn_test.h" -/* Initialize parameters for the tests. */ -extern int test_argc; -extern const char **test_argv; - -static const apr_getopt_option_t opt_def[] = - { - {"srcdir", 'S', 1, "the source directory for VPATH test runs"}, - {0, 0, 0, 0} - }; -static const char *srcdir = NULL; - -static svn_error_t *init_params(apr_pool_t *pool) -{ - apr_getopt_t *opt; - int optch; - const char *opt_arg; - apr_status_t status; - - apr_getopt_init(&opt, pool, test_argc, test_argv); - while (!(status = apr_getopt_long(opt, opt_def, &optch, &opt_arg))) - { - switch (optch) - { - case 'S': - srcdir = opt_arg; - break; - } - } - - if (!srcdir) - return svn_error_create(SVN_ERR_TEST_FAILED, 0, - "missing required parameter '--srcdir'"); - - return SVN_NO_ERROR; -} - /* A quick way to create error messages. */ static svn_error_t * fail(apr_pool_t *pool, const char *fmt, ...) @@ -89,6 +55,18 @@ fail(apr_pool_t *pool, const char *fmt, ...) return svn_error_create(SVN_ERR_TEST_FAILED, SVN_NO_ERROR, msg); } +static svn_error_t * +get_config_file_path(const char **cfg_file, + const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + const char *srcdir; + + SVN_ERR(svn_test_get_srcdir(&srcdir, opts, pool)); + *cfg_file = svn_dirent_join(srcdir, "config-test.cfg", pool); + + return SVN_NO_ERROR; +} static const char *config_keys[] = { "foo", "a", "b", "c", "d", "e", "f", "g", "h", "i", NULL }; @@ -99,16 +77,14 @@ static const char *config_values[] = { "bar", "Aa", "100", "bar", "Aa 100", NULL }; static svn_error_t * -test_text_retrieval(apr_pool_t *pool) +test_text_retrieval(const svn_test_opts_t *opts, + apr_pool_t *pool) { svn_config_t *cfg; int i; const char *cfg_file; - if (!srcdir) - SVN_ERR(init_params(pool)); - - cfg_file = apr_pstrcat(pool, srcdir, "/", "config-test.cfg", (char *)NULL); + SVN_ERR(get_config_file_path(&cfg_file, opts, pool)); SVN_ERR(svn_config_read3(&cfg, cfg_file, TRUE, FALSE, FALSE, pool)); /* Test values retrieved from our ConfigParser instance against @@ -150,16 +126,14 @@ static const char *false_keys[] = {"false1", "false2", "false3", "false4", NULL}; static svn_error_t * -test_boolean_retrieval(apr_pool_t *pool) +test_boolean_retrieval(const svn_test_opts_t *opts, + apr_pool_t *pool) { svn_config_t *cfg; int i; const char *cfg_file; - if (!srcdir) - SVN_ERR(init_params(pool)); - - cfg_file = apr_pstrcat(pool, srcdir, "/", "config-test.cfg", (char *)NULL); + SVN_ERR(get_config_file_path(&cfg_file, opts, pool)); SVN_ERR(svn_config_read3(&cfg, cfg_file, TRUE, FALSE, FALSE, pool)); for (i = 0; true_keys[i] != NULL; i++) @@ -211,15 +185,13 @@ test_boolean_retrieval(apr_pool_t *pool) } static svn_error_t * -test_has_section_case_insensitive(apr_pool_t *pool) +test_has_section_case_insensitive(const svn_test_opts_t *opts, + apr_pool_t *pool) { svn_config_t *cfg; const char *cfg_file; - if (!srcdir) - SVN_ERR(init_params(pool)); - - cfg_file = apr_pstrcat(pool, srcdir, "/", "config-test.cfg", (char *)NULL); + SVN_ERR(get_config_file_path(&cfg_file, opts, pool)); SVN_ERR(svn_config_read3(&cfg, cfg_file, TRUE, FALSE, FALSE, pool)); if (! svn_config_has_section(cfg, "section1")) @@ -241,15 +213,13 @@ test_has_section_case_insensitive(apr_pool_t *pool) } static svn_error_t * -test_has_section_case_sensitive(apr_pool_t *pool) +test_has_section_case_sensitive(const svn_test_opts_t *opts, + apr_pool_t *pool) { svn_config_t *cfg; const char *cfg_file; - if (!srcdir) - SVN_ERR(init_params(pool)); - - cfg_file = apr_pstrcat(pool, srcdir, "/", "config-test.cfg", (char *)NULL); + SVN_ERR(get_config_file_path(&cfg_file, opts, pool)); SVN_ERR(svn_config_read3(&cfg, cfg_file, TRUE, TRUE, FALSE, pool)); if (! svn_config_has_section(cfg, "section1")) @@ -271,7 +241,8 @@ test_has_section_case_sensitive(apr_pool_t *pool) } static svn_error_t * -test_has_option_case_sensitive(apr_pool_t *pool) +test_has_option_case_sensitive(const svn_test_opts_t *opts, + apr_pool_t *pool) { svn_config_t *cfg; const char *cfg_file; @@ -289,10 +260,7 @@ test_has_option_case_sensitive(apr_pool_t *pool) }; static const int test_data_size = sizeof(test_data)/sizeof(*test_data); - if (!srcdir) - SVN_ERR(init_params(pool)); - - cfg_file = apr_pstrcat(pool, srcdir, "/", "config-test.cfg", (char *)NULL); + SVN_ERR(get_config_file_path(&cfg_file, opts, pool)); SVN_ERR(svn_config_read3(&cfg, cfg_file, TRUE, TRUE, TRUE, pool)); for (i = 0; i < test_data_size; ++i) @@ -313,16 +281,14 @@ test_has_option_case_sensitive(apr_pool_t *pool) } static svn_error_t * -test_stream_interface(apr_pool_t *pool) +test_stream_interface(const svn_test_opts_t *opts, + apr_pool_t *pool) { svn_config_t *cfg; const char *cfg_file; svn_stream_t *stream; - if (!srcdir) - SVN_ERR(init_params(pool)); - - cfg_file = apr_pstrcat(pool, srcdir, "/", "config-test.cfg", (char *)NULL); + SVN_ERR(get_config_file_path(&cfg_file, opts, pool)); SVN_ERR(svn_stream_open_readonly(&stream, cfg_file, pool, pool)); SVN_ERR(svn_config_parse(&cfg, stream, TRUE, TRUE, pool)); @@ -353,16 +319,42 @@ test_ignore_bom(apr_pool_t *pool) } static svn_error_t * +test_read_only_mode(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_config_t *cfg; + svn_config_t *cfg2; + const char *cfg_file; + + SVN_ERR(get_config_file_path(&cfg_file, opts, pool)); + SVN_ERR(svn_config_read3(&cfg, cfg_file, TRUE, TRUE, FALSE, pool)); + + /* setting CFG to r/o mode shall toggle the r/o mode and expand values */ + + SVN_TEST_ASSERT(!svn_config__is_read_only(cfg)); + SVN_TEST_ASSERT(!svn_config__is_expanded(cfg, "section1", "i")); + + svn_config__set_read_only(cfg, pool); + + SVN_TEST_ASSERT(svn_config__is_read_only(cfg)); + SVN_TEST_ASSERT(svn_config__is_expanded(cfg, "section1", "i")); + + /* copies should be r/w with values */ + + SVN_ERR(svn_config_dup(&cfg2, cfg, pool)); + SVN_TEST_ASSERT(!svn_config__is_read_only(cfg2)); + + return SVN_NO_ERROR; +} + +static svn_error_t * test_expand(const svn_test_opts_t *opts, apr_pool_t *pool) { svn_config_t *cfg; const char *cfg_file, *val; - if (!srcdir) - SVN_ERR(init_params(pool)); - - cfg_file = apr_pstrcat(pool, srcdir, "/", "config-test.cfg", (char *)NULL); + SVN_ERR(get_config_file_path(&cfg_file, opts, pool)); SVN_ERR(svn_config_read3(&cfg, cfg_file, TRUE, TRUE, FALSE, pool)); /* Get expanded "g" which requires expanding "c". */ @@ -371,13 +363,34 @@ test_expand(const svn_test_opts_t *opts, /* Get expanded "c". */ svn_config_get(cfg, &val, "section1", "c", NULL); - /* With pool debugging enabled this ensures that the expanded value + /* With pool debugging enabled this ensures that the expanded value of "c" was not created in a temporary pool when expanding "g". */ SVN_TEST_STRING_ASSERT(val, "bar"); return SVN_NO_ERROR; } +static svn_error_t * +test_invalid_bom(apr_pool_t *pool) +{ + svn_config_t *cfg; + svn_error_t *err; + svn_string_t *cfg_string; + svn_stream_t *stream; + + cfg_string = svn_string_create("\xEF", pool); + stream = svn_stream_from_string(cfg_string, pool); + err = svn_config_parse(&cfg, stream, TRUE, TRUE, pool); + SVN_TEST_ASSERT_ERROR(err, SVN_ERR_MALFORMED_FILE); + + cfg_string = svn_string_create("\xEF\xBB", pool); + stream = svn_stream_from_string(cfg_string, pool); + err = svn_config_parse(&cfg, stream, TRUE, TRUE, pool); + SVN_TEST_ASSERT_ERROR(err, SVN_ERR_MALFORMED_FILE); + + return SVN_NO_ERROR; +} + /* ==================================================================== If you add a new test to this file, update this array. @@ -386,23 +399,33 @@ test_expand(const svn_test_opts_t *opts, */ /* An array of all test functions */ -struct svn_test_descriptor_t test_funcs[] = + +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, - SVN_TEST_PASS2(test_text_retrieval, - "test svn_config"), - SVN_TEST_PASS2(test_boolean_retrieval, - "test svn_config boolean conversion"), - SVN_TEST_PASS2(test_has_section_case_insensitive, - "test svn_config_has_section (case insensitive)"), - SVN_TEST_PASS2(test_has_section_case_sensitive, - "test svn_config_has_section (case sensitive)"), - SVN_TEST_PASS2(test_has_option_case_sensitive, - "test case-sensitive option name lookup"), - SVN_TEST_PASS2(test_stream_interface, - "test svn_config_parse"), - SVN_TEST_PASS2(test_ignore_bom, "test parsing config file with BOM"), + SVN_TEST_OPTS_PASS(test_text_retrieval, + "test svn_config"), + SVN_TEST_OPTS_PASS(test_boolean_retrieval, + "test svn_config boolean conversion"), + SVN_TEST_OPTS_PASS(test_has_section_case_insensitive, + "test svn_config_has_section (case insensitive)"), + SVN_TEST_OPTS_PASS(test_has_section_case_sensitive, + "test svn_config_has_section (case sensitive)"), + SVN_TEST_OPTS_PASS(test_has_option_case_sensitive, + "test case-sensitive option name lookup"), + SVN_TEST_OPTS_PASS(test_stream_interface, + "test svn_config_parse"), + SVN_TEST_PASS2(test_ignore_bom, + "test parsing config file with BOM"), + SVN_TEST_OPTS_PASS(test_read_only_mode, + "test r/o mode"), SVN_TEST_OPTS_PASS(test_expand, "test variable expansion"), + SVN_TEST_PASS2(test_invalid_bom, + "test parsing config file with invalid BOM"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/crypto-test.c b/subversion/tests/libsvn_subr/crypto-test.c index 0c52804..91fd6c7 100644 --- a/subversion/tests/libsvn_subr/crypto-test.c +++ b/subversion/tests/libsvn_subr/crypto-test.c @@ -177,7 +177,9 @@ test_passphrase_check(apr_pool_t *pool) /* The test table. */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = -1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_encrypt_decrypt_password, @@ -186,3 +188,5 @@ struct svn_test_descriptor_t test_funcs[] = "password checktext generation/validation"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/dirent_uri-test.c b/subversion/tests/libsvn_subr/dirent_uri-test.c index 992d288..61d9e24 100644 --- a/subversion/tests/libsvn_subr/dirent_uri-test.c +++ b/subversion/tests/libsvn_subr/dirent_uri-test.c @@ -270,7 +270,7 @@ test_dirent_join(apr_pool_t *pool) "\"%s\". expected \"%s\"", base, comp, result, expect); - result = svn_dirent_join_many(pool, base, comp, NULL); + result = svn_dirent_join_many(pool, base, comp, SVN_VA_NULL); if (strcmp(result, expect)) return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, "svn_dirent_join_many(\"%s\", \"%s\") returned " @@ -286,72 +286,72 @@ test_dirent_join(apr_pool_t *pool) "expected \"%s\"", \ result, expect); - TEST_MANY((pool, "abc", NULL), "abc"); - TEST_MANY((pool, "/abc", NULL), "/abc"); - TEST_MANY((pool, "/", NULL), "/"); - - TEST_MANY((pool, "abc", "def", "ghi", NULL), "abc/def/ghi"); - TEST_MANY((pool, "abc", "/def", "ghi", NULL), "/def/ghi"); - TEST_MANY((pool, "/abc", "def", "ghi", NULL), "/abc/def/ghi"); - TEST_MANY((pool, "abc", "def", "/ghi", NULL), "/ghi"); - TEST_MANY((pool, "/", "def", "/ghi", NULL), "/ghi"); - TEST_MANY((pool, "/", "/def", "/ghi", NULL), "/ghi"); - - TEST_MANY((pool, SVN_EMPTY_PATH, "def", "ghi", NULL), "def/ghi"); - TEST_MANY((pool, "abc", SVN_EMPTY_PATH, "ghi", NULL), "abc/ghi"); - TEST_MANY((pool, "abc", "def", SVN_EMPTY_PATH, NULL), "abc/def"); - TEST_MANY((pool, SVN_EMPTY_PATH, "def", SVN_EMPTY_PATH, NULL), "def"); - TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "ghi", NULL), "ghi"); - TEST_MANY((pool, "abc", SVN_EMPTY_PATH, SVN_EMPTY_PATH, NULL), "abc"); - TEST_MANY((pool, SVN_EMPTY_PATH, "def", "/ghi", NULL), "/ghi"); - TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "/ghi", NULL), "/ghi"); - - TEST_MANY((pool, "/", "def", "ghi", NULL), "/def/ghi"); - TEST_MANY((pool, "abc", "/", "ghi", NULL), "/ghi"); - TEST_MANY((pool, "abc", "def", "/", NULL), "/"); - TEST_MANY((pool, "/", "/", "ghi", NULL), "/ghi"); - TEST_MANY((pool, "/", "/", "/", NULL), "/"); - TEST_MANY((pool, "/", SVN_EMPTY_PATH, "ghi", NULL), "/ghi"); - TEST_MANY((pool, "/", "def", SVN_EMPTY_PATH, NULL), "/def"); - TEST_MANY((pool, SVN_EMPTY_PATH, "/", "ghi", NULL), "/ghi"); - TEST_MANY((pool, "/", SVN_EMPTY_PATH, SVN_EMPTY_PATH, NULL), "/"); - TEST_MANY((pool, SVN_EMPTY_PATH, "/", SVN_EMPTY_PATH, NULL), "/"); - TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "/", NULL), "/"); + TEST_MANY((pool, "abc", SVN_VA_NULL), "abc"); + TEST_MANY((pool, "/abc", SVN_VA_NULL), "/abc"); + TEST_MANY((pool, "/", SVN_VA_NULL), "/"); + + TEST_MANY((pool, "abc", "def", "ghi", SVN_VA_NULL), "abc/def/ghi"); + TEST_MANY((pool, "abc", "/def", "ghi", SVN_VA_NULL), "/def/ghi"); + TEST_MANY((pool, "/abc", "def", "ghi", SVN_VA_NULL), "/abc/def/ghi"); + TEST_MANY((pool, "abc", "def", "/ghi", SVN_VA_NULL), "/ghi"); + TEST_MANY((pool, "/", "def", "/ghi", SVN_VA_NULL), "/ghi"); + TEST_MANY((pool, "/", "/def", "/ghi", SVN_VA_NULL), "/ghi"); + + TEST_MANY((pool, SVN_EMPTY_PATH, "def", "ghi", SVN_VA_NULL), "def/ghi"); + TEST_MANY((pool, "abc", SVN_EMPTY_PATH, "ghi", SVN_VA_NULL), "abc/ghi"); + TEST_MANY((pool, "abc", "def", SVN_EMPTY_PATH, SVN_VA_NULL), "abc/def"); + TEST_MANY((pool, SVN_EMPTY_PATH, "def", SVN_EMPTY_PATH, SVN_VA_NULL), "def"); + TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "ghi", SVN_VA_NULL), "ghi"); + TEST_MANY((pool, "abc", SVN_EMPTY_PATH, SVN_EMPTY_PATH, SVN_VA_NULL), "abc"); + TEST_MANY((pool, SVN_EMPTY_PATH, "def", "/ghi", SVN_VA_NULL), "/ghi"); + TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "/ghi", SVN_VA_NULL), "/ghi"); + + TEST_MANY((pool, "/", "def", "ghi", SVN_VA_NULL), "/def/ghi"); + TEST_MANY((pool, "abc", "/", "ghi", SVN_VA_NULL), "/ghi"); + TEST_MANY((pool, "abc", "def", "/", SVN_VA_NULL), "/"); + TEST_MANY((pool, "/", "/", "ghi", SVN_VA_NULL), "/ghi"); + TEST_MANY((pool, "/", "/", "/", SVN_VA_NULL), "/"); + TEST_MANY((pool, "/", SVN_EMPTY_PATH, "ghi", SVN_VA_NULL), "/ghi"); + TEST_MANY((pool, "/", "def", SVN_EMPTY_PATH, SVN_VA_NULL), "/def"); + TEST_MANY((pool, SVN_EMPTY_PATH, "/", "ghi", SVN_VA_NULL), "/ghi"); + TEST_MANY((pool, "/", SVN_EMPTY_PATH, SVN_EMPTY_PATH, SVN_VA_NULL), "/"); + TEST_MANY((pool, SVN_EMPTY_PATH, "/", SVN_EMPTY_PATH, SVN_VA_NULL), "/"); + TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "/", SVN_VA_NULL), "/"); #ifdef SVN_USE_DOS_PATHS - TEST_MANY((pool, "X:/", "def", "ghi", NULL), "X:/def/ghi"); - TEST_MANY((pool, "abc", "X:/", "ghi", NULL), "X:/ghi"); - TEST_MANY((pool, "abc", "def", "X:/", NULL), "X:/"); - TEST_MANY((pool, "X:/", "X:/", "ghi", NULL), "X:/ghi"); - TEST_MANY((pool, "X:/", "X:/", "/", NULL), "/"); - TEST_MANY((pool, "X:/", SVN_EMPTY_PATH, "ghi", NULL), "X:/ghi"); - TEST_MANY((pool, "X:/", "def", SVN_EMPTY_PATH, NULL), "X:/def"); - TEST_MANY((pool, SVN_EMPTY_PATH, "X:/", "ghi", NULL), "X:/ghi"); - TEST_MANY((pool, "X:/", SVN_EMPTY_PATH, SVN_EMPTY_PATH, NULL), "X:/"); - TEST_MANY((pool, SVN_EMPTY_PATH, "X:/", SVN_EMPTY_PATH, NULL), "X:/"); - TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "X:/", NULL), "X:/"); - - TEST_MANY((pool, "X:", "def", "ghi", NULL), "X:def/ghi"); - TEST_MANY((pool, "X:", "X:/", "ghi", NULL), "X:/ghi"); - TEST_MANY((pool, "X:", "X:/", "/", NULL), "/"); - TEST_MANY((pool, "X:", SVN_EMPTY_PATH, "ghi", NULL), "X:ghi"); - TEST_MANY((pool, "X:", "def", SVN_EMPTY_PATH, NULL), "X:def"); - TEST_MANY((pool, SVN_EMPTY_PATH, "X:", "ghi", NULL), "X:ghi"); - TEST_MANY((pool, "//srv/shr", "def", "ghi", NULL), "//srv/shr/def/ghi"); - TEST_MANY((pool, "//srv/shr/fld", "def", "ghi", NULL), "//srv/shr/fld/def/ghi"); - TEST_MANY((pool, "//srv/shr/fld", "def", "//srv/shr", NULL), "//srv/shr"); - TEST_MANY((pool, "//srv/s r/fld", "def", "//srv/s r", NULL), "//srv/s r"); - TEST_MANY((pool, SVN_EMPTY_PATH, "//srv/shr/fld", "def", "ghi", NULL), "//srv/shr/fld/def/ghi"); - TEST_MANY((pool, SVN_EMPTY_PATH, "//srv/shr/fld", "def", "//srv/shr", NULL), "//srv/shr"); - - TEST_MANY((pool, "abcd", "/dir", "A:", "file", NULL), "A:file"); - TEST_MANY((pool, "abcd", "A:", "/dir", "file", NULL), "A:/dir/file"); + TEST_MANY((pool, "X:/", "def", "ghi", SVN_VA_NULL), "X:/def/ghi"); + TEST_MANY((pool, "abc", "X:/", "ghi", SVN_VA_NULL), "X:/ghi"); + TEST_MANY((pool, "abc", "def", "X:/", SVN_VA_NULL), "X:/"); + TEST_MANY((pool, "X:/", "X:/", "ghi", SVN_VA_NULL), "X:/ghi"); + TEST_MANY((pool, "X:/", "X:/", "/", SVN_VA_NULL), "/"); + TEST_MANY((pool, "X:/", SVN_EMPTY_PATH, "ghi", SVN_VA_NULL), "X:/ghi"); + TEST_MANY((pool, "X:/", "def", SVN_EMPTY_PATH, SVN_VA_NULL), "X:/def"); + TEST_MANY((pool, SVN_EMPTY_PATH, "X:/", "ghi", SVN_VA_NULL), "X:/ghi"); + TEST_MANY((pool, "X:/", SVN_EMPTY_PATH, SVN_EMPTY_PATH, SVN_VA_NULL), "X:/"); + TEST_MANY((pool, SVN_EMPTY_PATH, "X:/", SVN_EMPTY_PATH, SVN_VA_NULL), "X:/"); + TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "X:/", SVN_VA_NULL), "X:/"); + + TEST_MANY((pool, "X:", "def", "ghi", SVN_VA_NULL), "X:def/ghi"); + TEST_MANY((pool, "X:", "X:/", "ghi", SVN_VA_NULL), "X:/ghi"); + TEST_MANY((pool, "X:", "X:/", "/", SVN_VA_NULL), "/"); + TEST_MANY((pool, "X:", SVN_EMPTY_PATH, "ghi", SVN_VA_NULL), "X:ghi"); + TEST_MANY((pool, "X:", "def", SVN_EMPTY_PATH, SVN_VA_NULL), "X:def"); + TEST_MANY((pool, SVN_EMPTY_PATH, "X:", "ghi", SVN_VA_NULL), "X:ghi"); + TEST_MANY((pool, "//srv/shr", "def", "ghi", SVN_VA_NULL), "//srv/shr/def/ghi"); + TEST_MANY((pool, "//srv/shr/fld", "def", "ghi", SVN_VA_NULL), "//srv/shr/fld/def/ghi"); + TEST_MANY((pool, "//srv/shr/fld", "def", "//srv/shr", SVN_VA_NULL), "//srv/shr"); + TEST_MANY((pool, "//srv/s r/fld", "def", "//srv/s r", SVN_VA_NULL), "//srv/s r"); + TEST_MANY((pool, SVN_EMPTY_PATH, "//srv/shr/fld", "def", "ghi", SVN_VA_NULL), "//srv/shr/fld/def/ghi"); + TEST_MANY((pool, SVN_EMPTY_PATH, "//srv/shr/fld", "def", "//srv/shr", SVN_VA_NULL), "//srv/shr"); + + TEST_MANY((pool, "abcd", "/dir", "A:", "file", SVN_VA_NULL), "A:file"); + TEST_MANY((pool, "abcd", "A:", "/dir", "file", SVN_VA_NULL), "A:/dir/file"); #else /* !SVN_USE_DOS_PATHS */ - TEST_MANY((pool, "X:", "def", "ghi", NULL), "X:/def/ghi"); - TEST_MANY((pool, "X:", SVN_EMPTY_PATH, "ghi", NULL), "X:/ghi"); - TEST_MANY((pool, "X:", "def", SVN_EMPTY_PATH, NULL), "X:/def"); - TEST_MANY((pool, SVN_EMPTY_PATH, "X:", "ghi", NULL), "X:/ghi"); + TEST_MANY((pool, "X:", "def", "ghi", SVN_VA_NULL), "X:/def/ghi"); + TEST_MANY((pool, "X:", SVN_EMPTY_PATH, "ghi", SVN_VA_NULL), "X:/ghi"); + TEST_MANY((pool, "X:", "def", SVN_EMPTY_PATH, SVN_VA_NULL), "X:/def"); + TEST_MANY((pool, SVN_EMPTY_PATH, "X:", "ghi", SVN_VA_NULL), "X:/ghi"); #endif /* SVN_USE_DOS_PATHS */ /* ### probably need quite a few more tests... */ @@ -809,6 +809,9 @@ static const testcase_canonicalize_t uri_canonical_tests[] = { "http://hst/foo/../bar","http://hst/foo/../bar" }, { "http://hst/", "http://hst" }, { "http:///", "http://" }, + { "http:///example.com/", "http:///example.com" }, + { "http:////example.com/", "http:///example.com" }, + { "http://///////example.com/", "http:///example.com" }, { "https://", "https://" }, { "file:///", "file://" }, { "file://", "file://" }, @@ -1109,6 +1112,7 @@ test_relpath_is_canonical(apr_pool_t *pool) static const testcase_is_canonical_t tests[] = { { "", TRUE }, { ".", FALSE }, + { "..", TRUE }, { "/", FALSE }, { "/.", FALSE }, { "./", FALSE }, @@ -1937,13 +1941,13 @@ test_dirent_get_absolute(apr_pool_t *pool) expect_abs = expect; if (*expect == '%') - expect_abs = apr_pstrcat(pool, curdir, expect + 1, (char *)NULL); + expect_abs = apr_pstrcat(pool, curdir, expect + 1, SVN_VA_NULL); #ifdef SVN_USE_DOS_PATHS if (*expect == '@') - expect_abs = apr_pstrcat(pool, curdironc, expect + 1, NULL); + expect_abs = apr_pstrcat(pool, curdironc, expect + 1, SVN_VA_NULL); if (*expect == '$') - expect_abs = apr_pstrcat(pool, curdrive, expect + 1, NULL); + expect_abs = apr_pstrcat(pool, curdrive, expect + 1, SVN_VA_NULL); /* Remove double '/' when CWD was the root dir (E.g. C:/) */ expect_abs = svn_dirent_canonicalize(expect_abs, pool); @@ -1987,8 +1991,8 @@ test_dirent_get_absolute_from_lc_drive(apr_pool_t *pool) for (hi = apr_hash_first(pool, dirents); hi; hi = apr_hash_next(hi)) { - const char *dir = svn__apr_hash_index_key(hi); - svn_io_dirent2_t *de = svn__apr_hash_index_val(hi); + const char *dir = apr_hash_this_key(hi); + svn_io_dirent2_t *de = apr_hash_this_val(hi); if (de->kind == svn_node_dir && strcmp(dir, current_dir_on_C)) @@ -2857,7 +2861,9 @@ test_rule3(apr_pool_t *pool) /* The test table. */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_dirent_is_root, @@ -2958,3 +2964,5 @@ struct svn_test_descriptor_t test_funcs[] = "test match with RFC 6125 s. 6.4.3 Rule 3"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/error-code-test.c b/subversion/tests/libsvn_subr/error-code-test.c index e996616..8dada36 100644 --- a/subversion/tests/libsvn_subr/error-code-test.c +++ b/subversion/tests/libsvn_subr/error-code-test.c @@ -74,10 +74,14 @@ check_error_codes_unique(apr_pool_t *pool) /* The test table. */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(check_error_codes_unique, "check that error codes are unique"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/error-test.c b/subversion/tests/libsvn_subr/error-test.c index 18dacde..ea3291b 100644 --- a/subversion/tests/libsvn_subr/error-test.c +++ b/subversion/tests/libsvn_subr/error-test.c @@ -205,8 +205,12 @@ test_error_symbolic_name(apr_pool_t *pool) { SVN_ERR_WC_NOT_WORKING_COPY, "SVN_ERR_WC_NOT_WORKING_COPY" }, /* Test an implementation detail. */ { SVN_ERR_BAD_CATEGORY_START, "SVN_ERR_BAD_CONTAINING_POOL" }, +#ifdef SVN_DEBUG + { ENOENT, "ENOENT" }, + { APR_ENOPOOL, "APR_ENOPOOL" }, +#endif /* Test non-errors. */ - { 1, NULL }, + { -1, NULL }, { SVN_ERR_WC_CATEGORY_START - 1, NULL }, /* Whitebox-test exceptional cases. */ { SVN_WARNING, "SVN_WARNING" }, @@ -225,7 +229,9 @@ test_error_symbolic_name(apr_pool_t *pool) /* The test table. */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_error_root_cause, @@ -236,3 +242,5 @@ struct svn_test_descriptor_t test_funcs[] = "test svn_error_symbolic_name"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/hashdump-test.c b/subversion/tests/libsvn_subr/hashdump-test.c index a80b1c1..57a8535 100644 --- a/subversion/tests/libsvn_subr/hashdump-test.c +++ b/subversion/tests/libsvn_subr/hashdump-test.c @@ -38,9 +38,9 @@ /* Our own global variables */ -apr_hash_t *proplist, *new_proplist; +static apr_hash_t *proplist, *new_proplist; -const char *review = +static const char *review = "A forthright entrance, yet coquettish on the tongue, its deceptively\n" "fruity exterior hides the warm mahagony undercurrent that is the\n" "hallmark of Chateau Fraisant-Pitre. Connoisseurs of the region will\n" @@ -177,7 +177,10 @@ test3(apr_pool_t *pool) */ /* An array of all test functions */ -struct svn_test_descriptor_t test_funcs[] = + +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test1, @@ -188,3 +191,5 @@ struct svn_test_descriptor_t test_funcs[] = "write hash out, read back in, compare"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/io-test.c b/subversion/tests/libsvn_subr/io-test.c index 82e8630..e9de6fb 100644 --- a/subversion/tests/libsvn_subr/io-test.c +++ b/subversion/tests/libsvn_subr/io-test.c @@ -26,10 +26,14 @@ #include <stdio.h> #include <apr.h> +#include <apr_version.h> #include "svn_pools.h" #include "svn_string.h" +#include "svn_io.h" #include "private/svn_skel.h" +#include "private/svn_dep_compat.h" +#include "private/svn_io_private.h" #include "../svn_test.h" #include "../svn_test_fs.h" @@ -37,7 +41,7 @@ /* Helpers to create the test data directory. */ -#define TEST_DIR "io-test-temp" +#define TEST_DIR_PREFIX "io-test-temp" /* The definition for the test data files. */ struct test_file_definition_t @@ -64,7 +68,7 @@ struct test_file_definition_t char* created_path; }; -struct test_file_definition_t test_file_definitions[] = +static struct test_file_definition_t test_file_definitions_template[] = { {"empty", "", 0}, {"single_a", "a", 1}, @@ -119,6 +123,7 @@ struct test_file_definition_t test_file_definitions[] = static svn_error_t * create_test_file(struct test_file_definition_t* definition, + const char *testname, apr_pool_t *pool, apr_pool_t *scratch_pool) { @@ -127,6 +132,7 @@ create_test_file(struct test_file_definition_t* definition, apr_off_t midpos = definition->size / 2; svn_error_t *err = NULL; int i; + const char *test_dir = apr_pstrcat(pool, TEST_DIR_PREFIX, testname, NULL); if (definition->size < 5) SVN_ERR_ASSERT(strlen(definition->data) >= (apr_size_t)definition->size); @@ -134,9 +140,9 @@ create_test_file(struct test_file_definition_t* definition, SVN_ERR_ASSERT(strlen(definition->data) >= 5); - definition->created_path = svn_dirent_join(TEST_DIR, - definition->name, - pool); + definition->created_path = svn_dirent_join(test_dir, + definition->name, + pool); SVN_ERR(svn_io_file_open(&file_h, definition->created_path, @@ -174,37 +180,47 @@ create_test_file(struct test_file_definition_t* definition, /* Function to prepare the whole set of on-disk files to be compared. */ static svn_error_t * -create_comparison_candidates(apr_pool_t *scratch_pool) +create_comparison_candidates(struct test_file_definition_t **definitions, + const char *testname, + apr_pool_t *pool) { svn_node_kind_t kind; - apr_pool_t *iterpool = svn_pool_create(scratch_pool); + apr_pool_t *iterpool = svn_pool_create(pool); struct test_file_definition_t *candidate; svn_error_t *err = SVN_NO_ERROR; + apr_size_t count = 0; + const char *test_dir = apr_pstrcat(pool, TEST_DIR_PREFIX, + testname, NULL); /* If there's already a directory named io-test-temp, delete it. Doing things this way means that repositories stick around after a failure for postmortem analysis, but also that tests can be re-run without cleaning out the repositories created by prior runs. */ - SVN_ERR(svn_io_check_path(TEST_DIR, &kind, scratch_pool)); + SVN_ERR(svn_io_check_path(test_dir, &kind, pool)); if (kind == svn_node_dir) - SVN_ERR(svn_io_remove_dir2(TEST_DIR, TRUE, NULL, NULL, scratch_pool)); + SVN_ERR(svn_io_remove_dir2(test_dir, TRUE, NULL, NULL, pool)); else if (kind != svn_node_none) return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, "There is already a file named '%s'", - TEST_DIR); + test_dir); - SVN_ERR(svn_io_dir_make(TEST_DIR, APR_OS_DEFAULT, scratch_pool)); + SVN_ERR(svn_io_dir_make(test_dir, APR_OS_DEFAULT, pool)); - svn_test_add_dir_cleanup(TEST_DIR); + svn_test_add_dir_cleanup(test_dir); - for (candidate = test_file_definitions; + for (candidate = test_file_definitions_template; candidate->name != NULL; candidate += 1) + count++; + + *definitions = apr_pmemdup(pool, test_file_definitions_template, + (count + 1) * sizeof(**definitions)); + for (candidate = *definitions; candidate->name != NULL; candidate += 1) { svn_pool_clear(iterpool); - err = create_test_file(candidate, scratch_pool, iterpool); + err = create_test_file(candidate, testname, pool, iterpool); if (err) break; } @@ -227,8 +243,11 @@ test_two_file_size_comparison(apr_pool_t *scratch_pool) svn_error_t *err = SVN_NO_ERROR; svn_error_t *cmp_err; apr_pool_t *iterpool = svn_pool_create(scratch_pool); + struct test_file_definition_t *test_file_definitions; - SVN_ERR(create_comparison_candidates(scratch_pool)); + SVN_ERR(create_comparison_candidates(&test_file_definitions, + "test_two_file_size_comparison", + scratch_pool)); for (outer = test_file_definitions; outer->name != NULL; outer += 1) { @@ -278,8 +297,11 @@ test_two_file_content_comparison(apr_pool_t *scratch_pool) svn_error_t *err = SVN_NO_ERROR; svn_error_t *cmp_err; apr_pool_t *iterpool = svn_pool_create(scratch_pool); + struct test_file_definition_t *test_file_definitions; - SVN_ERR(create_comparison_candidates(scratch_pool)); + SVN_ERR(create_comparison_candidates(&test_file_definitions, + "test_two_file_content_comparison", + scratch_pool)); for (outer = test_file_definitions; outer->name != NULL; outer += 1) { @@ -331,8 +353,11 @@ test_three_file_size_comparison(apr_pool_t *scratch_pool) svn_error_t *err = SVN_NO_ERROR; svn_error_t *cmp_err; apr_pool_t *iterpool = svn_pool_create(scratch_pool); + struct test_file_definition_t *test_file_definitions; - SVN_ERR(create_comparison_candidates(scratch_pool)); + SVN_ERR(create_comparison_candidates(&test_file_definitions, + "test_three_file_size_comparison", + scratch_pool)); for (outer = test_file_definitions; outer->name != NULL; outer += 1) { @@ -411,8 +436,11 @@ test_three_file_content_comparison(apr_pool_t *scratch_pool) svn_error_t *err = SVN_NO_ERROR; svn_error_t *cmp_err; apr_pool_t *iterpool = svn_pool_create(scratch_pool); + struct test_file_definition_t *test_file_definitions; - SVN_ERR(create_comparison_candidates(scratch_pool)); + SVN_ERR(create_comparison_candidates(&test_file_definitions, + "test_three_file_content_comparison", + scratch_pool)); for (outer = test_file_definitions; outer->name != NULL; outer += 1) { @@ -507,10 +535,304 @@ read_length_line_shouldnt_loop(apr_pool_t *pool) return SVN_NO_ERROR; } +/* Move the read pointer in FILE to absolute position OFFSET and align + * the read buffer to multiples of BLOCK_SIZE. BUFFERED is set only if + * FILE actually uses a read buffer. Use POOL for allocations. + */ +static svn_error_t * +aligned_seek(apr_file_t *file, + apr_size_t block_size, + apr_size_t offset, + svn_boolean_t buffered, + apr_pool_t *pool) +{ + apr_off_t block_start; + apr_off_t current; + + SVN_ERR(svn_io_file_aligned_seek(file, (apr_off_t)block_size, + &block_start, (apr_off_t)offset, pool)); + + /* block start shall be aligned to multiples of block_size. + If it isn't, it must be aligned to APR's default block size(pre-1.3 APR) + */ + if (buffered) + { + SVN_TEST_ASSERT(block_start % block_size == 0); + SVN_TEST_ASSERT(offset - block_start < block_size); + } + + /* we must be at the desired offset */ + current = 0; + SVN_ERR(svn_io_file_seek(file, APR_CUR, ¤t, pool)); + SVN_TEST_ASSERT(current == (apr_off_t)offset); + + return SVN_NO_ERROR; +} + +/* Move the read pointer in FILE to absolute position OFFSET, align the + * read buffer to multiples of BLOCK_SIZE and read one byte from that + * position. Verify that it matches the CONTENTS for that offset. + * BUFFERED is set only if FILE actually uses a read buffer. + * Use POOL for allocations. + */ +static svn_error_t * +aligned_read_at(apr_file_t *file, + svn_stringbuf_t *contents, + apr_size_t block_size, + apr_size_t offset, + svn_boolean_t buffered, + apr_pool_t *pool) +{ + char c; + SVN_ERR(aligned_seek(file, block_size, offset, buffered, pool)); + + /* the data we read must match whatever we wrote there */ + SVN_ERR(svn_io_file_getc(&c, file, pool)); + SVN_TEST_ASSERT(c == contents->data[offset]); + + return SVN_NO_ERROR; +} + +/* Verify that aligned seek with the given BLOCK_SIZE works for FILE. + * CONTENTS is the data expected from FILE. BUFFERED is set only if FILE + * actually uses a read buffer. Use POOL for allocations. + */ +static svn_error_t * +aligned_read(apr_file_t *file, + svn_stringbuf_t *contents, + apr_size_t block_size, + svn_boolean_t buffered, + apr_pool_t *pool) +{ + apr_size_t i; + apr_size_t offset = 0; + const apr_size_t prime = 78427; + + /* "random" access to different offsets */ + for (i = 0, offset = prime; i < 10; ++i, offset += prime) + SVN_ERR(aligned_read_at(file, contents, block_size, + offset % contents->len, buffered, pool)); + + /* we can seek to EOF */ + SVN_ERR(aligned_seek(file, contents->len, block_size, buffered, pool)); + + /* reversed order access to all bytes */ + for (i = contents->len; i > 0; --i) + SVN_ERR(aligned_read_at(file, contents, block_size, i - 1, buffered, + pool)); + + /* forward order access to all bytes */ + for (i = 0; i < contents->len; ++i) + SVN_ERR(aligned_read_at(file, contents, block_size, i, buffered, pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +aligned_seek_test(apr_pool_t *pool) +{ + apr_size_t i; + const char *tmp_dir; + const char *tmp_file; + apr_file_t *f; + svn_stringbuf_t *contents; + const apr_size_t file_size = 100000; + + /* create a temp folder & schedule it for automatic cleanup */ + + SVN_ERR(svn_dirent_get_absolute(&tmp_dir, "aligned_seek_tmp", pool)); + SVN_ERR(svn_io_remove_dir2(tmp_dir, TRUE, NULL, NULL, pool)); + SVN_ERR(svn_io_make_dir_recursively(tmp_dir, pool)); + svn_test_add_dir_cleanup(tmp_dir); + + /* create a temp file with know contents */ + + contents = svn_stringbuf_create_ensure(file_size, pool); + for (i = 0; i < file_size; ++i) + svn_stringbuf_appendbyte(contents, (char)rand()); + + SVN_ERR(svn_io_write_unique(&tmp_file, tmp_dir, contents->data, + contents->len, + svn_io_file_del_on_pool_cleanup, pool)); + + /* now, access read data with varying alignment sizes */ + SVN_ERR(svn_io_file_open(&f, tmp_file, APR_READ | APR_BUFFERED, + APR_OS_DEFAULT, pool)); + SVN_ERR(aligned_read(f, contents, 0x1000, TRUE, pool)); /* APR default */ + SVN_ERR(aligned_read(f, contents, 0x8000, TRUE, pool)); /* "unusual" 32K */ + SVN_ERR(aligned_read(f, contents, 0x10000, TRUE, pool)); /* FSX default */ + SVN_ERR(aligned_read(f, contents, 0x100000, TRUE, pool)); /* larger than file */ + SVN_ERR(aligned_read(f, contents, 10001, TRUE, pool)); /* odd, larger than + APR default */ + SVN_ERR(aligned_read(f, contents, 1003, TRUE, pool)); /* odd, smaller than + APR default */ + SVN_ERR(svn_io_file_close(f, pool)); + + /* now, try read data with buffering disabled. + That are a special case because APR reports a buffer size of 0. */ + SVN_ERR(svn_io_file_open(&f, tmp_file, APR_READ, APR_OS_DEFAULT, pool)); + SVN_ERR(aligned_read(f, contents, 0x1000, FALSE, pool)); + SVN_ERR(aligned_read(f, contents, 0x8000, FALSE, pool)); + SVN_ERR(aligned_read(f, contents, 0x10000, FALSE, pool)); + SVN_ERR(aligned_read(f, contents, 0x100000, FALSE, pool)); + SVN_ERR(aligned_read(f, contents, 10001, FALSE, pool)); + SVN_ERR(aligned_read(f, contents, 1003, FALSE, pool)); + SVN_ERR(svn_io_file_close(f, pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +ignore_enoent(apr_pool_t *pool) +{ + const char *tmp_dir, *path; + const svn_io_dirent2_t *dirent_p; + apr_file_t *file; + + /* Create an empty directory. */ + SVN_ERR(svn_dirent_get_absolute(&tmp_dir, "ignore_enoent", pool)); + SVN_ERR(svn_io_remove_dir2(tmp_dir, TRUE, NULL, NULL, pool)); + SVN_ERR(svn_io_make_dir_recursively(tmp_dir, pool)); + svn_test_add_dir_cleanup(tmp_dir); + + /* Path does not exist. */ + path = svn_dirent_join(tmp_dir, "not-present", pool); + SVN_ERR(svn_io_remove_dir2(path, TRUE, NULL, NULL, pool)); + SVN_ERR(svn_io_remove_file2(path, TRUE, pool)); + SVN_ERR(svn_io_set_file_read_only(path, TRUE, pool)); + SVN_ERR(svn_io_set_file_read_write(path, TRUE, pool)); + SVN_ERR(svn_io_set_file_executable(path, TRUE, TRUE, pool)); + SVN_ERR(svn_io_set_file_executable(path, FALSE, TRUE, pool)); + SVN_ERR(svn_io_stat_dirent2(&dirent_p, path, TRUE, TRUE, pool, pool)); + SVN_ERR(svn_io_stat_dirent2(&dirent_p, path, FALSE, TRUE, pool, pool)); + + /* Neither path nor parent exists. */ + path = svn_dirent_join(path, "not-present", pool); + SVN_ERR(svn_io_remove_dir2(path, TRUE, NULL, NULL, pool)); + SVN_ERR(svn_io_remove_file2(path, TRUE, pool)); + SVN_ERR(svn_io_set_file_read_only(path, TRUE, pool)); + SVN_ERR(svn_io_set_file_read_write(path, TRUE, pool)); + SVN_ERR(svn_io_set_file_executable(path, TRUE, TRUE, pool)); + SVN_ERR(svn_io_set_file_executable(path, FALSE, TRUE, pool)); + SVN_ERR(svn_io_stat_dirent2(&dirent_p, path, TRUE, TRUE, pool, pool)); + SVN_ERR(svn_io_stat_dirent2(&dirent_p, path, FALSE, TRUE, pool, pool)); + + /* File does exist. */ + path = svn_dirent_join(tmp_dir, "present", pool); + SVN_ERR(svn_io_file_open(&file, path, + APR_WRITE | APR_CREATE | APR_TRUNCATE, + APR_OS_DEFAULT, + pool)); + SVN_ERR(svn_io_file_close(file, pool)); + + /* Path does not exist as child of file. */ + path = svn_dirent_join(path, "not-present", pool); + SVN_ERR(svn_io_remove_dir2(path, TRUE, NULL, NULL, pool)); + SVN_ERR(svn_io_remove_file2(path, TRUE, pool)); + SVN_ERR(svn_io_set_file_read_only(path, TRUE, pool)); + SVN_ERR(svn_io_set_file_read_write(path, TRUE, pool)); + SVN_ERR(svn_io_set_file_executable(path, TRUE, TRUE, pool)); + SVN_ERR(svn_io_set_file_executable(path, FALSE, TRUE, pool)); + SVN_ERR(svn_io_stat_dirent2(&dirent_p, path, TRUE, TRUE, pool, pool)); + SVN_ERR(svn_io_stat_dirent2(&dirent_p, path, FALSE, TRUE, pool, pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_install_stream_to_longpath(apr_pool_t *pool) +{ + const char *tmp_dir; + const char *final_abspath; + const char *deep_dir; + svn_stream_t *stream; + svn_stringbuf_t *actual_content; + int i; + + /* Create an empty directory. */ + SVN_ERR(svn_dirent_get_absolute(&tmp_dir, "test_install_stream_to_longpath", + pool)); + SVN_ERR(svn_io_remove_dir2(tmp_dir, TRUE, NULL, NULL, pool)); + SVN_ERR(svn_io_make_dir_recursively(tmp_dir, pool)); + svn_test_add_dir_cleanup(tmp_dir); + + deep_dir = tmp_dir; + + /* Generate very long path (> 260 symbols) */ + for (i = 0; i < 26; i++) + { + deep_dir = svn_dirent_join(deep_dir, "1234567890", pool); + SVN_ERR(svn_io_make_dir_recursively(deep_dir, pool)); + } + + final_abspath = svn_dirent_join(deep_dir, "stream1", pool); + SVN_ERR(svn_stream__create_for_install(&stream, deep_dir, pool, pool)); + SVN_ERR(svn_stream_puts(stream, "stream1 content")); + SVN_ERR(svn_stream_close(stream)); + SVN_ERR(svn_stream__install_stream(stream, + final_abspath, + TRUE, + pool)); + + SVN_ERR(svn_stringbuf_from_file2(&actual_content, + final_abspath, + pool)); + + SVN_TEST_STRING_ASSERT(actual_content->data, "stream1 content"); + + return SVN_NO_ERROR; +} +static svn_error_t * +test_apr_trunc_workaround(apr_pool_t *pool) +{ + const char *tmp_dir; + const char *tmp_file; + apr_file_t *f; + apr_size_t len; + apr_off_t offset; + char dummy; + + /* create a temp folder & schedule it for automatic cleanup */ + SVN_ERR(svn_dirent_get_absolute(&tmp_dir, "test_apr_trunc_workaround", + pool)); + SVN_ERR(svn_io_remove_dir2(tmp_dir, TRUE, NULL, NULL, pool)); + SVN_ERR(svn_io_make_dir_recursively(tmp_dir, pool)); + svn_test_add_dir_cleanup(tmp_dir); + + /* create an r/w file */ + tmp_file = svn_dirent_join(tmp_dir, "file", pool); + SVN_ERR(svn_io_file_open(&f, tmp_file, + APR_READ | APR_WRITE | APR_BUFFERED | APR_CREATE | + APR_TRUNCATE, + APR_OS_DEFAULT, pool)); + + /* write some content and put it internally into read mode */ + len = 10; + SVN_ERR(svn_io_file_write(f, "0123456789", &len, pool)); + + offset = 0; + SVN_ERR(svn_io_file_seek(f, APR_SET, &offset, pool)); + SVN_ERR(svn_io_file_getc(&dummy, f, pool)); + + /* clear the file and write some new content */ + SVN_ERR(svn_io_file_trunc(f, 0, pool)); + len = 3; + SVN_ERR(svn_io_file_write(f, "abc", &len, pool)); + + /* we should now be positioned at the end of the new content */ + offset = 0; + SVN_ERR(svn_io_file_seek(f, APR_CUR, &offset, pool)); + SVN_TEST_ASSERT(offset == (int)len); + + return SVN_NO_ERROR; +} + /* The test table. */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 3; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_two_file_size_comparison, @@ -523,5 +845,15 @@ struct svn_test_descriptor_t test_funcs[] = "three file content comparison"), SVN_TEST_PASS2(read_length_line_shouldnt_loop, "svn_io_read_length_line() shouldn't loop"), + SVN_TEST_PASS2(aligned_seek_test, + "test aligned seek"), + SVN_TEST_PASS2(ignore_enoent, + "test ignore-enoent"), + SVN_TEST_PASS2(test_install_stream_to_longpath, + "test svn_stream__install_stream to long path"), + SVN_TEST_PASS2(test_apr_trunc_workaround, + "test workaround for APR in svn_io_file_trunc"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/mergeinfo-test.c b/subversion/tests/libsvn_subr/mergeinfo-test.c index ecfcd02..5f4d37e 100644 --- a/subversion/tests/libsvn_subr/mergeinfo-test.c +++ b/subversion/tests/libsvn_subr/mergeinfo-test.c @@ -104,7 +104,7 @@ verify_mergeinfo_parse(const char *input, /* Were we expecting any more ranges? */ if (j < MAX_NBR_RANGES - 1 - && !expected_ranges[j].end == 0) + && expected_ranges[j].end != 0) return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, "svn_mergeinfo_parse (%s) failed to " "produce the expected number of ranges", @@ -114,11 +114,7 @@ verify_mergeinfo_parse(const char *input, } -/* Some of our own global variables (for simplicity), which map paths - -> merge ranges. */ -static apr_hash_t *info1, *info2; - -#define NBR_MERGEINFO_VALS 24 +#define NBR_MERGEINFO_VALS 25 /* Valid mergeinfo values. */ static const char * const mergeinfo_vals[NBR_MERGEINFO_VALS] = @@ -152,7 +148,8 @@ static const char * const mergeinfo_vals[NBR_MERGEINFO_VALS] = "/A/:7-8", "/A///:7-8", "/A/.:7-8", - "/A/./B:7-8" + "/A/./B:7-8", + ":7-8", }; /* Paths corresponding to mergeinfo_vals. */ static const char * const mergeinfo_paths[NBR_MERGEINFO_VALS] = @@ -185,7 +182,8 @@ static const char * const mergeinfo_paths[NBR_MERGEINFO_VALS] = "/A", "/A", "/A", - "/A/B" + "/A/B", + "/", }; /* First ranges from the paths identified by mergeinfo_paths. */ static svn_merge_range_t mergeinfo_ranges[NBR_MERGEINFO_VALS][MAX_NBR_RANGES] = @@ -216,6 +214,7 @@ static svn_merge_range_t mergeinfo_ranges[NBR_MERGEINFO_VALS][MAX_NBR_RANGES] = { {6, 8, TRUE} }, { {6, 8, TRUE} }, { {6, 8, TRUE} }, + { {6, 8, TRUE} }, }; static svn_error_t * @@ -268,6 +267,7 @@ test_parse_combine_rangeinfo(apr_pool_t *pool) { apr_array_header_t *result; svn_merge_range_t *resultrange; + apr_hash_t *info1; SVN_ERR(svn_mergeinfo_parse(&info1, single_mergeinfo, pool)); @@ -301,7 +301,7 @@ test_parse_combine_rangeinfo(apr_pool_t *pool) } -#define NBR_BROKEN_MERGEINFO_VALS 27 +#define NBR_BROKEN_MERGEINFO_VALS 26 /* Invalid mergeinfo values. */ static const char * const broken_mergeinfo_vals[NBR_BROKEN_MERGEINFO_VALS] = { @@ -333,8 +333,6 @@ static const char * const broken_mergeinfo_vals[NBR_BROKEN_MERGEINFO_VALS] = "/trunk:", "/trunk:2-9\n/branch:", "::", - /* No path */ - ":1-3", /* Invalid revisions */ "trunk:a-3", "branch:3-four", @@ -346,6 +344,7 @@ test_parse_broken_mergeinfo(apr_pool_t *pool) { int i; svn_error_t *err; + apr_hash_t *info1; /* Trigger some error(s) with mal-formed input. */ for (i = 0; i < NBR_BROKEN_MERGEINFO_VALS; i++) @@ -565,6 +564,7 @@ test_mergeinfo_intersect(apr_pool_t *pool) { {0, 1, TRUE}, {2, 4, TRUE}, {11, 12, TRUE} }; svn_rangelist_t *rangelist; apr_hash_t *intersection; + apr_hash_t *info1, *info2; SVN_ERR(svn_mergeinfo_parse(&info1, "/trunk: 1-6,12-16\n/foo: 31", pool)); SVN_ERR(svn_mergeinfo_parse(&info2, "/trunk: 1,3-4,7,9,11-12", pool)); @@ -701,6 +701,7 @@ test_merge_mergeinfo(apr_pool_t *pool) { int j; svn_string_t *info2_starting, *info2_ending; + apr_hash_t *info1, *info2; SVN_ERR(svn_mergeinfo_parse(&info1, mergeinfo[i].mergeinfo1, pool)); SVN_ERR(svn_mergeinfo_parse(&info2, mergeinfo[i].mergeinfo2, pool)); @@ -1109,6 +1110,7 @@ test_rangelist_to_string(apr_pool_t *pool) svn_rangelist_t *result; svn_string_t *output; svn_string_t *expected = svn_string_create("3,5,7-11,13-14", pool); + apr_hash_t *info1; SVN_ERR(svn_mergeinfo_parse(&info1, mergeinfo1, pool)); @@ -1129,6 +1131,7 @@ test_mergeinfo_to_string(apr_pool_t *pool) { svn_string_t *output; svn_string_t *expected; + apr_hash_t *info1, *info2; expected = svn_string_create("/fred:8-10\n/trunk:3,5,7-11,13-14", pool); SVN_ERR(svn_mergeinfo_parse(&info1, mergeinfo1, pool)); @@ -1670,7 +1673,9 @@ test_remove_prefix_from_catalog(apr_pool_t *pool) /* The test table. */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_parse_single_line_mergeinfo, @@ -1711,3 +1716,5 @@ struct svn_test_descriptor_t test_funcs[] = "removal of prefix paths from catalog keys"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/named_atomic-test-common.h b/subversion/tests/libsvn_subr/named_atomic-test-common.h deleted file mode 100644 index 2ada4ee..0000000 --- a/subversion/tests/libsvn_subr/named_atomic-test-common.h +++ /dev/null @@ -1,245 +0,0 @@ -/* - * named_atomic-test-common.h: shared function implementations for - * named_atomic-test - * - * ==================================================================== - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * ==================================================================== - */ - - - -#include "../svn_test.h" -#include "svn_pools.h" -#include "private/svn_named_atomic.h" - -/* Some constants that we will use in our tests */ - -/* All our atomics start with that name */ -#define ATOMIC_NAME "MyTestAtomic" - -/* Factor used to create non-trivial 64 bit numbers */ -#define HUGE_VALUE 1234567890123456ll - -/* to separate this code from any production environment */ -const char *name_namespace = NULL; -const char *name_namespace1 = NULL; -const char *name_namespace2 = NULL; - -/* data structure containing all information we need to check for - * a) passing some deadline - * b) reaching the maximum iteration number - */ -typedef struct watchdog_t -{ - apr_time_t deadline; - svn_named_atomic__t *atomic_counter; - int iterations; - int call_count; /* don't call apr_time_now() too often '*/ -} watchdog_t; - -/* init the WATCHDOG data structure for checking ATOMIC_COUNTER to reach - * ITERATIONS and for the system time to pass a deadline MAX_DURATION - * microsecs in the future. - */ -static void -init_watchdog(watchdog_t *watchdog, - svn_named_atomic__t *atomic_counter, - int iterations, - apr_time_t max_duration) -{ - watchdog->deadline = apr_time_now() + max_duration; - watchdog->atomic_counter = atomic_counter; - watchdog->iterations = iterations; - watchdog->call_count = 0; -} - -/* test for watchdog conditions */ -static svn_error_t * -check_watchdog(watchdog_t *watchdog, svn_boolean_t *done) -{ - apr_int64_t counter = 0; - - /* check for normal end of loop. - * We are a watchdog, so don't check for errors. */ - *done = FALSE; - svn_error_clear(svn_named_atomic__read(&counter, - watchdog->atomic_counter)); - if (counter >= watchdog->iterations) - { - *done = TRUE; - return SVN_NO_ERROR; - } - - /* Check the system time and indicate when deadline has passed */ - if (++watchdog->call_count > 100) - { - watchdog->call_count = 100; - if (apr_time_now() > watchdog->deadline) - return svn_error_createf(SVN_ERR_TEST_FAILED, - 0, - "Deadline has passed at iteration %d/%d", - (int)counter, watchdog->iterations); - } - - /* no problem so far */ - return SVN_NO_ERROR; -} - -/* "pipeline" test: initialization code executed by the worker with ID 0. - * Pushes COUNT tokens into ATOMIC_OUT and checks for ATOMIC_COUNTER not to - * exceed ITERATIONS (early termination). - */ -static svn_error_t * -test_pipeline_prepare(svn_named_atomic__t *atomic_out, - int count, - watchdog_t *watchdog) -{ - apr_int64_t value = 0; - int i; - svn_boolean_t done = FALSE; - - /* Initialize values in thread 0, pass them along in other threads */ - - for (i = 1; i <= count; ++i) - do - { - /* Generate new token (once the old one has been removed)*/ - SVN_ERR(svn_named_atomic__cmpxchg(&value, - i, - 0, - atomic_out)); - SVN_ERR(check_watchdog(watchdog, &done)); - if (done) return SVN_NO_ERROR; - } - while (value != 0); - - return SVN_NO_ERROR; -} - -/* "pipeline" test: the main loop. Each one of the COUNT workers receives - * data in its ATOMIC_IN and passes it on to ATOMIC_OUT until ATOMIC_COUNTER - * exceeds ITERATIONS. - */ -static svn_error_t * -test_pipeline_loop(svn_named_atomic__t *atomic_in, - svn_named_atomic__t *atomic_out, - svn_named_atomic__t *atomic_counter, - int count, - int iterations, - watchdog_t *watchdog) -{ - apr_int64_t value = 0, old_value, last_value = 0; - apr_int64_t counter; - svn_boolean_t done = FALSE; - - /* Pass the tokens along */ - - do - { - /* Wait for and consume incoming token. */ - do - { - SVN_ERR(svn_named_atomic__write(&value, 0, atomic_in)); - SVN_ERR(check_watchdog(watchdog, &done)); - if (done) return SVN_NO_ERROR; - } - while (value == 0); - - /* All tokes must come in in the same order */ - SVN_TEST_ASSERT((last_value % count) == (value - 1)); - last_value = value; - - /* Wait for the target atomic to become vacant and write the token */ - do - { - SVN_ERR(svn_named_atomic__cmpxchg(&old_value, - value, - 0, - atomic_out)); - SVN_ERR(check_watchdog(watchdog, &done)); - if (done) return SVN_NO_ERROR; - } - while (old_value != 0); - - /* Count the number of operations */ - SVN_ERR(svn_named_atomic__add(&counter, 1, atomic_counter)); - } - while (counter < iterations); - - /* done */ - - return SVN_NO_ERROR; -} - -/* "pipeline" test: worker with ID 0 initializes the data; all workers - * (COUNT in total) have one input and one output bucket that form a ring - * spanning all workers. Each worker passes the value along ITERATIONS times. - */ -static svn_error_t * -test_pipeline(int id, int count, int iterations, apr_pool_t *pool) -{ - svn_atomic_namespace__t *ns; - svn_named_atomic__t *atomic_in; - svn_named_atomic__t *atomic_out; - svn_named_atomic__t *atomic_counter; - svn_error_t *err = SVN_NO_ERROR; - watchdog_t watchdog; - - /* get the two I/O atomics for this thread */ - SVN_ERR(svn_atomic_namespace__create(&ns, name_namespace, pool)); - SVN_ERR(svn_named_atomic__get(&atomic_in, - ns, - apr_pstrcat(pool, - ATOMIC_NAME, - apr_itoa(pool, - id), - NULL), - FALSE)); - SVN_ERR(svn_named_atomic__get(&atomic_out, - ns, - apr_pstrcat(pool, - ATOMIC_NAME, - apr_itoa(pool, - (id + 1) % count), - NULL), - FALSE)); - - /* our iteration counter */ - SVN_ERR(svn_named_atomic__get(&atomic_counter, ns, "counter", FALSE)); - - /* safeguard our execution time. Limit it to 20s */ - init_watchdog(&watchdog, atomic_counter, iterations, 20000000); - - /* fill pipeline */ - if (id == 0) - err = test_pipeline_prepare(atomic_out, count, &watchdog); - - /* Pass the tokens along */ - if (!err) - err = test_pipeline_loop(atomic_in, atomic_out, atomic_counter, - count, iterations, &watchdog); - - /* if we experienced an error, cause everybody to exit */ - if (err) - svn_error_clear(svn_named_atomic__write(NULL, iterations, atomic_counter)); - - /* done */ - - return err; -} diff --git a/subversion/tests/libsvn_subr/named_atomic-test-proc.c b/subversion/tests/libsvn_subr/named_atomic-test-proc.c deleted file mode 100644 index 534247c..0000000 --- a/subversion/tests/libsvn_subr/named_atomic-test-proc.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * named_atomic-test-proc.c: a collection of svn_named_atomic__t tests - * - * ==================================================================== - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * ==================================================================== - */ - -/* ==================================================================== - To add tests, look toward the bottom of this file. -*/ - - -#include <stdio.h> - -/* shared test implementation */ -#include "named_atomic-test-common.h" - -/* Very simple process frame around the actual test code */ -int -main(int argc, const char *argv[]) -{ - svn_boolean_t got_error = FALSE; - apr_pool_t *pool; - svn_error_t *err; - - int id = 0; - int count = 0; - int iterations = 0; - - /* Initialize APR (Apache pools) */ - if (apr_initialize() != APR_SUCCESS) - { - printf("apr_initialize() failed.\n"); - exit(1); - } - - pool = svn_pool_create(NULL); - - /* lean & mean parameter parsing */ - if (argc != 5) - { - if (argc == 1) /* used to test that this executable can be started */ - exit(0); - - printf("Usage: named_atomic-proc-test ID COUNT ITERATIONS NS.\n"); - exit(1); - } - - id = (int)apr_atoi64(argv[1]); - count = (int)apr_atoi64(argv[2]); - iterations = (int)apr_atoi64(argv[3]); - name_namespace = argv[4]; - - /* run test routine */ - - err = test_pipeline(id, count, iterations, pool); - if (err) - { - const char *prefix = apr_psprintf(pool, "Process %d: ", id); - got_error = TRUE; - svn_handle_error2(err, stdout, FALSE, prefix); - svn_error_clear(err); - } - - /* Clean up APR */ - svn_pool_destroy(pool); - apr_terminate(); - - return got_error; -} diff --git a/subversion/tests/libsvn_subr/named_atomic-test.c b/subversion/tests/libsvn_subr/named_atomic-test.c deleted file mode 100644 index 05604d2..0000000 --- a/subversion/tests/libsvn_subr/named_atomic-test.c +++ /dev/null @@ -1,761 +0,0 @@ -/* - * named_atomic-test.c: a collection of svn_named_atomic__t tests - * - * ==================================================================== - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * ==================================================================== - */ - -/* ==================================================================== - To add tests, look toward the bottom of this file. -*/ - - -#include <stdio.h> -#include <apr_file_io.h> - -#include "svn_io.h" - -/* shared test implementation */ -#include "named_atomic-test-common.h" - -/* Name of the worker process executable */ -#define TEST_PROC "named_atomic-proc-test" - -/* number of hardware threads (logical cores) that we may use. - * Will be set to at least 2 - even on unicore machines. */ -static int hw_thread_count = 0; - -/* number of iterations that we should perform on concurrency tests - * (will be calibrated to about 1s runtime)*/ -static int suggested_iterations = 0; - -/* If possible, translate PROC to a global path and set DIRECTORY to - * the current directory. - */ -static svn_error_t * -adjust_proc_path(const char **proc, const char **directory, apr_pool_t *pool) -{ -#ifdef WIN32 - /* Under Windows, the test will not be in the current directory - * and neither will be PROC. Therefore, determine its full path */ - char path [MAX_PATH] = { 0 }; - GetModuleFileNameA(NULL, path, sizeof(path)); - *(strrchr(path, '\\') + 1) = 0; - *proc = apr_pstrcat(pool, path, *proc, ".exe", NULL); - - /* And we need to set the working dir to our working dir to make - * our sub-processes find all DLLs. */ - GetCurrentDirectoryA(sizeof(path), path); - *directory = apr_pstrdup(pool, path); -#endif - - return SVN_NO_ERROR; -} - -/* Returns true if PROC can be found and executed. - */ -static svn_boolean_t -proc_found(const char *proc, apr_pool_t *pool) -{ - static svn_tristate_t result = svn_tristate_unknown; - - if (result == svn_tristate_unknown) - { - svn_error_t *error = SVN_NO_ERROR; - const char * directory = NULL; - - /* all processes and their I/O data */ - apr_proc_t process; - const char * args[2]; - - args[0] = proc; - args[1] = NULL; - svn_error_clear(adjust_proc_path(&args[0], &directory, pool)); - - /* try to start the process */ - error = svn_io_start_cmd3(&process, - directory, /* working directory */ - args[0], - args, - NULL, /* environment */ - FALSE, /* no handle inheritance */ - FALSE, /* no STDIN pipe */ - NULL, - FALSE, /* no STDOUT pipe */ - NULL, - FALSE, /* no STDERR pipe */ - NULL, - pool); - if (!error) - error = svn_io_wait_for_cmd(&process, proc, NULL, NULL, pool); - - result = error ? svn_tristate_false : svn_tristate_true; - svn_error_clear(error); - } - - return result == svn_tristate_true; -} - -/* Remove temporary files from disk. - */ -static apr_status_t -cleanup_test_shm(void *arg) -{ - apr_pool_t *pool = arg; - - svn_error_clear(svn_atomic_namespace__cleanup(name_namespace, pool)); - svn_error_clear(svn_atomic_namespace__cleanup(name_namespace1, pool)); - svn_error_clear(svn_atomic_namespace__cleanup(name_namespace2, pool)); - - return 0; -} - -/* Bring shared memory to a defined state. This is very useful in case of - * lingering problems from previous tests or test runs. - */ -static svn_error_t * -init_test_shm(apr_pool_t *pool) -{ - svn_atomic_namespace__t *ns; - svn_named_atomic__t *atomic; - apr_pool_t *scratch = svn_pool_create(pool); - - if (name_namespace == NULL) - { - apr_pool_t *global_pool = svn_pool_create(NULL); - SVN_ERR(svn_io_open_unique_file3(NULL, - &name_namespace, - NULL, - svn_io_file_del_on_pool_cleanup, - global_pool, - pool)); - SVN_ERR(svn_io_open_unique_file3(NULL, - &name_namespace1, - NULL, - svn_io_file_del_on_pool_cleanup, - global_pool, - pool)); - SVN_ERR(svn_io_open_unique_file3(NULL, - &name_namespace2, - NULL, - svn_io_file_del_on_pool_cleanup, - global_pool, - pool)); - } - - /* skip tests if the current user does not have the required privileges */ - if (!svn_named_atomic__is_supported()) - return svn_error_wrap_apr(SVN_ERR_TEST_SKIPPED, - "user has insufficient privileges"); - - /* destroy temp files after usage */ - - apr_pool_cleanup_register(pool, pool, - cleanup_test_shm, apr_pool_cleanup_null); - - /* get the two I/O atomics for this thread */ - SVN_ERR(svn_atomic_namespace__create(&ns, name_namespace, scratch)); - SVN_ERR(svn_named_atomic__get(&atomic, ns, ATOMIC_NAME, TRUE)); - SVN_ERR(svn_named_atomic__write(NULL, 0, atomic)); - SVN_ERR(svn_named_atomic__get(&atomic, ns, ATOMIC_NAME "1", TRUE)); - SVN_ERR(svn_named_atomic__write(NULL, 0, atomic)); - SVN_ERR(svn_named_atomic__get(&atomic, ns, ATOMIC_NAME "2", TRUE)); - SVN_ERR(svn_named_atomic__write(NULL, 0, atomic)); - - svn_pool_clear(scratch); - - SVN_ERR(svn_atomic_namespace__create(&ns, name_namespace1, scratch)); - SVN_ERR(svn_named_atomic__get(&atomic, ns, ATOMIC_NAME, TRUE)); - SVN_ERR(svn_named_atomic__write(NULL, 0, atomic)); - svn_pool_clear(scratch); - - SVN_ERR(svn_atomic_namespace__create(&ns, name_namespace2, scratch)); - SVN_ERR(svn_named_atomic__get(&atomic, ns, ATOMIC_NAME, TRUE)); - SVN_ERR(svn_named_atomic__write(NULL, 0, atomic)); - svn_pool_clear(scratch); - - /* done */ - - return SVN_NO_ERROR; -} - -/* Prepare the shared memory for a run with COUNT workers. - */ -static svn_error_t * -init_concurrency_test_shm(apr_pool_t *pool, int count) -{ - svn_atomic_namespace__t *ns; - svn_named_atomic__t *atomic; - int i; - - /* get the two I/O atomics for this thread */ - SVN_ERR(svn_atomic_namespace__create(&ns, name_namespace, pool)); - - /* reset the I/O atomics for all threads */ - for (i = 0; i < count; ++i) - { - SVN_ERR(svn_named_atomic__get(&atomic, - ns, - apr_pstrcat(pool, - ATOMIC_NAME, - apr_itoa(pool, i), - NULL), - TRUE)); - SVN_ERR(svn_named_atomic__write(NULL, 0, atomic)); - } - - SVN_ERR(svn_named_atomic__get(&atomic, ns, "counter", TRUE)); - SVN_ERR(svn_named_atomic__write(NULL, 0, atomic)); - - return SVN_NO_ERROR; -} - -#if APR_HAS_THREADS - -/* our thread function type - */ -typedef svn_error_t *(*thread_func_t)(int, int, int, apr_pool_t *); - -/* Per-thread input and output data. - */ -struct thread_baton -{ - int thread_count; - int thread_no; - int iterations; - svn_error_t *result; - thread_func_t func; -}; - -/* APR thread function implementation: A wrapper around baton->func that - * handles the svn_error_t return value. - */ -static void * -APR_THREAD_FUNC test_thread(apr_thread_t *thread, void *baton) -{ - struct thread_baton *params = baton; - apr_pool_t *pool = svn_pool_create_ex(NULL, NULL); - - params->result = (*params->func)(params->thread_no, - params->thread_count, - params->iterations, - pool); - svn_pool_destroy(pool); - apr_thread_exit(thread, APR_SUCCESS); - - return NULL; -} - -/* Runs FUNC in COUNT concurrent threads ITERATION times and combines the - * results. - */ -static svn_error_t * -run_threads(apr_pool_t *pool, int count, int iterations, thread_func_t func) -{ - apr_status_t status; - int i; - svn_error_t *error = SVN_NO_ERROR; - - /* all threads and their I/O data */ - apr_thread_t **threads = apr_palloc(pool, count * sizeof(*threads)); - struct thread_baton *batons = apr_palloc(pool, count * sizeof(*batons)); - - /* start threads */ - for (i = 0; i < count; ++i) - { - batons[i].thread_count = count; - batons[i].thread_no = i; - batons[i].iterations = iterations; - batons[i].func = func; - - status = apr_thread_create(&threads[i], - NULL, - test_thread, - &batons[i], - pool); - if (status != APR_SUCCESS) - SVN_ERR(svn_error_wrap_apr(status, "could not create a thread")); - } - - /* Wait for threads to finish and return result. */ - for (i = 0; i < count; ++i) - { - apr_status_t retval; - status = apr_thread_join(&retval, threads[i]); - if (status != APR_SUCCESS) - SVN_ERR(svn_error_wrap_apr(status, "waiting for thread's end failed")); - - if (batons[i].result) - error = svn_error_compose_create (error, svn_error_quick_wrap - (batons[i].result, apr_psprintf(pool, "Thread %d failed", i))); - } - - return error; -} -#endif - -/* Runs PROC in COUNT concurrent worker processes and check the results. - */ -static svn_error_t * -run_procs(apr_pool_t *pool, const char *proc, int count, int iterations) -{ - int i, k; - svn_error_t *error = SVN_NO_ERROR; - const char * directory = NULL; - - /* all processes and their I/O data */ - apr_proc_t *process = apr_palloc(pool, count * sizeof(*process)); - apr_file_t *common_stdout = NULL; - apr_file_open_stdout(&common_stdout, pool); - - SVN_ERR(adjust_proc_path(&proc, &directory, pool)); - - /* start sub-processes */ - for (i = 0; i < count; ++i) - { - const char * args[6]; - - args[0] = proc; - args[1] = apr_itoa(pool, i); - args[2] = apr_itoa(pool, count); - args[3] = apr_itoa(pool, iterations); - args[4] = name_namespace; - args[5] = NULL; - - error = svn_io_start_cmd3(&process[i], - directory, /* working directory */ - args[0], - args, - NULL, /* environment */ - FALSE, /* no handle inheritance */ - FALSE, /* no STDIN pipe */ - NULL, - FALSE, /* consolidate into 1 STDOUT */ - common_stdout, - FALSE, /* no STDERR pipe */ - NULL, - pool); - if (error) - { - /* dump program name and parameters */ - for (k = 0; k < sizeof(args) / sizeof(args[0]); ++k) - if (args[k]) - printf(k == 0 ? "%s\n" : " %s\n", args[k]); - - if (directory) - printf("working folder %s:\n", directory); - - return error; - } - } - - /* Wait for sub-processes to finish and return result. */ - for (i = 0; i < count; ++i) - { - const char *cmd = apr_psprintf(pool, - "named_atomic-test-proc %d %d %d", - i, count, iterations); - error = svn_error_compose_create(error, - svn_io_wait_for_cmd(&process[i], - cmd, NULL, NULL, - pool)); - } - - return error; -} - -/* Set SUGGESTED_ITERATIONS to a value that COUNT workers will take - * about 1 second to execute. - */ -static svn_error_t * -calibrate_iterations(apr_pool_t *pool, int count) -{ - apr_time_t start; - int calib_iterations; - double taken = 0.0; - - /* increase iterations until we pass the 100ms mark */ - - for (calib_iterations = 10; taken < 100000.0; calib_iterations *= 2) - { - apr_pool_t *scratch = svn_pool_create(pool); - SVN_ERR(init_concurrency_test_shm(scratch, count)); - - start = apr_time_now(); - SVN_ERR(run_procs(pool, TEST_PROC, count, calib_iterations)); - - taken = (double)(apr_time_now() - start); - svn_pool_destroy(scratch); - } - - /* scale that to 1s */ - - suggested_iterations = (int)(1000000.0 / taken * calib_iterations); - - return SVN_NO_ERROR; -} - -/* Find out how far the system will scale, i.e. how many workers can be - * run concurrently without experiencing significant slowdowns. - * Sets HW_THREAD_COUNT to a value of 2 .. 32 (limit the system impact in - * case our heuristics fail) and determines the number of iterations. - * Can be called multiple times but will skip the calculations after the - * first successful run. - */ -static svn_error_t * -calibrate_concurrency(apr_pool_t *pool) -{ - if (hw_thread_count == 0) - { - /* these parameters should be ok even on very slow machines */ - hw_thread_count = 2; - suggested_iterations = 100; - - /* if we've got a proper machine and OS setup, let's prepare for - * some real testing */ - if (svn_named_atomic__is_efficient() && proc_found(TEST_PROC, pool)) - { - SVN_ERR(calibrate_iterations(pool, 2)); - for (; hw_thread_count < 32; hw_thread_count *= 2) - { - int saved_suggestion = suggested_iterations; - - /* run with an additional core to spare - * (even low CPU usage might cause heavy context switching) */ - SVN_ERR(calibrate_iterations(pool, hw_thread_count * 2 + 1)); - if (suggested_iterations < 100000) - { - /* Machines with only a small number of cores are prone - * to inconsistent performance due context switching. - * Reduce the number of iterations on those machines. */ - suggested_iterations = hw_thread_count > 2 - ? saved_suggestion - : saved_suggestion / 2; - break; - } - } - } - - printf("using %d cores for %d iterations\n", hw_thread_count, - suggested_iterations); - } - - return SVN_NO_ERROR; -} - -/* The individual tests */ - -static svn_error_t * -test_basics(apr_pool_t *pool) -{ - svn_atomic_namespace__t *ns; - svn_named_atomic__t *atomic; - apr_int64_t value; - - SVN_ERR(init_test_shm(pool)); - - /* Use a separate namespace for our tests isolate them from production */ - SVN_ERR(svn_atomic_namespace__create(&ns, name_namespace, pool)); - - /* Test a non-existing atomic */ - SVN_ERR(svn_named_atomic__get(&atomic, ns, ATOMIC_NAME "x", FALSE)); - SVN_TEST_ASSERT(atomic == NULL); - - /* Now, we auto-create it */ - SVN_ERR(svn_named_atomic__get(&atomic, ns, ATOMIC_NAME, TRUE)); - SVN_TEST_ASSERT(atomic != NULL); - - /* The default value should be 0 */ - SVN_TEST_ASSERT_ERROR(svn_named_atomic__read(&value, NULL), - SVN_ERR_BAD_ATOMIC); - value = 1; - SVN_ERR(svn_named_atomic__read(&value, atomic)); - SVN_TEST_ASSERT(value == 0); - - /* Write should return the previous value. */ - SVN_TEST_ASSERT_ERROR(svn_named_atomic__write(&value, 0, NULL), - SVN_ERR_BAD_ATOMIC); - value = 1; - SVN_ERR(svn_named_atomic__write(&value, 21, atomic)); - SVN_TEST_ASSERT(value == 0); - SVN_ERR(svn_named_atomic__read(&value, atomic)); - SVN_TEST_ASSERT(value == 21); - - SVN_ERR(svn_named_atomic__write(&value, 42, atomic)); - SVN_TEST_ASSERT(value == 21); - SVN_ERR(svn_named_atomic__read(&value, atomic)); - SVN_TEST_ASSERT(value == 42); - - SVN_ERR(svn_named_atomic__write(NULL, 17, atomic)); - SVN_ERR(svn_named_atomic__read(&value, atomic)); - SVN_TEST_ASSERT(value == 17); - - /* Adding & subtracting values */ - SVN_TEST_ASSERT_ERROR(svn_named_atomic__add(&value, 0, NULL), - SVN_ERR_BAD_ATOMIC); - SVN_ERR(svn_named_atomic__add(&value, 25, atomic)); - SVN_TEST_ASSERT(value == 42); - SVN_ERR(svn_named_atomic__add(NULL, 47, atomic)); - SVN_ERR(svn_named_atomic__read(&value, atomic)); - SVN_TEST_ASSERT(value == 89); - - SVN_ERR(svn_named_atomic__add(&value, -25, atomic)); - SVN_TEST_ASSERT(value == 64); - SVN_ERR(svn_named_atomic__add(NULL, -22, atomic)); - SVN_ERR(svn_named_atomic__read(&value, atomic)); - SVN_TEST_ASSERT(value == 42); - - /* Compare-and-exchange */ - SVN_TEST_ASSERT_ERROR(svn_named_atomic__cmpxchg(&value, 0, 0, NULL), - SVN_ERR_BAD_ATOMIC); - value = 1; - SVN_ERR(svn_named_atomic__cmpxchg(&value, 99, 41, atomic)); - SVN_TEST_ASSERT(value == 42); - - value = 1; - SVN_ERR(svn_named_atomic__cmpxchg(&value, 98, 42, atomic)); - SVN_TEST_ASSERT(value == 42); - SVN_ERR(svn_named_atomic__cmpxchg(&value, 67, 98, atomic)); - SVN_TEST_ASSERT(value == 98); - - SVN_ERR(svn_named_atomic__cmpxchg(NULL, 42, 67, atomic)); - SVN_ERR(svn_named_atomic__read(&value, atomic)); - SVN_TEST_ASSERT(value == 42); - - return SVN_NO_ERROR; -} - -static svn_error_t * -test_bignums(apr_pool_t *pool) -{ - svn_atomic_namespace__t *ns; - svn_named_atomic__t *atomic; - apr_int64_t value; - - SVN_ERR(init_test_shm(pool)); - - /* Use a separate namespace for our tests isolate them from production */ - SVN_ERR(svn_atomic_namespace__create(&ns, name_namespace, pool)); - - /* Auto-create our atomic variable */ - SVN_ERR(svn_named_atomic__get(&atomic, ns, ATOMIC_NAME, TRUE)); - SVN_TEST_ASSERT(atomic != NULL); - - /* Write should return the previous value. */ - - SVN_ERR(svn_named_atomic__write(NULL, 0, atomic)); - value = 1; - SVN_ERR(svn_named_atomic__write(&value, 21 * HUGE_VALUE, atomic)); - SVN_TEST_ASSERT(value == 0 * HUGE_VALUE); - SVN_ERR(svn_named_atomic__read(&value, atomic)); - SVN_TEST_ASSERT(value == 21 * HUGE_VALUE); - - SVN_ERR(svn_named_atomic__write(&value, 17 * HUGE_VALUE, atomic)); - SVN_TEST_ASSERT(value == 21 * HUGE_VALUE); - - /* Adding & subtracting values */ - SVN_ERR(svn_named_atomic__add(&value, 25 * HUGE_VALUE, atomic)); - SVN_TEST_ASSERT(value == 42 * HUGE_VALUE); - SVN_ERR(svn_named_atomic__add(&value, -25 * HUGE_VALUE, atomic)); - SVN_TEST_ASSERT(value == 17 * HUGE_VALUE); - - /* Compare-and-exchange */ - value = 1; - SVN_ERR(svn_named_atomic__cmpxchg(&value, 99 * HUGE_VALUE, 41 * HUGE_VALUE, atomic)); - SVN_TEST_ASSERT(value == 17 * HUGE_VALUE); - - value = 1; - SVN_ERR(svn_named_atomic__cmpxchg(&value, 98 * HUGE_VALUE, 17 * HUGE_VALUE, atomic)); - SVN_TEST_ASSERT(value == 17 * HUGE_VALUE); - SVN_ERR(svn_named_atomic__read(&value, atomic)); - SVN_TEST_ASSERT(value == 98 * HUGE_VALUE); - - return SVN_NO_ERROR; -} - -static svn_error_t * -test_multiple_atomics(apr_pool_t *pool) -{ - svn_atomic_namespace__t *ns; - svn_named_atomic__t *atomic1; - svn_named_atomic__t *atomic2; - svn_named_atomic__t *atomic1_alias; - svn_named_atomic__t *atomic2_alias; - apr_int64_t value1; - apr_int64_t value2; - - SVN_ERR(init_test_shm(pool)); - - /* Use a separate namespace for our tests isolate them from production */ - SVN_ERR(svn_atomic_namespace__create(&ns, name_namespace, pool)); - - /* Create two atomics */ - SVN_ERR(svn_named_atomic__get(&atomic1, ns, ATOMIC_NAME "1", TRUE)); - SVN_ERR(svn_named_atomic__get(&atomic2, ns, ATOMIC_NAME "2", TRUE)); - SVN_TEST_ASSERT(atomic1 != NULL); - SVN_TEST_ASSERT(atomic2 != NULL); - SVN_TEST_ASSERT(atomic1 != atomic2); - - /* Get aliases to those */ - SVN_ERR(svn_named_atomic__get(&atomic1_alias, ns, ATOMIC_NAME "1", TRUE)); - SVN_ERR(svn_named_atomic__get(&atomic2_alias, ns, ATOMIC_NAME "2", TRUE)); - SVN_TEST_ASSERT(atomic1 == atomic1_alias); - SVN_TEST_ASSERT(atomic2 == atomic2_alias); - - /* The atomics shall not overlap, i.e. changes to one do not affect the other */ - SVN_ERR(svn_named_atomic__write(NULL, 0, atomic1)); - SVN_ERR(svn_named_atomic__write(NULL, 0, atomic2)); - SVN_ERR(svn_named_atomic__write(&value1, 21 * HUGE_VALUE, atomic1)); - SVN_ERR(svn_named_atomic__write(&value2, 42 * HUGE_VALUE, atomic2)); - SVN_TEST_ASSERT(value1 == 0); - SVN_TEST_ASSERT(value2 == 0); - - SVN_ERR(svn_named_atomic__read(&value1, atomic1)); - SVN_ERR(svn_named_atomic__read(&value2, atomic2)); - SVN_TEST_ASSERT(value1 == 21 * HUGE_VALUE); - SVN_TEST_ASSERT(value2 == 42 * HUGE_VALUE); - - SVN_ERR(svn_named_atomic__add(&value1, 25 * HUGE_VALUE, atomic1)); - SVN_ERR(svn_named_atomic__add(&value2, -25 * HUGE_VALUE, atomic2)); - SVN_TEST_ASSERT(value1 == 46 * HUGE_VALUE); - SVN_TEST_ASSERT(value2 == 17 * HUGE_VALUE); - - value1 = 1; - value2 = 1; - SVN_ERR(svn_named_atomic__cmpxchg(&value1, 4 * HUGE_VALUE, 46 * HUGE_VALUE, atomic1)); - SVN_ERR(svn_named_atomic__cmpxchg(&value2, 98 * HUGE_VALUE, 17 * HUGE_VALUE, atomic2)); - SVN_TEST_ASSERT(value1 == 46 * HUGE_VALUE); - SVN_TEST_ASSERT(value2 == 17 * HUGE_VALUE); - - SVN_ERR(svn_named_atomic__read(&value1, atomic1)); - SVN_ERR(svn_named_atomic__read(&value2, atomic2)); - SVN_TEST_ASSERT(value1 == 4 * HUGE_VALUE); - SVN_TEST_ASSERT(value2 == 98 * HUGE_VALUE); - - return SVN_NO_ERROR; -} - -static svn_error_t * -test_namespaces(apr_pool_t *pool) -{ - svn_atomic_namespace__t *test_namespace1; - svn_atomic_namespace__t *test_namespace1_alias; - svn_atomic_namespace__t *test_namespace2; - svn_atomic_namespace__t *test_namespace2_alias; - svn_named_atomic__t *atomic1; - svn_named_atomic__t *atomic2; - svn_named_atomic__t *atomic1_alias; - svn_named_atomic__t *atomic2_alias; - apr_int64_t value; - - SVN_ERR(init_test_shm(pool)); - - /* Use a separate namespace for our tests isolate them from production */ - SVN_ERR(svn_atomic_namespace__create(&test_namespace1, name_namespace1, pool)); - SVN_ERR(svn_atomic_namespace__create(&test_namespace1_alias, name_namespace1, pool)); - SVN_ERR(svn_atomic_namespace__create(&test_namespace2, name_namespace2, pool)); - SVN_ERR(svn_atomic_namespace__create(&test_namespace2_alias, name_namespace2, pool)); - - /* Create two atomics with the same name in different namespaces */ - SVN_ERR(svn_named_atomic__get(&atomic1, test_namespace1, ATOMIC_NAME, TRUE)); - SVN_ERR(svn_named_atomic__get(&atomic1_alias, test_namespace1_alias, ATOMIC_NAME, FALSE)); - SVN_ERR(svn_named_atomic__get(&atomic2, test_namespace2, ATOMIC_NAME, TRUE)); - SVN_ERR(svn_named_atomic__get(&atomic2_alias, test_namespace2_alias, ATOMIC_NAME, FALSE)); - SVN_TEST_ASSERT(atomic1 != atomic1_alias); - SVN_TEST_ASSERT(atomic1_alias != NULL); - SVN_TEST_ASSERT(atomic2 != atomic2_alias); - SVN_TEST_ASSERT(atomic2_alias != NULL); - - /* Write data to our atomics */ - SVN_ERR(svn_named_atomic__write(NULL, 21 * HUGE_VALUE, atomic1)); - SVN_ERR(svn_named_atomic__write(NULL, 42 * HUGE_VALUE, atomic2)); - - /* Now check who sees which value */ - SVN_ERR(svn_named_atomic__read(&value, atomic1)); - SVN_TEST_ASSERT(value == 21 * HUGE_VALUE); - SVN_ERR(svn_named_atomic__read(&value, atomic2)); - SVN_TEST_ASSERT(value == 42 * HUGE_VALUE); - - SVN_ERR(svn_named_atomic__read(&value, atomic1_alias)); - SVN_TEST_ASSERT(value == 21 * HUGE_VALUE); - SVN_ERR(svn_named_atomic__read(&value, atomic2_alias)); - SVN_TEST_ASSERT(value == 42 * HUGE_VALUE); - - return SVN_NO_ERROR; -} - -static svn_error_t * -test_multithreaded(apr_pool_t *pool) -{ -#if APR_HAS_THREADS - SVN_ERR(init_test_shm(pool)); - - SVN_ERR(calibrate_concurrency(pool)); - - SVN_ERR(init_concurrency_test_shm(pool, hw_thread_count)); - SVN_ERR(run_threads(pool, hw_thread_count, suggested_iterations, test_pipeline)); - - return SVN_NO_ERROR; -#else - return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL, NULL); -#endif -} - -static svn_error_t * -test_multiprocess(apr_pool_t *pool) -{ - if (!proc_found(TEST_PROC, pool)) - return svn_error_wrap_apr(SVN_ERR_TEST_SKIPPED, - "executable '%s' not found", TEST_PROC); - - SVN_ERR(init_test_shm(pool)); - - SVN_ERR(calibrate_concurrency(pool)); - - SVN_ERR(init_concurrency_test_shm(pool, hw_thread_count)); - SVN_ERR(run_procs(pool, TEST_PROC, hw_thread_count, suggested_iterations)); - - return SVN_NO_ERROR; -} - -/* - ==================================================================== - 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_PASS2(test_basics, - "basic r/w access to a single atomic"), - SVN_TEST_PASS2(test_bignums, - "atomics must be 64 bits"), - SVN_TEST_PASS2(test_multiple_atomics, - "basic r/w access to multiple atomics"), - SVN_TEST_PASS2(test_namespaces, - "use different namespaces"), - SVN_TEST_PASS2(test_multithreaded, - "multithreaded access to atomics"), - SVN_TEST_PASS2(test_multiprocess, - "multi-process access to atomics"), - SVN_TEST_NULL - }; diff --git a/subversion/tests/libsvn_subr/opt-test.c b/subversion/tests/libsvn_subr/opt-test.c index a7c570a..c336d81 100644 --- a/subversion/tests/libsvn_subr/opt-test.c +++ b/subversion/tests/libsvn_subr/opt-test.c @@ -193,7 +193,9 @@ test_svn_opt_args_to_target_array2(apr_pool_t *pool) /* The test table. */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_parse_peg_rev, @@ -202,3 +204,5 @@ struct svn_test_descriptor_t test_funcs[] = "test svn_opt_args_to_target_array2"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/packed-data-test.c b/subversion/tests/libsvn_subr/packed-data-test.c new file mode 100644 index 0000000..d5d6a20 --- /dev/null +++ b/subversion/tests/libsvn_subr/packed-data-test.c @@ -0,0 +1,577 @@ +/* + * packed-data-test.c: a collection of svn_packed__* tests + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + +/* ==================================================================== + To add tests, look toward the bottom of this file. + +*/ + + + +#include <stdio.h> +#include <string.h> +#include <apr_pools.h> + +#include "../svn_test.h" + +#include "svn_error.h" +#include "svn_string.h" /* This includes <apr_*.h> */ +#include "private/svn_packed_data.h" + +/* Take the WRITE_ROOT, serialize its contents, parse it again into a new + * data root and return it in *READ_ROOT. Allocate it in POOL. + */ +static svn_error_t* +get_read_root(svn_packed__data_root_t **read_root, + svn_packed__data_root_t *write_root, + apr_pool_t *pool) +{ + svn_stringbuf_t *stream_buffer = svn_stringbuf_create_empty(pool); + svn_stream_t *stream; + + stream = svn_stream_from_stringbuf(stream_buffer, pool); + SVN_ERR(svn_packed__data_write(stream, write_root, pool)); + SVN_ERR(svn_stream_close(stream)); + + stream = svn_stream_from_stringbuf(stream_buffer, pool); + SVN_ERR(svn_packed__data_read(read_root, stream, pool, pool)); + SVN_ERR(svn_stream_close(stream)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_empty_container(apr_pool_t *pool) +{ + /* create an empty, readable container */ + svn_packed__data_root_t *root = svn_packed__data_create_root(pool); + SVN_ERR(get_read_root(&root, root, pool)); + + /* there should be no sub-streams */ + SVN_TEST_ASSERT(svn_packed__first_int_stream(root) == NULL); + SVN_TEST_ASSERT(svn_packed__first_byte_stream(root) == NULL); + + return SVN_NO_ERROR; +} + +/* Check that COUNT numbers from VALUES can be written as uints to a + * packed data stream and can be read from that stream again. Deltify + * data in the stream if DIFF is set. Use POOL for allocations. + */ +static svn_error_t * +verify_uint_stream(const apr_uint64_t *values, + apr_size_t count, + svn_boolean_t diff, + apr_pool_t *pool) +{ + svn_packed__data_root_t *root = svn_packed__data_create_root(pool); + svn_packed__int_stream_t *stream + = svn_packed__create_int_stream(root, diff, FALSE); + + apr_size_t i; + for (i = 0; i < count; ++i) + svn_packed__add_uint(stream, values[i]); + + SVN_ERR(get_read_root(&root, root, pool)); + + /* the container should contain exactly one int stream */ + stream = svn_packed__first_int_stream(root); + SVN_TEST_ASSERT(stream); + SVN_TEST_ASSERT(!svn_packed__next_int_stream(stream)); + SVN_TEST_ASSERT(!svn_packed__first_byte_stream(root)); + + /* the stream shall contain exactly the items we put into it */ + SVN_TEST_ASSERT(svn_packed__int_count(stream) == count); + for (i = 0; i < count; ++i) + SVN_TEST_ASSERT(svn_packed__get_uint(stream) == values[i]); + + /* reading beyond eos should return 0 values */ + SVN_TEST_ASSERT(svn_packed__get_uint(stream) == 0); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_uint_stream(apr_pool_t *pool) +{ + enum { COUNT = 8 }; + const apr_uint64_t values[COUNT] = + { + APR_UINT64_MAX, + 0, + APR_UINT64_MAX, + APR_UINT64_C(0x8000000000000000), + 0, + APR_UINT64_C(0x7fffffffffffffff), + APR_UINT64_C(0x1234567890abcdef), + APR_UINT64_C(0x0fedcba987654321), + }; + + SVN_ERR(verify_uint_stream(values, COUNT, FALSE, pool)); + SVN_ERR(verify_uint_stream(values, COUNT, TRUE, pool)); + + return SVN_NO_ERROR; +} + +/* Check that COUNT numbers from VALUES can be written as signed ints to a + * packed data stream and can be read from that stream again. Deltify + * data in the stream if DIFF is set. Use POOL for allocations. + */ +static svn_error_t * +verify_int_stream(const apr_int64_t *values, + apr_size_t count, + svn_boolean_t diff, + apr_pool_t *pool) +{ + svn_packed__data_root_t *root = svn_packed__data_create_root(pool); + svn_packed__int_stream_t *stream + = svn_packed__create_int_stream(root, diff, TRUE); + + apr_size_t i; + for (i = 0; i < count; ++i) + svn_packed__add_int(stream, values[i]); + + SVN_ERR(get_read_root(&root, root, pool)); + + /* the container should contain exactly one int stream */ + stream = svn_packed__first_int_stream(root); + SVN_TEST_ASSERT(stream); + SVN_TEST_ASSERT(!svn_packed__next_int_stream(stream)); + SVN_TEST_ASSERT(!svn_packed__first_byte_stream(root)); + + /* the stream shall contain exactly the items we put into it */ + SVN_TEST_ASSERT(svn_packed__int_count(stream) == count); + for (i = 0; i < count; ++i) + SVN_TEST_ASSERT(svn_packed__get_int(stream) == values[i]); + + /* reading beyond eos should return 0 values */ + SVN_TEST_ASSERT(svn_packed__get_int(stream) == 0); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_int_stream(apr_pool_t *pool) +{ + enum { COUNT = 7 }; + const apr_int64_t values[COUNT] = + { + APR_INT64_MAX, /* extreme value */ + APR_INT64_MIN, /* other extreme, creating maximum delta to predecessor */ + 0, /* delta to predecessor > APR_INT64_MAX */ + APR_INT64_MAX, /* max value, again */ + -APR_INT64_MAX, /* _almost_ min value, almost max delta */ + APR_INT64_C(0x1234567890abcdef), /* some arbitrary value */ + -APR_INT64_C(0x0fedcba987654321), /* arbitrary value, different sign */ + }; + + SVN_ERR(verify_int_stream(values, COUNT, FALSE, pool)); + SVN_ERR(verify_int_stream(values, COUNT, TRUE, pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_byte_stream(apr_pool_t *pool) +{ + enum { COUNT = 6 }; + const svn_string_t values[COUNT] = + { + { "", 0 }, + { "\0", 1 }, + { "\0", 1 }, + { "some text", 9 }, + { "", 0 }, + { "some more", 9 } + }; + + svn_packed__data_root_t *root = svn_packed__data_create_root(pool); + svn_packed__byte_stream_t *stream + = svn_packed__create_bytes_stream(root); + + apr_size_t i; + for (i = 0; i < COUNT; ++i) + svn_packed__add_bytes(stream, values[i].data, values[i].len); + + SVN_ERR(get_read_root(&root, root, pool)); + + /* the container should contain exactly one byte stream */ + stream = svn_packed__first_byte_stream(root); + SVN_TEST_ASSERT(stream); + SVN_TEST_ASSERT(!svn_packed__next_byte_stream(stream)); + + /* the stream shall contain exactly the items we put into it */ + SVN_TEST_ASSERT(svn_packed__byte_count(stream) == 20); + for (i = 0; i < COUNT; ++i) + { + svn_string_t string; + string.data = svn_packed__get_bytes(stream, &string.len); + + SVN_TEST_ASSERT(string.len == values[i].len); + SVN_TEST_ASSERT(!memcmp(string.data, values[i].data, string.len)); + } + + /* reading beyond eos should return 0 values */ + SVN_TEST_ASSERT(svn_packed__byte_count(stream) == 0); + + return SVN_NO_ERROR; +} + +/* Some simple structure that we use as sub-structure to BASE_RECORD_T. + * Have it contain numbers and strings. + */ +typedef struct sub_record_t +{ + int sub_counter; + svn_string_t text; +} sub_record_t; + +/* signed / unsigned, 64 bits and shorter, diff-able and not, multiple + * strings, multiple sub-records. */ +typedef struct base_record_t +{ + int counter; + svn_string_t description; + apr_uint64_t large_unsigned1; + apr_uint64_t large_unsigned2; + const sub_record_t *left_subs; + apr_int64_t large_signed1; + apr_int64_t large_signed2; + unsigned prime; + const sub_record_t *right_subs; + svn_string_t binary; +} base_record_t; + +/* our test data */ +enum {SUB_RECORD_COUNT = 7}; +enum {BASE_RECORD_COUNT = 4}; + +static const sub_record_t sub_records[SUB_RECORD_COUNT] = +{ + { 6, { "this is quite a longish piece of text", 37} }, + { 5, { "x", 1} }, + { 4, { "not empty", 9} }, + { 3, { "another bit of text", 19} }, + { 2, { "", 0} }, + { 1, { "first sub-record", 16} }, + { 0 } +}; + +static const base_record_t test_data[BASE_RECORD_COUNT] = +{ + { 1, { "maximum", 7}, + APR_UINT64_MAX, APR_UINT64_MAX, sub_records, + APR_INT64_MAX, APR_INT64_MAX, 9967, sub_records + 1, + { "\0\1\2\3\4\5\6\7\x8\x9\xa", 11} }, + + { 2, { "minimum", 7}, + 0, 0, sub_records + 6, + APR_INT64_MIN, APR_INT64_MIN, 6029, sub_records + 5, + { "X\0\0Y", 4} }, + + { 3, { "mean", 4}, + APR_UINT64_C(0x8000000000000000), APR_UINT64_C(0x8000000000000000), + sub_records + 2, + 0, 0, 653, sub_records + 3, + { "\xff\0\1\2\3\4\5\6\7\x8\x9\xa", 12} }, + + { 4, { "random", 6}, + APR_UINT64_C(0x1234567890abcdef), APR_UINT64_C(0xfedcba987654321), + sub_records + 4, + APR_INT64_C(0x1234567890abcd), APR_INT64_C(-0xedcba987654321), 7309, + sub_records + 1, + { "\x80\x7f\0\1\6", 5} } +}; + +/* Serialize RECORDS into INT_STREAM and TEXT_STREAM. Stop when the + * current record's SUB_COUNTER is 0. + */ +static unsigned +pack_subs(svn_packed__int_stream_t *int_stream, + svn_packed__byte_stream_t *text_stream, + const sub_record_t *records) +{ + unsigned count; + for (count = 0; records[count].sub_counter; ++count) + { + svn_packed__add_int(int_stream, records[count].sub_counter); + svn_packed__add_bytes(text_stream, + records[count].text.data, + records[count].text.len); + } + + return count; +} + +/* Serialize COUNT records starting from DATA into a packed data container + * allocated in POOL and return the container root. + */ +static svn_packed__data_root_t * +pack(const base_record_t *data, + apr_size_t count, + apr_pool_t *pool) +{ + apr_size_t i; + svn_packed__data_root_t *root = svn_packed__data_create_root(pool); + svn_packed__int_stream_t *base_stream + = svn_packed__create_int_stream(root, FALSE, FALSE); + svn_packed__int_stream_t *sub_count_stream + = svn_packed__create_int_stream(root, TRUE, FALSE); + + svn_packed__int_stream_t *left_sub_stream + = svn_packed__create_int_stream(root, FALSE, TRUE); + svn_packed__int_stream_t *right_sub_stream + = svn_packed__create_int_stream(root, FALSE, TRUE); + + svn_packed__byte_stream_t *base_description_stream + = svn_packed__create_bytes_stream(root); + svn_packed__byte_stream_t *base_binary_stream + = svn_packed__create_bytes_stream(root); + svn_packed__byte_stream_t *sub_text_stream + = svn_packed__create_bytes_stream(root); + + svn_packed__create_int_substream(base_stream, TRUE, TRUE); /* counter */ + svn_packed__create_int_substream(base_stream, TRUE, FALSE); /* large_unsigned1 */ + svn_packed__create_int_substream(base_stream, FALSE, FALSE); /* large_unsigned2 */ + svn_packed__create_int_substream(base_stream, TRUE, TRUE); /* large_signed1 */ + svn_packed__create_int_substream(base_stream, FALSE, TRUE); /* large_signed2 */ + svn_packed__create_int_substream(base_stream, TRUE, FALSE); /* prime */ + + for (i = 0; i < count; ++i) + { + svn_packed__add_int(base_stream, data[i].counter); + svn_packed__add_bytes(base_description_stream, + data[i].description.data, + data[i].description.len); + svn_packed__add_uint(base_stream, data[i].large_unsigned1); + svn_packed__add_uint(base_stream, data[i].large_unsigned2); + svn_packed__add_uint(sub_count_stream, + pack_subs(left_sub_stream, sub_text_stream, + data[i].left_subs)); + + svn_packed__add_int(base_stream, data[i].large_signed1); + svn_packed__add_int(base_stream, data[i].large_signed2); + svn_packed__add_uint(base_stream, data[i].prime); + svn_packed__add_uint(sub_count_stream, + pack_subs(right_sub_stream, sub_text_stream, + data[i].right_subs)); + + svn_packed__add_bytes(base_binary_stream, + data[i].binary.data, + data[i].binary.len); + } + + return root; +} + +/* Deserialize COUNT records from INT_STREAM and TEXT_STREAM and return + * the result allocated in POOL. + */ +static sub_record_t * +unpack_subs(svn_packed__int_stream_t *int_stream, + svn_packed__byte_stream_t *text_stream, + apr_size_t count, + apr_pool_t *pool) +{ + sub_record_t *records = apr_pcalloc(pool, (count + 1) * sizeof(*records)); + + apr_size_t i; + for (i = 0; i < count; ++i) + { + records[i].sub_counter = (int) svn_packed__get_int(int_stream); + records[i].text.data = svn_packed__get_bytes(text_stream, + &records[i].text.len); + } + + return records; +} + +/* Deserialize all records from the packed data container ROOT, allocate + * them in POOL and return them. Set *COUNT to the number of records read. + */ +static base_record_t * +unpack(apr_size_t *count, + svn_packed__data_root_t *root, + apr_pool_t *pool) +{ + svn_packed__int_stream_t *base_stream + = svn_packed__first_int_stream(root); + svn_packed__int_stream_t *sub_count_stream + = svn_packed__next_int_stream(base_stream); + svn_packed__byte_stream_t *base_description_stream + = svn_packed__first_byte_stream(root); + svn_packed__byte_stream_t *base_binary_stream + = svn_packed__next_byte_stream(base_description_stream); + svn_packed__byte_stream_t *sub_text_stream + = svn_packed__next_byte_stream(base_binary_stream); + + svn_packed__int_stream_t *left_sub_stream + = svn_packed__next_int_stream(sub_count_stream); + svn_packed__int_stream_t *right_sub_stream + = svn_packed__next_int_stream(left_sub_stream); + + apr_size_t i; + base_record_t *data; + *count = svn_packed__int_count(sub_count_stream) / 2; + data = apr_pcalloc(pool, *count * sizeof(*data)); + + for (i = 0; i < *count; ++i) + { + data[i].counter = (int) svn_packed__get_int(base_stream); + data[i].description.data + = svn_packed__get_bytes(base_description_stream, + &data[i].description.len); + data[i].large_unsigned1 = svn_packed__get_uint(base_stream); + data[i].large_unsigned2 = svn_packed__get_uint(base_stream); + data[i].left_subs = unpack_subs(left_sub_stream, sub_text_stream, + (apr_size_t)svn_packed__get_uint(sub_count_stream), + pool); + + data[i].large_signed1 = svn_packed__get_int(base_stream); + data[i].large_signed2 = svn_packed__get_int(base_stream); + data[i].prime = (unsigned) svn_packed__get_uint(base_stream); + data[i].right_subs = unpack_subs(right_sub_stream, sub_text_stream, + (apr_size_t)svn_packed__get_uint(sub_count_stream), + pool); + + data[i].binary.data + = svn_packed__get_bytes(base_binary_stream, + &data[i].binary.len); + } + + return data; +} + +/* Assert that LHS and RHS contain the same binary data (i.e. don't test + * for a terminating NUL). + */ +static svn_error_t * +compare_binary(const svn_string_t *lhs, + const svn_string_t *rhs) +{ + SVN_TEST_ASSERT(lhs->len == rhs->len); + SVN_TEST_ASSERT(!memcmp(lhs->data, rhs->data, rhs->len)); + + return SVN_NO_ERROR; +} + +/* Assert that LHS and RHS contain the same number of records with the + * same contents. + */ +static svn_error_t * +compare_subs(const sub_record_t *lhs, + const sub_record_t *rhs) +{ + for (; lhs->sub_counter; ++lhs, ++rhs) + { + SVN_TEST_ASSERT(lhs->sub_counter == rhs->sub_counter); + SVN_ERR(compare_binary(&lhs->text, &rhs->text)); + } + + SVN_TEST_ASSERT(lhs->sub_counter == rhs->sub_counter); + return SVN_NO_ERROR; +} + +/* Assert that the first COUNT records in LHS and RHS have the same contents. + */ +static svn_error_t * +compare(const base_record_t *lhs, + const base_record_t *rhs, + apr_size_t count) +{ + apr_size_t i; + for (i = 0; i < count; ++i) + { + SVN_TEST_ASSERT(lhs[i].counter == rhs[i].counter); + SVN_ERR(compare_binary(&lhs[i].description, &rhs[i].description)); + SVN_TEST_ASSERT(lhs[i].large_unsigned1 == rhs[i].large_unsigned1); + SVN_TEST_ASSERT(lhs[i].large_unsigned2 == rhs[i].large_unsigned2); + SVN_ERR(compare_subs(lhs[i].left_subs, rhs[i].left_subs)); + SVN_TEST_ASSERT(lhs[i].counter == rhs[i].counter); + SVN_TEST_ASSERT(lhs[i].large_signed1 == rhs[i].large_signed1); + SVN_TEST_ASSERT(lhs[i].large_signed2 == rhs[i].large_signed2); + SVN_TEST_ASSERT(lhs[i].prime == rhs[i].prime); + SVN_ERR(compare_subs(lhs[i].right_subs, rhs[i].right_subs)); + SVN_ERR(compare_binary(&lhs[i].binary, &rhs[i].binary)); + } + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_empty_structure(apr_pool_t *pool) +{ + base_record_t *unpacked; + apr_size_t count; + + /* create an empty, readable container */ + svn_packed__data_root_t *root = pack(test_data, 0, pool); + + SVN_ERR(get_read_root(&root, root, pool)); + unpacked = unpack(&count, root, pool); + SVN_TEST_ASSERT(count == 0); + SVN_ERR(compare(unpacked, test_data, count)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_full_structure(apr_pool_t *pool) +{ + base_record_t *unpacked; + apr_size_t count; + + /* create an empty, readable container */ + svn_packed__data_root_t *root = pack(test_data, BASE_RECORD_COUNT, pool); + + SVN_ERR(get_read_root(&root, root, pool)); + unpacked = unpack(&count, root, pool); + SVN_TEST_ASSERT(count == BASE_RECORD_COUNT); + SVN_ERR(compare(unpacked, test_data, count)); + + return SVN_NO_ERROR; +} + +/* An array of all test functions */ + +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = + { + SVN_TEST_NULL, + SVN_TEST_PASS2(test_empty_container, + "test empty container"), + SVN_TEST_PASS2(test_uint_stream, + "test a single uint stream"), + SVN_TEST_PASS2(test_int_stream, + "test a single int stream"), + SVN_TEST_PASS2(test_byte_stream, + "test a single bytes stream"), + SVN_TEST_PASS2(test_empty_structure, + "test empty, nested structure"), + SVN_TEST_PASS2(test_full_structure, + "test nested structure"), + SVN_TEST_NULL + }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/path-test.c b/subversion/tests/libsvn_subr/path-test.c index ec35176..6f0a996 100644 --- a/subversion/tests/libsvn_subr/path-test.c +++ b/subversion/tests/libsvn_subr/path-test.c @@ -315,9 +315,9 @@ test_uri_decode(apr_pool_t *pool) const char *path; const char *result; } tests[] = { - { "http://c.r.a/s%\0008me", + { "http://c.r.a/s%\0" "8me", "http://c.r.a/s%"}, - { "http://c.r.a/s%6\000me", + { "http://c.r.a/s%6\0" "me", "http://c.r.a/s%6" }, { "http://c.r.a/s%68me", "http://c.r.a/shme" }, @@ -489,7 +489,7 @@ test_path_join(apr_pool_t *pool) if (svn_path_is_url(base)) continue; - result = svn_path_join_many(pool, base, comp, NULL); + result = svn_path_join_many(pool, base, comp, SVN_VA_NULL); if (strcmp(result, expect)) return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, "svn_path_join_many(\"%s\", \"%s\") returned " @@ -505,74 +505,74 @@ test_path_join(apr_pool_t *pool) "expected \"%s\"", \ result, expect); - TEST_MANY((pool, "abc", NULL), "abc"); - TEST_MANY((pool, "/abc", NULL), "/abc"); - TEST_MANY((pool, "/", NULL), "/"); - - TEST_MANY((pool, "abc", "def", "ghi", NULL), "abc/def/ghi"); - TEST_MANY((pool, "abc", "/def", "ghi", NULL), "/def/ghi"); - TEST_MANY((pool, "/abc", "def", "ghi", NULL), "/abc/def/ghi"); - TEST_MANY((pool, "abc", "def", "/ghi", NULL), "/ghi"); - TEST_MANY((pool, "/", "def", "/ghi", NULL), "/ghi"); - TEST_MANY((pool, "/", "/def", "/ghi", NULL), "/ghi"); - - TEST_MANY((pool, SVN_EMPTY_PATH, "def", "ghi", NULL), "def/ghi"); - TEST_MANY((pool, "abc", SVN_EMPTY_PATH, "ghi", NULL), "abc/ghi"); - TEST_MANY((pool, "abc", "def", SVN_EMPTY_PATH, NULL), "abc/def"); - TEST_MANY((pool, SVN_EMPTY_PATH, "def", SVN_EMPTY_PATH, NULL), "def"); - TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "ghi", NULL), "ghi"); - TEST_MANY((pool, "abc", SVN_EMPTY_PATH, SVN_EMPTY_PATH, NULL), "abc"); - TEST_MANY((pool, SVN_EMPTY_PATH, "def", "/ghi", NULL), "/ghi"); - TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "/ghi", NULL), "/ghi"); - - TEST_MANY((pool, "/", "def", "ghi", NULL), "/def/ghi"); - TEST_MANY((pool, "abc", "/", "ghi", NULL), "/ghi"); - TEST_MANY((pool, "abc", "def", "/", NULL), "/"); - TEST_MANY((pool, "/", "/", "ghi", NULL), "/ghi"); - TEST_MANY((pool, "/", "/", "/", NULL), "/"); - TEST_MANY((pool, "/", SVN_EMPTY_PATH, "ghi", NULL), "/ghi"); - TEST_MANY((pool, "/", "def", SVN_EMPTY_PATH, NULL), "/def"); - TEST_MANY((pool, SVN_EMPTY_PATH, "/", "ghi", NULL), "/ghi"); - TEST_MANY((pool, "/", SVN_EMPTY_PATH, SVN_EMPTY_PATH, NULL), "/"); - TEST_MANY((pool, SVN_EMPTY_PATH, "/", SVN_EMPTY_PATH, NULL), "/"); - TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "/", NULL), "/"); + TEST_MANY((pool, "abc", SVN_VA_NULL), "abc"); + TEST_MANY((pool, "/abc", SVN_VA_NULL), "/abc"); + TEST_MANY((pool, "/", SVN_VA_NULL), "/"); + + TEST_MANY((pool, "abc", "def", "ghi", SVN_VA_NULL), "abc/def/ghi"); + TEST_MANY((pool, "abc", "/def", "ghi", SVN_VA_NULL), "/def/ghi"); + TEST_MANY((pool, "/abc", "def", "ghi", SVN_VA_NULL), "/abc/def/ghi"); + TEST_MANY((pool, "abc", "def", "/ghi", SVN_VA_NULL), "/ghi"); + TEST_MANY((pool, "/", "def", "/ghi", SVN_VA_NULL), "/ghi"); + TEST_MANY((pool, "/", "/def", "/ghi", SVN_VA_NULL), "/ghi"); + + TEST_MANY((pool, SVN_EMPTY_PATH, "def", "ghi", SVN_VA_NULL), "def/ghi"); + TEST_MANY((pool, "abc", SVN_EMPTY_PATH, "ghi", SVN_VA_NULL), "abc/ghi"); + TEST_MANY((pool, "abc", "def", SVN_EMPTY_PATH, SVN_VA_NULL), "abc/def"); + TEST_MANY((pool, SVN_EMPTY_PATH, "def", SVN_EMPTY_PATH, SVN_VA_NULL), "def"); + TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "ghi", SVN_VA_NULL), "ghi"); + TEST_MANY((pool, "abc", SVN_EMPTY_PATH, SVN_EMPTY_PATH, SVN_VA_NULL), "abc"); + TEST_MANY((pool, SVN_EMPTY_PATH, "def", "/ghi", SVN_VA_NULL), "/ghi"); + TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "/ghi", SVN_VA_NULL), "/ghi"); + + TEST_MANY((pool, "/", "def", "ghi", SVN_VA_NULL), "/def/ghi"); + TEST_MANY((pool, "abc", "/", "ghi", SVN_VA_NULL), "/ghi"); + TEST_MANY((pool, "abc", "def", "/", SVN_VA_NULL), "/"); + TEST_MANY((pool, "/", "/", "ghi", SVN_VA_NULL), "/ghi"); + TEST_MANY((pool, "/", "/", "/", SVN_VA_NULL), "/"); + TEST_MANY((pool, "/", SVN_EMPTY_PATH, "ghi", SVN_VA_NULL), "/ghi"); + TEST_MANY((pool, "/", "def", SVN_EMPTY_PATH, SVN_VA_NULL), "/def"); + TEST_MANY((pool, SVN_EMPTY_PATH, "/", "ghi", SVN_VA_NULL), "/ghi"); + TEST_MANY((pool, "/", SVN_EMPTY_PATH, SVN_EMPTY_PATH, SVN_VA_NULL), "/"); + TEST_MANY((pool, SVN_EMPTY_PATH, "/", SVN_EMPTY_PATH, SVN_VA_NULL), "/"); + TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "/", SVN_VA_NULL), "/"); #ifdef SVN_USE_DOS_PATHS /* These will fail, see issue #2028 - TEST_MANY((pool, "X:", "def", "ghi", NULL), "X:def/ghi"); - TEST_MANY((pool, "X:", SVN_EMPTY_PATH, "ghi", NULL), "X:ghi"); - TEST_MANY((pool, "X:", "def", SVN_EMPTY_PATH, NULL), "X:def"); - TEST_MANY((pool, SVN_EMPTY_PATH, "X:", "ghi", NULL), "X:ghi"); - TEST_MANY((pool, "X:/", "def", "ghi", NULL), "X:/def/ghi"); - TEST_MANY((pool, "abc", "X:/", "ghi", NULL), "X:/ghi"); - TEST_MANY((pool, "abc", "def", "X:/", NULL), "X:/"); - TEST_MANY((pool, "X:/", "X:/", "ghi", NULL), "X:/ghi"); - TEST_MANY((pool, "X:/", "X:/", "/", NULL), "/"); - TEST_MANY((pool, "X:/", SVN_EMPTY_PATH, "ghi", NULL), "X:/ghi"); - TEST_MANY((pool, "X:/", "def", SVN_EMPTY_PATH, NULL), "X:/def"); - TEST_MANY((pool, SVN_EMPTY_PATH, "X:/", "ghi", NULL), "X:/ghi"); - TEST_MANY((pool, "X:/", SVN_EMPTY_PATH, SVN_EMPTY_PATH, NULL), "X:/"); - TEST_MANY((pool, SVN_EMPTY_PATH, "X:/", SVN_EMPTY_PATH, NULL), "X:/"); - TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "X:/", NULL), "X:/"); - TEST_MANY((pool, "X:", "X:/", "ghi", NULL), "X:/ghi"); - TEST_MANY((pool, "X:", "X:/", "/", NULL), "/"); - - TEST_MANY((pool, "//srv/shr", "def", "ghi", NULL), "//srv/shr/def/ghi"); - TEST_MANY((pool, "//srv", "shr", "def", "ghi", NULL), "//srv/shr/def/ghi"); - TEST_MANY((pool, "//srv/shr/fld", "def", "ghi", NULL), + TEST_MANY((pool, "X:", "def", "ghi", SVN_VA_NULL), "X:def/ghi"); + TEST_MANY((pool, "X:", SVN_EMPTY_PATH, "ghi", SVN_VA_NULL), "X:ghi"); + TEST_MANY((pool, "X:", "def", SVN_EMPTY_PATH, SVN_VA_NULL), "X:def"); + TEST_MANY((pool, SVN_EMPTY_PATH, "X:", "ghi", SVN_VA_NULL), "X:ghi"); + TEST_MANY((pool, "X:/", "def", "ghi", SVN_VA_NULL), "X:/def/ghi"); + TEST_MANY((pool, "abc", "X:/", "ghi", SVN_VA_NULL), "X:/ghi"); + TEST_MANY((pool, "abc", "def", "X:/", SVN_VA_NULL), "X:/"); + TEST_MANY((pool, "X:/", "X:/", "ghi", SVN_VA_NULL), "X:/ghi"); + TEST_MANY((pool, "X:/", "X:/", "/", SVN_VA_NULL), "/"); + TEST_MANY((pool, "X:/", SVN_EMPTY_PATH, "ghi", SVN_VA_NULL), "X:/ghi"); + TEST_MANY((pool, "X:/", "def", SVN_EMPTY_PATH, SVN_VA_NULL), "X:/def"); + TEST_MANY((pool, SVN_EMPTY_PATH, "X:/", "ghi", SVN_VA_NULL), "X:/ghi"); + TEST_MANY((pool, "X:/", SVN_EMPTY_PATH, SVN_EMPTY_PATH, SVN_VA_NULL), "X:/"); + TEST_MANY((pool, SVN_EMPTY_PATH, "X:/", SVN_EMPTY_PATH, SVN_VA_NULL), "X:/"); + TEST_MANY((pool, SVN_EMPTY_PATH, SVN_EMPTY_PATH, "X:/", SVN_VA_NULL), "X:/"); + TEST_MANY((pool, "X:", "X:/", "ghi", SVN_VA_NULL), "X:/ghi"); + TEST_MANY((pool, "X:", "X:/", "/", SVN_VA_NULL), "/"); + + TEST_MANY((pool, "//srv/shr", "def", "ghi", SVN_VA_NULL), "//srv/shr/def/ghi"); + TEST_MANY((pool, "//srv", "shr", "def", "ghi", SVN_VA_NULL), "//srv/shr/def/ghi"); + TEST_MANY((pool, "//srv/shr/fld", "def", "ghi", SVN_VA_NULL), "//srv/shr/fld/def/ghi"); - TEST_MANY((pool, "//srv/shr/fld", "def", "//srv/shr", NULL), "//srv/shr"); - TEST_MANY((pool, "//srv", "shr", "//srv/shr", NULL), "//srv/shr"); - TEST_MANY((pool, SVN_EMPTY_PATH, "//srv/shr/fld", "def", "ghi", NULL), + TEST_MANY((pool, "//srv/shr/fld", "def", "//srv/shr", SVN_VA_NULL), "//srv/shr"); + TEST_MANY((pool, "//srv", "shr", "//srv/shr", SVN_VA_NULL), "//srv/shr"); + TEST_MANY((pool, SVN_EMPTY_PATH, "//srv/shr/fld", "def", "ghi", SVN_VA_NULL), "//srv/shr/fld/def/ghi"); - TEST_MANY((pool, SVN_EMPTY_PATH, "//srv/shr/fld", "def", "//srv/shr", NULL), + TEST_MANY((pool, SVN_EMPTY_PATH, "//srv/shr/fld", "def", "//srv/shr", SVN_VA_NULL), "//srv/shr"); */ #else /* WIN32 or Cygwin */ - TEST_MANY((pool, "X:", "def", "ghi", NULL), "X:/def/ghi"); - TEST_MANY((pool, "X:", SVN_EMPTY_PATH, "ghi", NULL), "X:/ghi"); - TEST_MANY((pool, "X:", "def", SVN_EMPTY_PATH, NULL), "X:/def"); - TEST_MANY((pool, SVN_EMPTY_PATH, "X:", "ghi", NULL), "X:/ghi"); + TEST_MANY((pool, "X:", "def", "ghi", SVN_VA_NULL), "X:/def/ghi"); + TEST_MANY((pool, "X:", SVN_EMPTY_PATH, "ghi", SVN_VA_NULL), "X:/ghi"); + TEST_MANY((pool, "X:", "def", SVN_EMPTY_PATH, SVN_VA_NULL), "X:/def"); + TEST_MANY((pool, SVN_EMPTY_PATH, "X:", "ghi", SVN_VA_NULL), "X:/ghi"); #endif /* non-WIN32 */ /* ### probably need quite a few more tests... */ @@ -1210,6 +1210,7 @@ test_path_splitext(apr_pool_t *pool) { "yep.still/no-ext", "yep.still/no-ext", "" }, { "folder.with/period.log", "folder.with/period.", "log" }, { "period.", "period.", "" }, + { "dir/period.", "dir/period.", "" }, { "file.ends-with/period.", "file.ends-with/period.", "" }, { "two-periods..txt", "two-periods..", "txt" }, { ".dot-file", ".dot-file", "" }, @@ -1527,7 +1528,7 @@ condense_targets_tests_helper(const char* title, /* Verify the common part with the expected (prefix with cwd). */ if (*exp_common == '%') - exp_common_abs = apr_pstrcat(pool, curdir, exp_common + 1, (char *)NULL); + exp_common_abs = apr_pstrcat(pool, curdir, exp_common + 1, SVN_VA_NULL); if (strcmp(common_path, exp_common_abs) != 0) { @@ -1544,7 +1545,7 @@ condense_targets_tests_helper(const char* title, { const char * target = APR_ARRAY_IDX(condensed_targets, i, const char*); if (token && (*token == '%')) - token = apr_pstrcat(pool, curdir, token + 1, (char *)NULL); + token = apr_pstrcat(pool, curdir, token + 1, SVN_VA_NULL); if (! token || (target && (strcmp(target, token) != 0))) { @@ -1700,7 +1701,9 @@ test_path_resolve_repos_relative_url(apr_pool_t *pool) /* The test table. */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_path_is_child, @@ -1759,3 +1762,5 @@ struct svn_test_descriptor_t test_funcs[] = "test svn_path_resolve_repos_relative_url"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/prefix-string-test.c b/subversion/tests/libsvn_subr/prefix-string-test.c new file mode 100644 index 0000000..e420cff --- /dev/null +++ b/subversion/tests/libsvn_subr/prefix-string-test.c @@ -0,0 +1,154 @@ +/* + * prefix-string-test.c: a collection of svn_prefix_string__* tests + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + +/* ==================================================================== + To add tests, look toward the bottom of this file. + +*/ + + + +#include <stdio.h> +#include <string.h> +#include <apr_pools.h> + +#include "../svn_test.h" + +#include "svn_error.h" +#include "svn_string.h" /* This includes <apr_*.h> */ +#include "private/svn_string_private.h" + +static svn_error_t * +test_empty_string(apr_pool_t *pool) +{ + svn_prefix_tree__t *tree = svn_prefix_tree__create(pool); + svn_prefix_string__t *empty = svn_prefix_string__create(tree, ""); + + /* same instance for all strings of the same value */ + SVN_TEST_ASSERT(empty == svn_prefix_string__create(tree, "")); + + /* does it actually have the right contents? */ + SVN_TEST_ASSERT(svn_prefix_string__expand(empty, pool)->len == 0); + SVN_TEST_STRING_ASSERT(svn_prefix_string__expand(empty, pool)->data, ""); + + /* strings shall be equal to themselves */ + SVN_TEST_ASSERT(0 == svn_prefix_string__compare(empty, empty)); + + return SVN_NO_ERROR; +} + +enum {TEST_CASE_COUNT = 9}; + +static const char *test_cases[TEST_CASE_COUNT] = +{ + "a longish string of sorts, longer than 7 anyway", + "some other string", + "more stuff on root", + "some shorter string", + "some short string", + "some short str", + "some short str2", + "a longish string of sorts, longer than ?! anyway", + "a" +}; + +static svn_error_t * +test_string_creation(apr_pool_t *pool) +{ + svn_prefix_tree__t *tree = svn_prefix_tree__create(pool); + svn_prefix_string__t *strings[TEST_CASE_COUNT]; + int i; + + /* create strings and remember their initial references */ + for (i = 0; i < TEST_CASE_COUNT; ++i) + strings[i] = svn_prefix_string__create(tree, test_cases[i]); + + /* doing this again must yield the same pointers */ + for (i = 0; i < TEST_CASE_COUNT; ++i) + SVN_TEST_ASSERT(strings[i] + == svn_prefix_string__create(tree, test_cases[i])); + + /* converting them back to strings must be the initial values */ + for (i = 0; i < TEST_CASE_COUNT; ++i) + { + svn_string_t *expanded = svn_prefix_string__expand(strings[i], pool); + + SVN_TEST_ASSERT(expanded->len == strlen(test_cases[i])); + SVN_TEST_STRING_ASSERT(expanded->data, test_cases[i]); + + } + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_string_comparison(apr_pool_t *pool) +{ + svn_prefix_tree__t *tree = svn_prefix_tree__create(pool); + svn_prefix_string__t *strings[TEST_CASE_COUNT]; + int i, k; + + /* create strings */ + for (i = 0; i < TEST_CASE_COUNT; ++i) + strings[i] = svn_prefix_string__create(tree, test_cases[i]); + + /* comparing them with themselves */ + for (i = 0; i < TEST_CASE_COUNT; ++i) + SVN_TEST_ASSERT(! svn_prefix_string__compare(strings[i], strings[i])); + + /* compare with all other strings */ + for (i = 0; i < TEST_CASE_COUNT; ++i) + { + svn_string_t *lhs = svn_prefix_string__expand(strings[i], pool); + for (k = 0; k < TEST_CASE_COUNT; ++k) + { + svn_string_t *rhs = svn_prefix_string__expand(strings[k], pool); + int expected_diff = strcmp(lhs->data, rhs->data); + int actual_diff = svn_prefix_string__compare(strings[i], strings[k]); + + SVN_TEST_ASSERT((actual_diff < 0) == (expected_diff < 0)); + SVN_TEST_ASSERT((actual_diff > 0) == (expected_diff > 0)); + SVN_TEST_ASSERT(!actual_diff == !expected_diff); + } + } + + return SVN_NO_ERROR; +} + +/* An array of all test functions */ + +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = + { + SVN_TEST_NULL, + SVN_TEST_PASS2(test_empty_string, + "check empty strings"), + SVN_TEST_PASS2(test_string_creation, + "create many strings"), + SVN_TEST_PASS2(test_string_comparison, + "compare strings"), + SVN_TEST_NULL + }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/priority-queue-test.c b/subversion/tests/libsvn_subr/priority-queue-test.c new file mode 100644 index 0000000..bd2d991 --- /dev/null +++ b/subversion/tests/libsvn_subr/priority-queue-test.c @@ -0,0 +1,240 @@ +/* + * priority-queue-test.c: a collection of svn_priority_queue__* tests + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + +/* ==================================================================== + To add tests, look toward the bottom of this file. + +*/ + + + +#include <stdio.h> +#include <string.h> +#include <apr_pools.h> + +#include "../svn_test.h" + +#include "svn_error.h" +#include "private/svn_sorts_private.h" + +/* priority queue test: + * items in the queue are simple integers, in ascending order */ + +/* number of items to put into the queue */ +enum {NUMBER_COUNT = 11}; + +/* the actual values in the order we add them to the queue */ +static const int numbers[NUMBER_COUNT] + = { 8395, 0, -1, 3885, 1, -435, 99993, 10, 0, 1, 8395 }; + +/* test_update will modify in-queue data and expects the queue to return + the values in the following order: */ +static const int expected_modified[NUMBER_COUNT] + = { -431, 0, 1, 3, 5, 10, 16, 3889, 8395, 8403, 99997 }; + +/* standard compare function for integers */ +static int +compare_func(const void *lhs, const void *rhs) +{ + return *(const int *)lhs - *(const int *)rhs; +} + +/* Check that QUEUE is empty and the usual operations still work */ +static svn_error_t * +verify_empty_queue(svn_priority_queue__t *queue) +{ + /* it's an empty queue */ + SVN_TEST_ASSERT(svn_priority_queue__size(queue) == 0); + SVN_TEST_ASSERT(svn_priority_queue__peek(queue) == NULL); + + /* these should be no-ops */ + svn_priority_queue__update(queue); + svn_priority_queue__pop(queue); + + return SVN_NO_ERROR; +} + +/* check that the tip of QUEUE equals EXPECTED and remove the first element */ +static svn_error_t * +extract_expected(svn_priority_queue__t *queue, int expected) +{ + int value = *(int *)svn_priority_queue__peek(queue); + SVN_TEST_ASSERT(value == expected); + svn_priority_queue__pop(queue); + + return SVN_NO_ERROR; +} + +/* Verify that QUEUE returns all elements in the proper order. + Also check that data can be added & removed without disturbing the order. + */ +static svn_error_t * +verify_queue_order(svn_priority_queue__t *queue) +{ + int sorted[NUMBER_COUNT]; + int i; + + /* reference order */ + memcpy(sorted, numbers, sizeof(numbers)); + qsort(sorted, NUMBER_COUNT, sizeof(sorted[0]), compare_func); + + /* verify that the queue returns the data in the same order */ + for (i = 0; i < NUMBER_COUNT; ++i) + { + int item = *(int *)svn_priority_queue__peek(queue); + int to_insert; + + /* is this the value we expected? */ + SVN_TEST_ASSERT(item == sorted[i]); + + /* add two items at the tip of the queue */ + to_insert = item - 1; + svn_priority_queue__push(queue, &to_insert); + svn_priority_queue__push(queue, &item); + + /* check queue length */ + SVN_TEST_ASSERT(svn_priority_queue__size(queue) == NUMBER_COUNT-i+2); + + /* now, lets extract all 3 of them */ + SVN_ERR(extract_expected(queue, item-1)); + SVN_ERR(extract_expected(queue, item)); + SVN_ERR(extract_expected(queue, item)); + + /* check queue length */ + SVN_TEST_ASSERT(svn_priority_queue__size(queue) == NUMBER_COUNT-i-1); + } + + /* the queue should now be empty */ + verify_empty_queue(queue); + + return SVN_NO_ERROR; +} + +/* return a queue allocated in POOL containing all items of NUMBERS */ +static svn_priority_queue__t * +create_standard_queue(apr_pool_t *pool) +{ + apr_array_header_t *elements + = apr_array_make(pool, 11, sizeof(numbers[0])); + + /* build queue */ + int i; + for (i = 0; i < NUMBER_COUNT; ++i) + APR_ARRAY_PUSH(elements, int) = numbers[i]; + + return svn_priority_queue__create(elements, compare_func); +} + + +static svn_error_t * +test_empty_queue(apr_pool_t *pool) +{ + apr_array_header_t *elements + = apr_array_make(pool, 0, sizeof(int)); + svn_priority_queue__t *queue + = svn_priority_queue__create(elements, compare_func); + + verify_empty_queue(queue); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_sort_queue(apr_pool_t *pool) +{ + svn_priority_queue__t *queue = create_standard_queue(pool); + + /* data should come out of the queue in sorted order */ + SVN_ERR(verify_queue_order(queue)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_push(apr_pool_t *pool) +{ + apr_array_header_t *elements + = apr_array_make(pool, 3, sizeof(int)); + svn_priority_queue__t *queue + = svn_priority_queue__create(elements, compare_func); + + /* build queue */ + int i; + for (i = 0; i < NUMBER_COUNT; ++i) + svn_priority_queue__push(queue, &numbers[i]); + + /* data should come out of the queue in sorted order */ + SVN_ERR(verify_queue_order(queue)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_update(apr_pool_t *pool) +{ + svn_priority_queue__t *queue = create_standard_queue(pool); + + /* modify all items in the queue */ + int i; + for (i = 0; i < NUMBER_COUNT; ++i) + { + int *tip = svn_priority_queue__peek(queue); + *tip += 4; + svn_priority_queue__update(queue); + + /* extract and verify tip */ + SVN_TEST_ASSERT(*(int *)svn_priority_queue__peek(queue) + == expected_modified[i]); + svn_priority_queue__pop(queue); + + /* this should be a no-op now */ + svn_priority_queue__update(queue); + + SVN_TEST_ASSERT(svn_priority_queue__size(queue) == NUMBER_COUNT-i-1); + } + + /* the queue should now be empty */ + verify_empty_queue(queue); + + return SVN_NO_ERROR; +} + +/* An array of all test functions */ + +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = + { + SVN_TEST_NULL, + SVN_TEST_PASS2(test_empty_queue, + "test empty queue"), + SVN_TEST_PASS2(test_sort_queue, + "data returned by a priority queue shall be ordered"), + SVN_TEST_PASS2(test_push, + "priority queues can be built up incrementally"), + SVN_TEST_PASS2(test_update, + "updating the head of the queue"), + SVN_TEST_NULL + }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/revision-test.c b/subversion/tests/libsvn_subr/revision-test.c index 7e5d752..53ca8da 100644 --- a/subversion/tests/libsvn_subr/revision-test.c +++ b/subversion/tests/libsvn_subr/revision-test.c @@ -34,6 +34,12 @@ test_revnum_parse(apr_pool_t *pool) "", "abc", "-456", + "2147483648", + "4294967295", + "4300000000", + "00000000001", + "21474836470", + "999999999999999999999999", NULL }; @@ -41,6 +47,8 @@ test_revnum_parse(apr_pool_t *pool) "0", "12345", "12345ABC", + "0000000001", + "2147483647x", NULL }; @@ -115,10 +123,14 @@ test_revnum_parse(apr_pool_t *pool) /* The test table. */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_revnum_parse, "test svn_revnum_parse"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/root-pools-test.c b/subversion/tests/libsvn_subr/root-pools-test.c new file mode 100644 index 0000000..8116418 --- /dev/null +++ b/subversion/tests/libsvn_subr/root-pools-test.c @@ -0,0 +1,137 @@ +/* + * root-pools-test.c -- test the svn_root_pools__* API + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + +#include <apr_pools.h> +#include <apr_thread_proc.h> +#include <apr_thread_cond.h> + +#include "private/svn_atomic.h" +#include "private/svn_subr_private.h" + +#include "../svn_test.h" + +/* do a few allocations of various sizes from POOL */ +static void +do_some_allocations(apr_pool_t *pool) +{ + int i; + apr_size_t fib = 1, fib1 = 0, fib2 = 0; + for (i = 0; i < 25; ++i) /* fib(25) = 75025 */ + { + apr_pcalloc(pool, fib1); + fib2 = fib1; + fib1 = fib; + fib += fib2; + } +} + +/* allocate, use and recycle a pool from POOLs a few times */ +static void +use_root_pool(svn_root_pools__t *pools) +{ + int i; + for (i = 0; i < 1000; ++i) + { + apr_pool_t *pool = svn_root_pools__acquire_pool(pools); + do_some_allocations(pool); + svn_root_pools__release_pool(pool, pools); + } +} + +#if APR_HAS_THREADS +static void * +APR_THREAD_FUNC thread_func(apr_thread_t *tid, void *data) +{ + /* give all threads a good chance to get started by the scheduler */ + apr_thread_yield(); + + use_root_pool(data); + apr_thread_exit(tid, APR_SUCCESS); + + return NULL; +} +#endif + +static svn_error_t * +test_root_pool(apr_pool_t *pool) +{ + svn_root_pools__t *pools; + SVN_ERR(svn_root_pools__create(&pools)); + use_root_pool(pools); + + return SVN_NO_ERROR; +} + +#define APR_ERR(expr) \ + do { \ + apr_status_t status = (expr); \ + if (status) \ + return svn_error_wrap_apr(status, NULL); \ + } while (0) + +static svn_error_t * +test_root_pool_concurrency(apr_pool_t *pool) +{ +#if APR_HAS_THREADS + /* The svn_root_pools__t container is supposed to be thread-safe. + Do some multi-threaded access and hope that there are no segfaults. + */ + enum { THREAD_COUNT = 10 }; + svn_root_pools__t *pools; + apr_thread_t *threads[THREAD_COUNT]; + int i; + + SVN_ERR(svn_root_pools__create(&pools)); + + for (i = 0; i < THREAD_COUNT; ++i) + APR_ERR(apr_thread_create(&threads[i], NULL, thread_func, pools, pool)); + + /* wait for the threads to finish */ + for (i = 0; i < THREAD_COUNT; ++i) + { + apr_status_t retval; + APR_ERR(apr_thread_join(&retval, threads[i])); + APR_ERR(retval); + } +#endif + + return SVN_NO_ERROR; +} + + +/* The test table. */ + +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = + { + SVN_TEST_NULL, + SVN_TEST_PASS2(test_root_pool, + "test root pool recycling"), + SVN_TEST_SKIP2(test_root_pool_concurrency, + ! APR_HAS_THREADS, + "test concurrent root pool recycling"), + SVN_TEST_NULL + }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/skel-test.c b/subversion/tests/libsvn_subr/skel-test.c index 49fe1a3..9839e6a 100644 --- a/subversion/tests/libsvn_subr/skel-test.c +++ b/subversion/tests/libsvn_subr/skel-test.c @@ -59,7 +59,7 @@ get_empty_string(apr_pool_t *pool) { svn_pool_clear(pool); - return svn_stringbuf_ncreate(0, 0, pool); + return svn_stringbuf_create_empty(pool); } /* Parse a skeleton from a Subversion string. */ @@ -886,7 +886,9 @@ unparse_list(apr_pool_t *pool) /* The test table. */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(parse_implicit_length, @@ -903,3 +905,5 @@ struct svn_test_descriptor_t test_funcs[] = "unparse lists"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/spillbuf-test.c b/subversion/tests/libsvn_subr/spillbuf-test.c index c928dc3..16021b1 100644 --- a/subversion/tests/libsvn_subr/spillbuf-test.c +++ b/subversion/tests/libsvn_subr/spillbuf-test.c @@ -57,10 +57,8 @@ check_read(svn_spillbuf_t *buf, static svn_error_t * -test_spillbuf_basic(apr_pool_t *pool) +test_spillbuf__basic(apr_pool_t *pool, apr_size_t len, svn_spillbuf_t *buf) { - apr_size_t len = strlen(basic_data); /* Don't include basic_data's NUL */ - svn_spillbuf_t *buf = svn_spillbuf__create(len, 10 * len, pool); int i; const char *readptr; apr_size_t readlen; @@ -87,6 +85,22 @@ test_spillbuf_basic(apr_pool_t *pool) return SVN_NO_ERROR; } +static svn_error_t * +test_spillbuf_basic(apr_pool_t *pool) +{ + apr_size_t len = strlen(basic_data); /* Don't include basic_data's NUL */ + svn_spillbuf_t *buf = svn_spillbuf__create(len, 10 * len, pool); + return test_spillbuf__basic(pool, len, buf); +} + +static svn_error_t * +test_spillbuf_basic_spill_all(apr_pool_t *pool) +{ + apr_size_t len = strlen(basic_data); /* Don't include basic_data's NUL */ + svn_spillbuf_t *buf = + svn_spillbuf__create_extended(len, 10 * len, TRUE, TRUE, NULL, pool); + return test_spillbuf__basic(pool, len, buf); +} static svn_error_t * read_callback(svn_boolean_t *stop, @@ -107,12 +121,8 @@ read_callback(svn_boolean_t *stop, static svn_error_t * -test_spillbuf_callback(apr_pool_t *pool) +test_spillbuf__callback(apr_pool_t *pool, svn_spillbuf_t *buf) { - svn_spillbuf_t *buf = svn_spillbuf__create( - sizeof(basic_data) /* blocksize */, - 10 * sizeof(basic_data) /* maxsize */, - pool); int i; int counter; svn_boolean_t exhausted; @@ -133,15 +143,31 @@ test_spillbuf_callback(apr_pool_t *pool) return SVN_NO_ERROR; } - static svn_error_t * -test_spillbuf_file(apr_pool_t *pool) +test_spillbuf_callback(apr_pool_t *pool) { - apr_size_t altsize = sizeof(basic_data) + 2; svn_spillbuf_t *buf = svn_spillbuf__create( - altsize /* blocksize */, - 2 * sizeof(basic_data) /* maxsize */, + sizeof(basic_data) /* blocksize */, + 10 * sizeof(basic_data) /* maxsize */, pool); + return test_spillbuf__callback(pool, buf); +} + +static svn_error_t * +test_spillbuf_callback_spill_all(apr_pool_t *pool) +{ + svn_spillbuf_t *buf = svn_spillbuf__create_extended( + sizeof(basic_data) /* blocksize */, + 10 * sizeof(basic_data) /* maxsize */, + TRUE /* delte on close */, + TRUE /* spill all data */, + NULL, pool); + return test_spillbuf__callback(pool, buf); +} + +static svn_error_t * +test_spillbuf__file(apr_pool_t *pool, apr_size_t altsize, svn_spillbuf_t *buf) +{ int i; const char *readptr; apr_size_t readlen; @@ -203,14 +229,33 @@ test_spillbuf_file(apr_pool_t *pool) return SVN_NO_ERROR; } +static svn_error_t * +test_spillbuf_file(apr_pool_t *pool) +{ + apr_size_t altsize = sizeof(basic_data) + 2; + svn_spillbuf_t *buf = svn_spillbuf__create( + altsize /* blocksize */, + 2 * sizeof(basic_data) /* maxsize */, + pool); + return test_spillbuf__file(pool, altsize, buf); +} static svn_error_t * -test_spillbuf_interleaving(apr_pool_t *pool) +test_spillbuf_file_spill_all(apr_pool_t *pool) { - svn_spillbuf_t *buf = svn_spillbuf__create(8 /* blocksize */, - 15 /* maxsize */, - pool); + apr_size_t altsize = sizeof(basic_data) + 2; + svn_spillbuf_t *buf = svn_spillbuf__create_extended( + altsize /* blocksize */, + 2 * sizeof(basic_data) /* maxsize */, + TRUE /* delte on close */, + TRUE /* spill all data */, + NULL, pool); + return test_spillbuf__file(pool, altsize, buf); +} +static svn_error_t * +test_spillbuf__interleaving(apr_pool_t *pool, svn_spillbuf_t* buf) +{ SVN_ERR(svn_spillbuf__write(buf, "abcdef", 6, pool)); SVN_ERR(svn_spillbuf__write(buf, "ghijkl", 6, pool)); /* now: two blocks: 8 and 4 bytes */ @@ -238,18 +283,36 @@ test_spillbuf_interleaving(apr_pool_t *pool) return SVN_NO_ERROR; } +static svn_error_t * +test_spillbuf_interleaving(apr_pool_t *pool) +{ + svn_spillbuf_t *buf = svn_spillbuf__create(8 /* blocksize */, + 15 /* maxsize */, + pool); + return test_spillbuf__interleaving(pool, buf); +} + +static svn_error_t * +test_spillbuf_interleaving_spill_all(apr_pool_t *pool) +{ + svn_spillbuf_t *buf = svn_spillbuf__create_extended( + 8 /* blocksize */, + 15 /* maxsize */, + TRUE /* delte on close */, + TRUE /* spill all data */, + NULL, pool); + return test_spillbuf__interleaving(pool, buf); +} static svn_error_t * test_spillbuf_reader(apr_pool_t *pool) { - svn_spillbuf_reader_t *sbr; + svn_spillbuf_reader_t *sbr = svn_spillbuf__reader_create(4 /* blocksize */, + 100 /* maxsize */, + pool); apr_size_t amt; char buf[10]; - sbr = svn_spillbuf__reader_create(4 /* blocksize */, - 100 /* maxsize */, - pool); - SVN_ERR(svn_spillbuf__reader_write(sbr, "abcdef", 6, pool)); /* Get a buffer from the underlying reader, and grab a couple bytes. */ @@ -270,13 +333,13 @@ test_spillbuf_reader(apr_pool_t *pool) return SVN_NO_ERROR; } - static svn_error_t * test_spillbuf_stream(apr_pool_t *pool) { - svn_stream_t *stream = svn_stream__from_spillbuf(8 /* blocksize */, - 15 /* maxsize */, - pool); + svn_spillbuf_t *buf = svn_spillbuf__create(4 /* blocksize */, + 100 /* maxsize */, + pool); + svn_stream_t *stream = svn_stream__from_spillbuf(buf, pool); char readbuf[256]; apr_size_t readlen; apr_size_t writelen; @@ -287,7 +350,7 @@ test_spillbuf_stream(apr_pool_t *pool) /* now: two blocks: 8 and 4 bytes */ readlen = 8; - SVN_ERR(svn_stream_read(stream, readbuf, &readlen)); + SVN_ERR(svn_stream_read_full(stream, readbuf, &readlen)); SVN_TEST_ASSERT(readlen == 8 && memcmp(readbuf, "abcdefgh", 8) == 0); /* now: one block: 4 bytes */ @@ -295,7 +358,7 @@ test_spillbuf_stream(apr_pool_t *pool) SVN_ERR(svn_stream_write(stream, "mnopqr", &writelen)); /* now: two blocks: 8 and 2 bytes */ - SVN_ERR(svn_stream_read(stream, readbuf, &readlen)); + SVN_ERR(svn_stream_read_full(stream, readbuf, &readlen)); SVN_TEST_ASSERT(readlen == 8 && memcmp(readbuf, "ijklmnop", 8) == 0); /* now: one block: 2 bytes */ @@ -305,28 +368,23 @@ test_spillbuf_stream(apr_pool_t *pool) SVN_ERR(svn_stream_write(stream, "GHIJKL", &writelen)); /* now: two blocks: 8 and 6 bytes, and 6 bytes spilled to a file */ - SVN_ERR(svn_stream_read(stream, readbuf, &readlen)); + SVN_ERR(svn_stream_read_full(stream, readbuf, &readlen)); SVN_TEST_ASSERT(readlen == 8 && memcmp(readbuf, "qrstuvwx", 8) == 0); readlen = 6; - SVN_ERR(svn_stream_read(stream, readbuf, &readlen)); + SVN_ERR(svn_stream_read_full(stream, readbuf, &readlen)); SVN_TEST_ASSERT(readlen == 6 && memcmp(readbuf, "ABCDEF", 6) == 0); - SVN_ERR(svn_stream_read(stream, readbuf, &readlen)); + SVN_ERR(svn_stream_read_full(stream, readbuf, &readlen)); SVN_TEST_ASSERT(readlen == 6 && memcmp(readbuf, "GHIJKL", 6) == 0); return SVN_NO_ERROR; } - static svn_error_t * -test_spillbuf_rwfile(apr_pool_t *pool) +test_spillbuf__rwfile(apr_pool_t *pool, svn_spillbuf_t *buf) { - svn_spillbuf_t *buf = svn_spillbuf__create(4 /* blocksize */, - 10 /* maxsize */, - pool); - SVN_ERR(svn_spillbuf__write(buf, "abcdef", 6, pool)); SVN_ERR(svn_spillbuf__write(buf, "ghijkl", 6, pool)); SVN_ERR(svn_spillbuf__write(buf, "mnopqr", 6, pool)); @@ -360,14 +418,30 @@ test_spillbuf_rwfile(apr_pool_t *pool) return SVN_NO_ERROR; } - static svn_error_t * -test_spillbuf_eof(apr_pool_t *pool) +test_spillbuf_rwfile(apr_pool_t *pool) { svn_spillbuf_t *buf = svn_spillbuf__create(4 /* blocksize */, 10 /* maxsize */, pool); + return test_spillbuf__rwfile(pool, buf); +} + +static svn_error_t * +test_spillbuf_rwfile_spill_all(apr_pool_t *pool) +{ + svn_spillbuf_t *buf = svn_spillbuf__create_extended( + 4 /* blocksize */, + 10 /* maxsize */, + TRUE /* delte on close */, + TRUE /* spill all data */, + NULL, pool); + return test_spillbuf__rwfile(pool, buf); +} +static svn_error_t * +test_spillbuf__eof(apr_pool_t *pool, svn_spillbuf_t *buf) +{ SVN_ERR(svn_spillbuf__write(buf, "abcdef", 6, pool)); SVN_ERR(svn_spillbuf__write(buf, "ghijkl", 6, pool)); /* now: two blocks: 4 and 2 bytes, and 6 bytes in spill file. */ @@ -415,19 +489,108 @@ test_spillbuf_eof(apr_pool_t *pool) return SVN_NO_ERROR; } +static svn_error_t * +test_spillbuf_eof(apr_pool_t *pool) +{ + svn_spillbuf_t *buf = svn_spillbuf__create(4 /* blocksize */, + 10 /* maxsize */, + pool); + return test_spillbuf__eof(pool, buf); +} + +static svn_error_t * +test_spillbuf_eof_spill_all(apr_pool_t *pool) +{ + svn_spillbuf_t *buf = svn_spillbuf__create_extended( + 4 /* blocksize */, + 10 /* maxsize */, + TRUE /* delte on close */, + TRUE /* spill all data */, + NULL, pool); + return test_spillbuf__eof(pool, buf); +} + +static svn_error_t * +test_spillbuf__file_attrs(apr_pool_t *pool, svn_boolean_t spill_all, + svn_spillbuf_t *buf) +{ + apr_finfo_t finfo; + + SVN_ERR(svn_spillbuf__write(buf, "abcdef", 6, pool)); + SVN_ERR(svn_spillbuf__write(buf, "ghijkl", 6, pool)); + SVN_ERR(svn_spillbuf__write(buf, "mnopqr", 6, pool)); + + /* Check that the spillbuf size is what we expect it to be */ + SVN_TEST_ASSERT(svn_spillbuf__get_size(buf) == 18); + + /* Check file existence */ + SVN_TEST_ASSERT(svn_spillbuf__get_filename(buf) != NULL); + SVN_TEST_ASSERT(svn_spillbuf__get_file(buf) != NULL); + + /* The size of the file must match expectations */ + SVN_ERR(svn_io_file_info_get(&finfo, APR_FINFO_SIZE, + svn_spillbuf__get_file(buf), pool)); + if (spill_all) + SVN_TEST_ASSERT(finfo.size == svn_spillbuf__get_size(buf)); + else + SVN_TEST_ASSERT(finfo.size == (svn_spillbuf__get_size(buf) + - svn_spillbuf__get_memory_size(buf))); + return SVN_NO_ERROR; +} + +static svn_error_t * +test_spillbuf_file_attrs(apr_pool_t *pool) +{ + svn_spillbuf_t *buf = svn_spillbuf__create(4 /* blocksize */, + 10 /* maxsize */, + pool); + return test_spillbuf__file_attrs(pool, FALSE, buf); +} + +static svn_error_t * +test_spillbuf_file_attrs_spill_all(apr_pool_t *pool) +{ + svn_spillbuf_t *buf = svn_spillbuf__create_extended( + 4 /* blocksize */, + 10 /* maxsize */, + TRUE /* delte on close */, + TRUE /* spill all data */, + NULL, pool); + return test_spillbuf__file_attrs(pool, TRUE, buf); +} /* The test table. */ -struct svn_test_descriptor_t test_funcs[] = + +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_spillbuf_basic, "basic spill buffer test"), + SVN_TEST_PASS2(test_spillbuf_basic_spill_all, + "basic spill buffer test (spill-all-data)"), SVN_TEST_PASS2(test_spillbuf_callback, "spill buffer read callback"), + SVN_TEST_PASS2(test_spillbuf_callback_spill_all, + "spill buffer read callback (spill-all-data)"), SVN_TEST_PASS2(test_spillbuf_file, "spill buffer file test"), + SVN_TEST_PASS2(test_spillbuf_file_spill_all, + "spill buffer file test (spill-all-data)"), SVN_TEST_PASS2(test_spillbuf_interleaving, "interleaving reads and writes"), + SVN_TEST_PASS2(test_spillbuf_interleaving_spill_all, + "interleaving reads and writes (spill-all-data)"), SVN_TEST_PASS2(test_spillbuf_reader, "spill buffer reader test"), SVN_TEST_PASS2(test_spillbuf_stream, "spill buffer stream test"), SVN_TEST_PASS2(test_spillbuf_rwfile, "read/write spill file"), + SVN_TEST_PASS2(test_spillbuf_rwfile_spill_all, + "read/write spill file (spill-all-data)"), SVN_TEST_PASS2(test_spillbuf_eof, "validate reaching EOF of spill file"), + SVN_TEST_PASS2(test_spillbuf_eof_spill_all, + "validate reaching EOF (spill-all-data)"), + SVN_TEST_PASS2(test_spillbuf_file_attrs, "check spill file properties"), + SVN_TEST_PASS2(test_spillbuf_file_attrs_spill_all, + "check spill file properties (spill-all-data)"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/sqlite-test.c b/subversion/tests/libsvn_subr/sqlite-test.c new file mode 100644 index 0000000..f44aa8d --- /dev/null +++ b/subversion/tests/libsvn_subr/sqlite-test.c @@ -0,0 +1,186 @@ +/* + * sqlite-test.c -- test the stream functions + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + +#include "private/svn_sqlite.h" +#include "../svn_test.h" + +static svn_error_t * +open_db(svn_sqlite__db_t **sdb, + const char **db_abspath_p, + const char *db_name, + const char *const *statements, + apr_int32_t timeout, + apr_pool_t *pool) +{ + const char *db_dir, *db_abspath; + + SVN_ERR(svn_dirent_get_absolute(&db_dir, "sqlite-test-tmp", pool)); + SVN_ERR(svn_io_remove_dir2(db_dir, TRUE, NULL, NULL, pool)); + SVN_ERR(svn_io_make_dir_recursively(db_dir, pool)); + svn_test_add_dir_cleanup(db_dir); + + db_abspath = svn_dirent_join(db_dir, db_name, pool); + + SVN_ERR(svn_sqlite__open(sdb, db_abspath, svn_sqlite__mode_rwcreate, + statements, 0, NULL, timeout, pool, pool)); + + if (db_abspath_p) + *db_abspath_p = db_abspath; + return SVN_NO_ERROR; +} + +static svn_error_t * +error_second(svn_sqlite__context_t *sctx, + int argc, + svn_sqlite__value_t *values[], + void *baton) +{ + static int i = 0; + + if (++i == 2) + svn_sqlite__result_error(sctx, "fake error", 0); + else + svn_sqlite__result_int64(sctx, 1); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_sqlite_reset(apr_pool_t *pool) +{ + svn_sqlite__db_t *sdb; + svn_sqlite__stmt_t *stmt; + svn_boolean_t have_row; + const char *value; + + static const char *const statements[] = { + "CREATE TABLE reset (" + " one TEXT NOT NULL PRIMARY KEY," + " two TEXT" + ");" + "INSERT INTO reset(one, two) VALUES ('foo', 'bar');" + "INSERT INTO reset(one, two) VALUES ('zig', 'zag')", + + "SELECT one FROM reset WHERE two IS NOT NULL AND error_second(one) " + "ORDER BY one", + + NULL + }; + + SVN_ERR(open_db(&sdb, NULL, "reset", statements, 0, pool)); + SVN_ERR(svn_sqlite__create_scalar_function(sdb, "error_second", + 1, FALSE /* deterministic */, + error_second, NULL)); + SVN_ERR(svn_sqlite__exec_statements(sdb, 0)); + SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 1)); + + /* First step is OK. */ + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + SVN_TEST_ASSERT(have_row); + value = svn_sqlite__column_text(stmt, 0, NULL); + SVN_TEST_ASSERT(value && !strcmp(value, "foo")); + + /* Second step fails. */ + SVN_TEST_ASSERT_ERROR(svn_sqlite__step(&have_row, stmt), + SVN_ERR_SQLITE_ERROR); + + /* The svn_sqlite__step wrapper calls svn_sqlite__reset when step + fails so the reset call here is a no-op. The first step can be + repeated. */ + SVN_ERR(svn_sqlite__reset(stmt)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + SVN_TEST_ASSERT(have_row); + value = svn_sqlite__column_text(stmt, 0, NULL); + SVN_TEST_ASSERT(value && !strcmp(value, "foo")); + SVN_ERR(svn_sqlite__reset(stmt)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_sqlite_txn_commit_busy(apr_pool_t *pool) +{ + svn_sqlite__db_t *sdb1; + svn_sqlite__db_t *sdb2; + const char *db_abspath; + svn_error_t *err; + + static const char *const statements[] = { + "CREATE TABLE test (one TEXT NOT NULL PRIMARY KEY)", + + "INSERT INTO test(one) VALUES ('foo')", + + "SELECT one from test", + + NULL + }; + + /* Open two db connections. + + Use a small busy_timeout of 250ms, since we're about to receive an + SVN_ERR_SQLITE_BUSY error, and retrying for the default 10 seconds + would be a waste of time. */ + SVN_ERR(open_db(&sdb1, &db_abspath, "txn_commit_busy", + statements, 250, pool)); + SVN_ERR(svn_sqlite__open(&sdb2, db_abspath, svn_sqlite__mode_readwrite, + statements, 0, NULL, 250, pool, pool)); + SVN_ERR(svn_sqlite__exec_statements(sdb1, 0)); + + /* Begin two deferred transactions. */ + SVN_ERR(svn_sqlite__begin_transaction(sdb1)); + SVN_ERR(svn_sqlite__exec_statements(sdb1, 1 /* INSERT */)); + SVN_ERR(svn_sqlite__begin_transaction(sdb2)); + SVN_ERR(svn_sqlite__exec_statements(sdb2, 2 /* SELECT */)); + + /* Try to COMMIT the first write transaction; this should fail due to + the concurrent read transaction that holds a shared lock on the db. */ + err = svn_sqlite__finish_transaction(sdb1, SVN_NO_ERROR); + SVN_TEST_ASSERT_ERROR(err, SVN_ERR_SQLITE_BUSY); + + /* We failed to COMMIT the first transaction, but COMMIT-ting the + second transaction through a different db connection should succeed. + Upgrade it to a write transaction by executing the INSERT statement, + and then commit. */ + SVN_ERR(svn_sqlite__exec_statements(sdb2, 1 /* INSERT */)); + SVN_ERR(svn_sqlite__finish_transaction(sdb2, SVN_NO_ERROR)); + + SVN_ERR(svn_sqlite__close(sdb2)); + SVN_ERR(svn_sqlite__close(sdb1)); + + return SVN_NO_ERROR; +} + + +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = + { + SVN_TEST_NULL, + SVN_TEST_PASS2(test_sqlite_reset, + "sqlite reset"), + SVN_TEST_PASS2(test_sqlite_txn_commit_busy, + "sqlite busy on transaction commit"), + SVN_TEST_NULL + }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/stream-test.c b/subversion/tests/libsvn_subr/stream-test.c index c8dba13..aaa9bf1 100644 --- a/subversion/tests/libsvn_subr/stream-test.c +++ b/subversion/tests/libsvn_subr/stream-test.c @@ -73,7 +73,7 @@ test_stream_from_string(apr_pool_t *pool) while (len == TEST_BUF_SIZE) { /* Read a chunk ... */ - SVN_ERR(svn_stream_read(stream, buffer, &len)); + SVN_ERR(svn_stream_read_full(stream, buffer, &len)); /* ... and append the chunk to the stringbuf. */ svn_stringbuf_appendbytes(outbuf, buffer, len); @@ -206,7 +206,7 @@ test_stream_compressed(apr_pool_t *pool) while (len >= TEST_BUF_SIZE) { len = TEST_BUF_SIZE; - SVN_ERR(svn_stream_read(stream, buf, &len)); + SVN_ERR(svn_stream_read_full(stream, buf, &len)); if (len > 0) svn_stringbuf_appendbytes(inbuf, buf, len); } @@ -332,17 +332,17 @@ test_stream_seek_stringbuf(apr_pool_t *pool) stringbuf = svn_stringbuf_create("OneTwo", pool); stream = svn_stream_from_stringbuf(stringbuf, pool); len = 3; - SVN_ERR(svn_stream_read(stream, buf, &len)); + SVN_ERR(svn_stream_read_full(stream, buf, &len)); buf[3] = '\0'; SVN_TEST_STRING_ASSERT(buf, "One"); SVN_ERR(svn_stream_mark(stream, &mark, pool)); len = 3; - SVN_ERR(svn_stream_read(stream, buf, &len)); + SVN_ERR(svn_stream_read_full(stream, buf, &len)); buf[3] = '\0'; SVN_TEST_STRING_ASSERT(buf, "Two"); SVN_ERR(svn_stream_seek(stream, mark)); len = 3; - SVN_ERR(svn_stream_read(stream, buf, &len)); + SVN_ERR(svn_stream_read_full(stream, buf, &len)); buf[3] = '\0'; SVN_TEST_STRING_ASSERT(buf, "Two"); @@ -351,7 +351,7 @@ test_stream_seek_stringbuf(apr_pool_t *pool) SVN_ERR(svn_stream_skip(stream, 2)); /* The remaining line should be empty */ len = 3; - SVN_ERR(svn_stream_read(stream, buf, &len)); + SVN_ERR(svn_stream_read_full(stream, buf, &len)); buf[len] = '\0'; SVN_TEST_ASSERT(len == 1); SVN_TEST_STRING_ASSERT(buf, "o"); @@ -381,7 +381,7 @@ test_stream_seek_translated(apr_pool_t *pool) FALSE, keywords, TRUE, pool); /* Seek from outside of keyword to inside of keyword. */ len = 25; - SVN_ERR(svn_stream_read(translated_stream, buf, &len)); + SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 25); buf[25] = '\0'; SVN_TEST_STRING_ASSERT(buf, "One$MyKeyword: my keyword"); @@ -389,7 +389,7 @@ test_stream_seek_translated(apr_pool_t *pool) SVN_ERR(svn_stream_reset(translated_stream)); SVN_ERR(svn_stream_seek(translated_stream, mark)); len = 4; - SVN_ERR(svn_stream_read(translated_stream, buf, &len)); + SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 4); buf[4] = '\0'; SVN_TEST_STRING_ASSERT(buf, " was"); @@ -397,7 +397,7 @@ test_stream_seek_translated(apr_pool_t *pool) SVN_ERR(svn_stream_seek(translated_stream, mark)); SVN_ERR(svn_stream_skip(translated_stream, 2)); len = 2; - SVN_ERR(svn_stream_read(translated_stream, buf, &len)); + SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 2); buf[len] = '\0'; SVN_TEST_STRING_ASSERT(buf, "as"); @@ -405,13 +405,13 @@ test_stream_seek_translated(apr_pool_t *pool) /* Seek from inside of keyword to inside of keyword. */ SVN_ERR(svn_stream_mark(translated_stream, &mark, pool)); len = 9; - SVN_ERR(svn_stream_read(translated_stream, buf, &len)); + SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 9); buf[9] = '\0'; SVN_TEST_STRING_ASSERT(buf, " expanded"); SVN_ERR(svn_stream_seek(translated_stream, mark)); len = 9; - SVN_ERR(svn_stream_read(translated_stream, buf, &len)); + SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 9); buf[9] = '\0'; SVN_TEST_STRING_ASSERT(buf, " expanded"); @@ -419,7 +419,7 @@ test_stream_seek_translated(apr_pool_t *pool) SVN_ERR(svn_stream_seek(translated_stream, mark)); SVN_ERR(svn_stream_skip(translated_stream, 6)); len = 3; - SVN_ERR(svn_stream_read(translated_stream, buf, &len)); + SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 3); buf[len] = '\0'; SVN_TEST_STRING_ASSERT(buf, "ded"); @@ -427,13 +427,13 @@ test_stream_seek_translated(apr_pool_t *pool) /* Seek from inside of keyword to outside of keyword. */ SVN_ERR(svn_stream_mark(translated_stream, &mark, pool)); len = 4; - SVN_ERR(svn_stream_read(translated_stream, buf, &len)); + SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 4); buf[4] = '\0'; SVN_TEST_STRING_ASSERT(buf, " $Tw"); SVN_ERR(svn_stream_seek(translated_stream, mark)); len = 4; - SVN_ERR(svn_stream_read(translated_stream, buf, &len)); + SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 4); buf[4] = '\0'; SVN_TEST_STRING_ASSERT(buf, " $Tw"); @@ -441,7 +441,7 @@ test_stream_seek_translated(apr_pool_t *pool) SVN_ERR(svn_stream_seek(translated_stream, mark)); SVN_ERR(svn_stream_skip(translated_stream, 2)); len = 2; - SVN_ERR(svn_stream_read(translated_stream, buf, &len)); + SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 2); buf[len] = '\0'; SVN_TEST_STRING_ASSERT(buf, "Tw"); @@ -449,13 +449,13 @@ test_stream_seek_translated(apr_pool_t *pool) /* Seek from outside of keyword to outside of keyword. */ SVN_ERR(svn_stream_mark(translated_stream, &mark, pool)); len = 1; - SVN_ERR(svn_stream_read(translated_stream, buf, &len)); + SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 1); buf[1] = '\0'; SVN_TEST_STRING_ASSERT(buf, "o"); SVN_ERR(svn_stream_seek(translated_stream, mark)); len = 1; - SVN_ERR(svn_stream_read(translated_stream, buf, &len)); + SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 1); buf[1] = '\0'; SVN_TEST_STRING_ASSERT(buf, "o"); @@ -463,7 +463,7 @@ test_stream_seek_translated(apr_pool_t *pool) SVN_ERR(svn_stream_seek(translated_stream, mark)); SVN_ERR(svn_stream_skip(translated_stream, 2)); len = 1; - SVN_ERR(svn_stream_read(translated_stream, buf, &len)); + SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 0); buf[len] = '\0'; SVN_TEST_STRING_ASSERT(buf, ""); @@ -524,7 +524,7 @@ test_stream_compressed_empty_file(apr_pool_t *pool) pool, pool)); stream = svn_stream_compressed(empty_file_stream, pool); len = sizeof(buf); - SVN_ERR(svn_stream_read(stream, buf, &len)); + SVN_ERR(svn_stream_read_full(stream, buf, &len)); if (len > 0) return svn_error_create(SVN_ERR_TEST_FAILED, NULL, "Got unexpected result."); @@ -727,9 +727,87 @@ test_stream_base64_2(apr_pool_t *pool) return SVN_NO_ERROR; } +static svn_error_t * +test_stringbuf_from_stream(apr_pool_t *pool) +{ + const char *test_cases[] = + { + "", + "x", + "this string is longer than the default 64 minimum block size used" + "by the function under test", + NULL + }; + + const char **test_case; + for (test_case = test_cases; *test_case; ++test_case) + { + svn_stringbuf_t *result1, *result2, *result3, *result4; + svn_stringbuf_t *original = svn_stringbuf_create(*test_case, pool); + + svn_stream_t *stream1 = svn_stream_from_stringbuf(original, pool); + svn_stream_t *stream2 = svn_stream_from_stringbuf(original, pool); + + SVN_ERR(svn_stringbuf_from_stream(&result1, stream1, 0, pool)); + SVN_ERR(svn_stringbuf_from_stream(&result2, stream1, 0, pool)); + SVN_ERR(svn_stringbuf_from_stream(&result3, stream2, original->len, + pool)); + SVN_ERR(svn_stringbuf_from_stream(&result4, stream2, original->len, + pool)); + + /* C-string contents must match */ + SVN_TEST_STRING_ASSERT(result1->data, original->data); + SVN_TEST_STRING_ASSERT(result2->data, ""); + SVN_TEST_STRING_ASSERT(result3->data, original->data); + SVN_TEST_STRING_ASSERT(result4->data, ""); + + /* assumed length must match */ + SVN_TEST_ASSERT(result1->len == original->len); + SVN_TEST_ASSERT(result2->len == 0); + SVN_TEST_ASSERT(result3->len == original->len); + SVN_TEST_ASSERT(result4->len == 0); + } + + return SVN_NO_ERROR; +} + +static svn_error_t * +empty_read_full_fn(void *baton, char *buffer, apr_size_t *len) +{ + *len = 0; + return SVN_NO_ERROR; +} + +static svn_error_t * +test_stream_compressed_read_full(apr_pool_t *pool) +{ + svn_stream_t *stream, *empty_stream; + char buf[1]; + apr_size_t len; + + /* Reading an empty stream with read_full only support should not error. */ + empty_stream = svn_stream_create(NULL, pool); + + /* Create stream with only full read support. */ + svn_stream_set_read2(empty_stream, NULL, empty_read_full_fn); + + stream = svn_stream_compressed(empty_stream, pool); + len = sizeof(buf); + SVN_ERR(svn_stream_read_full(stream, buf, &len)); + if (len > 0) + return svn_error_create(SVN_ERR_TEST_FAILED, NULL, + "Got unexpected result."); + + SVN_ERR(svn_stream_close(stream)); + + return SVN_NO_ERROR; +} + /* The test table. */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_stream_from_string, @@ -752,5 +830,11 @@ struct svn_test_descriptor_t test_funcs[] = "test base64 encoding/decoding streams"), SVN_TEST_PASS2(test_stream_base64_2, "base64 decoding allocation problem"), + SVN_TEST_PASS2(test_stringbuf_from_stream, + "test svn_stringbuf_from_stream"), + SVN_TEST_PASS2(test_stream_compressed_read_full, + "test compression for streams without partial read"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/string-test.c b/subversion/tests/libsvn_subr/string-test.c index 735db18..ab0cc44 100644 --- a/subversion/tests/libsvn_subr/string-test.c +++ b/subversion/tests/libsvn_subr/string-test.c @@ -38,6 +38,7 @@ #include "svn_io.h" #include "svn_error.h" +#include "svn_sorts.h" /* MIN / MAX */ #include "svn_string.h" /* This includes <apr_*.h> */ #include "private/svn_string_private.h" @@ -58,9 +59,8 @@ fail(apr_pool_t *pool, const char *fmt, ...) /* 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 const char *phrase_1 = "hello, "; +static const char *phrase_2 = "a longish phrase of sorts, longer than 16 anyway"; @@ -68,7 +68,7 @@ const char *phrase_2 = "a longish phrase of sorts, longer than 16 anyway"; static svn_error_t * test1(apr_pool_t *pool) { - a = svn_stringbuf_create(phrase_1, pool); + svn_stringbuf_t *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)) @@ -81,7 +81,7 @@ test1(apr_pool_t *pool) static svn_error_t * test2(apr_pool_t *pool) { - b = svn_stringbuf_ncreate(phrase_2, 16, pool); + svn_stringbuf_t *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)) @@ -97,8 +97,8 @@ test3(apr_pool_t *pool) char *tmp; size_t old_len; - a = svn_stringbuf_create(phrase_1, pool); - b = svn_stringbuf_ncreate(phrase_2, 16, pool); + svn_stringbuf_t *a = svn_stringbuf_create(phrase_1, pool); + svn_stringbuf_t *b = svn_stringbuf_ncreate(phrase_2, 16, pool); tmp = apr_palloc(pool, (a->len + b->len + 1)); strcpy(tmp, a->data); @@ -117,7 +117,7 @@ test3(apr_pool_t *pool) static svn_error_t * test4(apr_pool_t *pool) { - a = svn_stringbuf_create(phrase_1, pool); + svn_stringbuf_t *a = svn_stringbuf_create(phrase_1, pool); svn_stringbuf_appendcstr(a, "new bytes to append"); /* Test that length, data, and null-termination are correct. */ @@ -132,7 +132,7 @@ test4(apr_pool_t *pool) static svn_error_t * test5(apr_pool_t *pool) { - a = svn_stringbuf_create(phrase_1, pool); + svn_stringbuf_t *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. */ @@ -147,9 +147,9 @@ test5(apr_pool_t *pool) static svn_error_t * test6(apr_pool_t *pool) { - a = svn_stringbuf_create(phrase_1, pool); - b = svn_stringbuf_create(phrase_2, pool); - c = svn_stringbuf_dup(a, pool); + svn_stringbuf_t *a = svn_stringbuf_create(phrase_1, pool); + svn_stringbuf_t *b = svn_stringbuf_create(phrase_2, pool); + svn_stringbuf_t *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))) @@ -165,7 +165,7 @@ test7(apr_pool_t *pool) char *tmp; size_t tmp_len; - c = svn_stringbuf_create(phrase_2, pool); + svn_stringbuf_t *c = svn_stringbuf_create(phrase_2, pool); tmp_len = c->len; tmp = apr_palloc(pool, c->len + 1); @@ -185,7 +185,7 @@ test7(apr_pool_t *pool) static svn_error_t * test8(apr_pool_t *pool) { - c = svn_stringbuf_create(phrase_2, pool); + svn_stringbuf_t *c = svn_stringbuf_create(phrase_2, pool); svn_stringbuf_setempty(c); @@ -199,7 +199,7 @@ test8(apr_pool_t *pool) static svn_error_t * test9(apr_pool_t *pool) { - a = svn_stringbuf_create(phrase_1, pool); + svn_stringbuf_t *a = svn_stringbuf_create(phrase_1, pool); svn_stringbuf_fillchar(a, '#'); @@ -379,7 +379,7 @@ test_find_char_backward(const char* data, { apr_size_t i; - a = svn_stringbuf_create(data, pool); + svn_stringbuf_t *a = svn_stringbuf_create(data, pool); i = svn_stringbuf_find_char_backward(a, ch); if (i == pos) @@ -391,7 +391,7 @@ test_find_char_backward(const char* data, static svn_error_t * test13(apr_pool_t *pool) { - a = svn_stringbuf_create("test, test", pool); + svn_stringbuf_t *a = svn_stringbuf_create("test, test", pool); return test_find_char_backward(a->data, a->len, ',', 4, pool); } @@ -399,7 +399,7 @@ test13(apr_pool_t *pool) static svn_error_t * test14(apr_pool_t *pool) { - a = svn_stringbuf_create(",test test", pool); + svn_stringbuf_t *a = svn_stringbuf_create(",test test", pool); return test_find_char_backward(a->data, a->len, ',', 0, pool); } @@ -407,7 +407,7 @@ test14(apr_pool_t *pool) static svn_error_t * test15(apr_pool_t *pool) { - a = svn_stringbuf_create("testing,", pool); + svn_stringbuf_t *a = svn_stringbuf_create("testing,", pool); return test_find_char_backward(a->data, a->len, @@ -419,7 +419,7 @@ test15(apr_pool_t *pool) static svn_error_t * test16(apr_pool_t *pool) { - a = svn_stringbuf_create_empty(pool); + svn_stringbuf_t *a = svn_stringbuf_create_empty(pool); return test_find_char_backward(a->data, a->len, ',', 0, pool); } @@ -427,7 +427,7 @@ test16(apr_pool_t *pool) static svn_error_t * test17(apr_pool_t *pool) { - a = svn_stringbuf_create("test test test", pool); + svn_stringbuf_t *a = svn_stringbuf_create("test test test", pool); return test_find_char_backward(a->data, a->len, @@ -443,7 +443,7 @@ test_first_non_whitespace(const char *str, { apr_size_t i; - a = svn_stringbuf_create(str, pool); + svn_stringbuf_t *a = svn_stringbuf_create(str, pool); i = svn_stringbuf_first_non_whitespace(a); @@ -474,8 +474,8 @@ test20(apr_pool_t *pool) static svn_error_t * test21(apr_pool_t *pool) { - a = svn_stringbuf_create(" \ttest\t\t \t ", pool); - b = svn_stringbuf_create("test", pool); + svn_stringbuf_t *a = svn_stringbuf_create(" \ttest\t\t \t ", pool); + svn_stringbuf_t *b = svn_stringbuf_create("test", pool); svn_stringbuf_strip_whitespace(a); @@ -490,8 +490,8 @@ test_stringbuf_unequal(const char* str1, const char* str2, apr_pool_t *pool) { - a = svn_stringbuf_create(str1, pool); - b = svn_stringbuf_create(str2, pool); + svn_stringbuf_t *a = svn_stringbuf_create(str1, pool); + svn_stringbuf_t *b = svn_stringbuf_create(str2, pool); if (svn_stringbuf_compare(a, b)) return fail(pool, "test failed"); @@ -521,23 +521,58 @@ test24(apr_pool_t *pool) SVN_TEST_ASSERT(length == 1); SVN_TEST_STRING_ASSERT(buffer, "0"); - length = svn__i64toa(buffer, 0x8000000000000000ll); + length = svn__i64toa(buffer, APR_INT64_MIN); SVN_TEST_ASSERT(length == 20); SVN_TEST_STRING_ASSERT(buffer, "-9223372036854775808"); - length = svn__i64toa(buffer, 0x7fffffffffffffffll); + length = svn__i64toa(buffer, APR_INT64_MAX); SVN_TEST_ASSERT(length == 19); SVN_TEST_STRING_ASSERT(buffer, "9223372036854775807"); - length = svn__ui64toa(buffer, 0ull); + length = svn__ui64toa(buffer, 0u); SVN_TEST_ASSERT(length == 1); SVN_TEST_STRING_ASSERT(buffer, "0"); - length = svn__ui64toa(buffer, 0xffffffffffffffffull); + length = svn__ui64toa(buffer, APR_UINT64_MAX); SVN_TEST_ASSERT(length == 20); SVN_TEST_STRING_ASSERT(buffer, "18446744073709551615"); - return test_stringbuf_unequal("abc", "abb", pool); + return SVN_NO_ERROR; +} + +static svn_error_t * +sub_test_base36(apr_uint64_t value, const char *base36) +{ + char buffer[SVN_INT64_BUFFER_SIZE]; + apr_size_t length; + apr_size_t expected_length = strlen(base36); + const char *end = buffer; + apr_uint64_t result; + + length = svn__ui64tobase36(buffer, value); + SVN_TEST_ASSERT(length == expected_length); + SVN_TEST_STRING_ASSERT(buffer, base36); + + result = svn__base36toui64(&end, buffer); + SVN_TEST_ASSERT(end - buffer == length); + SVN_TEST_ASSERT(result == value); + + result = svn__base36toui64(NULL, buffer); + SVN_TEST_ASSERT(result == value); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_base36(apr_pool_t *pool) +{ + SVN_ERR(sub_test_base36(0, "0")); + SVN_ERR(sub_test_base36(APR_UINT64_C(1234567890), "kf12oi")); + SVN_ERR(sub_test_base36(APR_UINT64_C(0x7fffffffffffffff), "1y2p0ij32e8e7")); + SVN_ERR(sub_test_base36(APR_UINT64_C(0x8000000000000000), "1y2p0ij32e8e8")); + SVN_ERR(sub_test_base36(APR_UINT64_MAX, "3w5e11264sgsf")); + + return SVN_NO_ERROR; } static svn_error_t * @@ -554,7 +589,7 @@ expect_stringbuf_equal(const svn_stringbuf_t* str1, static svn_error_t * test_stringbuf_insert(apr_pool_t *pool) { - a = svn_stringbuf_create("st , ", pool); + svn_stringbuf_t *a = svn_stringbuf_create("st , ", pool); svn_stringbuf_insert(a, 0, "teflon", 2); SVN_TEST_STRING_ASSERT(a->data, "test , "); @@ -587,7 +622,7 @@ test_stringbuf_insert(apr_pool_t *pool) static svn_error_t * test_stringbuf_remove(apr_pool_t *pool) { - a = svn_stringbuf_create("test hello, world!", pool); + svn_stringbuf_t *a = svn_stringbuf_create("test hello, world!", pool); svn_stringbuf_remove(a, 0, 2); SVN_TEST_STRING_ASSERT(a->data, "st hello, world!"); @@ -599,13 +634,21 @@ test_stringbuf_remove(apr_pool_t *pool) SVN_TEST_STRING_ASSERT(a->data, "stell"); svn_stringbuf_remove(a, 1200, 393); - return expect_stringbuf_equal(a, "stell", pool); + SVN_ERR(expect_stringbuf_equal(a, "stell", pool)); + + svn_stringbuf_remove(a, APR_SIZE_MAX, 2); + SVN_ERR(expect_stringbuf_equal(a, "stell", pool)); + + svn_stringbuf_remove(a, 1, APR_SIZE_MAX); + SVN_ERR(expect_stringbuf_equal(a, "s", pool)); + + return SVN_NO_ERROR; } static svn_error_t * test_stringbuf_replace(apr_pool_t *pool) { - a = svn_stringbuf_create("odd with some world?", pool); + svn_stringbuf_t *a = svn_stringbuf_create("odd with some world?", pool); svn_stringbuf_replace(a, 0, 3, "tester", 4); SVN_TEST_STRING_ASSERT(a->data, "test with some world?"); @@ -637,6 +680,12 @@ test_stringbuf_replace(apr_pool_t *pool) svn_stringbuf_ncreate("test hello\0-\0world!\0-\0!", 23, pool))); + svn_stringbuf_replace(a, 1, APR_SIZE_MAX, "x", 1); + SVN_ERR(expect_stringbuf_equal(a, "tx", pool)); + + svn_stringbuf_replace(a, APR_SIZE_MAX, APR_SIZE_MAX, "y", 1); + SVN_ERR(expect_stringbuf_equal(a, "txy", pool)); + return SVN_NO_ERROR; } @@ -648,13 +697,14 @@ test_string_similarity(apr_pool_t *pool) const char *stra; const char *strb; apr_size_t lcs; - int score; + unsigned int score; } tests[] = { -#define SCORE(lcs, len) ((2000 * (lcs) + (len)/2) / (len)) +#define SCORE(lcs, len) \ + ((2 * SVN_STRING__SIM_RANGE_MAX * (lcs) + (len)/2) / (len)) /* Equality */ - {"", "", 0, 1000}, + {"", "", 0, SVN_STRING__SIM_RANGE_MAX}, {"quoth", "quoth", 5, SCORE(5, 5+5)}, /* Deletion at start */ @@ -708,17 +758,20 @@ test_string_similarity(apr_pool_t *pool) for (t = tests; t->stra; ++t) { apr_size_t lcs; - const unsigned int score = + const apr_size_t score = svn_cstring__similarity(t->stra, t->strb, &buffer, &lcs); /* fprintf(stderr, - "lcs %s ~ %s score %.3f (%"APR_SIZE_T_FMT - ") expected %.3f (%"APR_SIZE_T_FMT"))\n", - t->stra, t->strb, score/1000.0, lcs, t->score/1000.0, t->lcs); + "lcs %s ~ %s score %.6f (%"APR_SIZE_T_FMT + ") expected %.6f (%"APR_SIZE_T_FMT"))\n", + t->stra, t->strb, score/1.0/SVN_STRING__SIM_RANGE_MAX, + lcs, t->score/1.0/SVN_STRING__SIM_RANGE_MAX, t->lcs); */ if (score != t->score) - return fail(pool, "%s ~ %s score %.3f <> expected %.3f", - t->stra, t->strb, score/1000.0, t->score/1000.0); + return fail(pool, "%s ~ %s score %.6f <> expected %.6f", + t->stra, t->strb, + score/1.0/SVN_STRING__SIM_RANGE_MAX, + t->score/1.0/SVN_STRING__SIM_RANGE_MAX); if (lcs != t->lcs) return fail(pool, @@ -731,7 +784,8 @@ test_string_similarity(apr_pool_t *pool) { const svn_string_t foo = {"svn:foo", 4}; const svn_string_t bar = {"svn:bar", 4}; - if (1000 != svn_string__similarity(&foo, &bar, &buffer, NULL)) + if (SVN_STRING__SIM_RANGE_MAX + != svn_string__similarity(&foo, &bar, &buffer, NULL)) return fail(pool, "'%s'[:4] ~ '%s'[:4] found different", foo.data, bar.data); } @@ -739,6 +793,106 @@ test_string_similarity(apr_pool_t *pool) return SVN_NO_ERROR; } +static svn_error_t * +test_string_matching(apr_pool_t *pool) +{ + const struct test_data_t + { + const char *a; + const char *b; + apr_size_t match_len; + apr_size_t rmatch_len; + } + tests[] = + { + /* edge cases */ + {"", "", 0, 0}, + {"", "x", 0, 0}, + {"x", "", 0, 0}, + {"x", "x", 1, 1}, + {"", "1234567890abcdef", 0, 0}, + {"1234567890abcdef", "", 0, 0}, + {"1234567890abcdef", "1234567890abcdef", 16, 16}, + + /* left-side matches */ + {"x", "y", 0, 0}, + {"ax", "ay", 1, 0}, + {"ax", "a", 1, 0}, + {"a", "ay", 1, 0}, + {"1234567890abcdef", "1234567890abcdeg", 15, 0}, + {"1234567890abcdef_", "1234567890abcdefg", 16, 0}, + {"12345678_0abcdef", "1234567890abcdeg", 8, 0}, + {"1234567890abcdef", "12345678", 8, 0}, + {"12345678", "1234567890abcdef", 8, 0}, + {"12345678_0ab", "1234567890abcdef", 8, 0}, + + /* right-side matches */ + {"xa", "ya", 0, 1}, + {"xa", "a", 0, 1}, + {"a", "ya", 0, 1}, + {"_234567890abcdef", "1234567890abcdef", 0, 15}, + {"_1234567890abcdef", "x1234567890abcdef", 0, 16}, + {"1234567_90abcdef", "_1234567890abcdef", 0, 8}, + {"1234567890abcdef", "90abcdef", 0, 8}, + {"90abcdef", "1234567890abcdef", 0, 8}, + {"8_0abcdef", "7890abcdef", 0, 7}, + + /* two-side matches */ + {"bxa", "bya", 1, 1}, + {"bxa", "ba", 1, 1}, + {"ba", "bya", 1, 1}, + {"1234567_90abcdef", "1234567890abcdef", 7, 8}, + {"12345678_90abcdef", "1234567890abcdef", 8, 8}, + {"12345678_0abcdef", "1234567890abcdef", 8, 7}, + {"123456_abcdef", "1234sdffdssdf567890abcdef", 4, 6}, + {"1234567890abcdef", "12345678ef", 8, 2}, + {"x_234567890abcdef", "x1234567890abcdef", 1, 15}, + {"1234567890abcdefx", "1234567890abcdex", 15, 1}, + + /* list terminator */ + {NULL} + }; + + const struct test_data_t *test; + for (test = tests; test->a != NULL; ++test) + { + apr_size_t a_len = strlen(test->a); + apr_size_t b_len = strlen(test->b); + apr_size_t max_match = MIN(a_len, b_len); + apr_size_t match_len + = svn_cstring__match_length(test->a, test->b, max_match); + apr_size_t rmatch_len + = svn_cstring__reverse_match_length(test->a + a_len, test->b + b_len, + max_match); + + SVN_TEST_ASSERT(match_len == test->match_len); + SVN_TEST_ASSERT(rmatch_len == test->rmatch_len); + } + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_string_skip_prefix(apr_pool_t *pool) +{ + SVN_TEST_STRING_ASSERT(svn_cstring_skip_prefix("12345", "12345"), + ""); + SVN_TEST_STRING_ASSERT(svn_cstring_skip_prefix("12345", "123"), + "45"); + SVN_TEST_STRING_ASSERT(svn_cstring_skip_prefix("12345", ""), + "12345"); + SVN_TEST_STRING_ASSERT(svn_cstring_skip_prefix("12345", "23"), + NULL); + SVN_TEST_STRING_ASSERT(svn_cstring_skip_prefix("1", "12"), + NULL); + SVN_TEST_STRING_ASSERT(svn_cstring_skip_prefix("", ""), + ""); + SVN_TEST_STRING_ASSERT(svn_cstring_skip_prefix("", "12"), + NULL); + + return SVN_NO_ERROR; +} + /* ==================================================================== If you add a new test to this file, update this array. @@ -747,7 +901,10 @@ test_string_similarity(apr_pool_t *pool) */ /* An array of all test functions */ -struct svn_test_descriptor_t test_funcs[] = + +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test1, @@ -783,7 +940,7 @@ struct svn_test_descriptor_t test_funcs[] = SVN_TEST_PASS2(test16, "find_char_backward; len = 0 case"), SVN_TEST_PASS2(test17, - "find_char_backward; no occurence case"), + "find_char_backward; no occurrence case"), SVN_TEST_PASS2(test18, "check whitespace removal; common case"), SVN_TEST_PASS2(test19, @@ -798,6 +955,8 @@ struct svn_test_descriptor_t test_funcs[] = "compare stringbufs; same length, different content"), SVN_TEST_PASS2(test24, "verify i64toa"), + SVN_TEST_PASS2(test_base36, + "verify base36 conversion"), SVN_TEST_PASS2(test_stringbuf_insert, "check inserting into svn_stringbuf_t"), SVN_TEST_PASS2(test_stringbuf_remove, @@ -806,5 +965,11 @@ struct svn_test_descriptor_t test_funcs[] = "check replacement in svn_stringbuf_t"), SVN_TEST_PASS2(test_string_similarity, "test string similarity scores"), + SVN_TEST_PASS2(test_string_matching, + "test string matching"), + SVN_TEST_PASS2(test_string_skip_prefix, + "test svn_cstring_skip_prefix()"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/subst_translate-test.c b/subversion/tests/libsvn_subr/subst_translate-test.c index 1e555f2..0c4ee96 100644 --- a/subversion/tests/libsvn_subr/subst_translate-test.c +++ b/subversion/tests/libsvn_subr/subst_translate-test.c @@ -115,7 +115,7 @@ test_svn_subst_translate_string2_null_encoding_helper(apr_pool_t *pool) svn_string_t *new_value = NULL; svn_boolean_t translated_to_utf8 = FALSE; svn_boolean_t translated_line_endings = TRUE; - /* 'Æ', which is 0xc6 in both ISO-8859-1 and Windows-1252 */ + /* The 'AE' ligature, which is 0xc6 in both ISO-8859-1 and Windows-1252 */ svn_string_t *source_string = svn_string_create("\xc6", pool); SVN_ERR(svn_subst_translate_string2(&new_value, &translated_to_utf8, @@ -397,7 +397,7 @@ test_svn_subst_long_keywords(apr_pool_t *pool) "01234567890123456789012345678901234567890123456789" "012345678901234567890123456789012345678901234567"; - /* The longest keyword that can be expanded: the value is empty. */ + /* The longest keyword that can be expanded: the value is empty. */ const char keyword_z[] = "Q" "01234567890123456789012345678901234567890123456789" @@ -500,7 +500,9 @@ test_svn_subst_long_keywords(apr_pool_t *pool) return SVN_NO_ERROR; } -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_svn_subst_translate_string2, @@ -519,3 +521,6 @@ struct svn_test_descriptor_t test_funcs[] = "test long keywords (issue 4350)"), SVN_TEST_NULL }; + +SVN_TEST_MAIN + diff --git a/subversion/tests/libsvn_subr/time-test.c b/subversion/tests/libsvn_subr/time-test.c index 82e56b1..51fbe67 100644 --- a/subversion/tests/libsvn_subr/time-test.c +++ b/subversion/tests/libsvn_subr/time-test.c @@ -29,10 +29,10 @@ #include "../svn_test.h" /* All these variables should refer to the same point in time. */ -apr_time_t test_timestamp = APR_TIME_C(1021316450966679); -const char *test_timestring = +static apr_time_t test_timestamp = APR_TIME_C(1021316450966679); +static const char *test_timestring = "2002-05-13T19:00:50.966679Z"; -const char *test_old_timestring = +static const char *test_old_timestring = "Mon 13 May 2002 22:00:50.966679 (day 133, dst 1, gmt_off 010800)"; @@ -339,7 +339,9 @@ test_parse_date(apr_pool_t *pool) /* The test table. */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(test_time_to_cstring, @@ -354,3 +356,5 @@ struct svn_test_descriptor_t test_funcs[] = "test svn_parse_date"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/translate-test.c b/subversion/tests/libsvn_subr/translate-test.c index 9300503..2436bc7 100644 --- a/subversion/tests/libsvn_subr/translate-test.c +++ b/subversion/tests/libsvn_subr/translate-test.c @@ -48,7 +48,7 @@ /*** Helpers ***/ /* (Almost) all the tests share the same test data. */ -const char *lines[] = +static const char *lines[] = { "Line 1: fairly boring subst test data... blah blah", "Line 2: fairly boring subst test data... blah blah.", @@ -223,15 +223,12 @@ random_eol_marker(void) static svn_error_t * create_file(const char *fname, const char *eol_str, apr_pool_t *pool) { - apr_status_t apr_err; apr_file_t *f; apr_size_t i, j; - apr_err = apr_file_open(&f, fname, + SVN_ERR(svn_io_file_open(&f, fname, (APR_WRITE | APR_CREATE | APR_EXCL | APR_BINARY), - APR_OS_DEFAULT, pool); - if (apr_err) - return svn_error_create(apr_err, NULL, fname); + APR_OS_DEFAULT, pool)); for (i = 0; i < (sizeof(lines) / sizeof(*lines)); i++) { @@ -243,45 +240,13 @@ create_file(const char *fname, const char *eol_str, apr_pool_t *pool) fprintf() doing a newline conversion? */ for (j = 0; this_eol_str[j]; j++) { - apr_err = apr_file_putc(this_eol_str[j], f); - if (apr_err) - return svn_error_create(apr_err, NULL, fname); + SVN_ERR(svn_io_file_putc(this_eol_str[j], f, pool)); } } - apr_err = apr_file_close(f); - if (apr_err) - return svn_error_create(apr_err, NULL, fname); - - return SVN_NO_ERROR; -} - - -/* If FNAME is a regular file, remove it; if it doesn't exist at all, - return success. Otherwise, return error. */ -static svn_error_t * -remove_file(const char *fname, apr_pool_t *pool) -{ - apr_status_t apr_err; - apr_finfo_t finfo; - - if (apr_stat(&finfo, fname, APR_FINFO_TYPE, pool) == APR_SUCCESS) - { - if (finfo.filetype == APR_REG) - { - apr_err = apr_file_remove(fname, pool); - if (apr_err) - return svn_error_create(apr_err, NULL, fname); - } - else - return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, - "non-file '%s' is in the way", fname); - } - - return SVN_NO_ERROR; + return svn_error_trace(svn_io_file_close(f, pool)); } - /* Set up, run, and verify the results of a substitution. * * Create a file TEST_NAME.src using global `lines' as the initial @@ -325,14 +290,14 @@ substitute_and_verify(const char *test_name, apr_size_t idx = 0; apr_size_t i; const char *expect[(sizeof(lines) / sizeof(*lines))]; - const char *src_fname = apr_pstrcat(pool, test_name, ".src", (char *)NULL); - const char *dst_fname = apr_pstrcat(pool, test_name, ".dst", (char *)NULL); + const char *src_fname = apr_pstrcat(pool, test_name, ".src", SVN_VA_NULL); + const char *dst_fname = apr_pstrcat(pool, test_name, ".dst", SVN_VA_NULL); svn_string_t *val; apr_pool_t *subpool = svn_pool_create(pool); /** Clean up from previous tests, set up src data, and convert. **/ - SVN_ERR(remove_file(src_fname, pool)); - SVN_ERR(remove_file(dst_fname, pool)); + SVN_ERR(svn_io_remove_file2(src_fname, TRUE, pool)); + SVN_ERR(svn_io_remove_file2(dst_fname, TRUE, pool)); SVN_ERR(create_file(src_fname, src_eol, pool)); if (rev) @@ -395,7 +360,7 @@ substitute_and_verify(const char *test_name, else { svn_error_clear(err); - SVN_ERR(remove_file(src_fname, pool)); + SVN_ERR(svn_io_remove_file2(src_fname, FALSE, pool)); return SVN_NO_ERROR; } @@ -419,27 +384,27 @@ substitute_and_verify(const char *test_name, "Valid $LastChangedRevision: ", rev, " $, started unexpanded.", - (char *)NULL); + SVN_VA_NULL); expect[5 - 1] = apr_pstrcat(pool, "Line 5: ", "Valid $Rev: ", rev, " $, started unexpanded.", - (char *)NULL); + SVN_VA_NULL); expect[26 - 1] = apr_pstrcat(pool, "Line 26: ", "Emptily expanded keyword $Rev: ", rev," $.", - (char *)NULL); + SVN_VA_NULL); expect[29 - 1] = apr_pstrcat(pool, "Line 29: ", "Valid $LastChangedRevision: ", rev, " $, started expanded.", - (char *)NULL); + SVN_VA_NULL); expect[30 - 1] = apr_pstrcat(pool, "Line 30: ", "Valid $Rev: ", rev, " $, started expanded.", - (char *)NULL); + SVN_VA_NULL); } else /* unexpand */ { @@ -462,31 +427,31 @@ substitute_and_verify(const char *test_name, "Valid $LastChangedDate: ", date, " $, started unexpanded.", - (char *)NULL); + SVN_VA_NULL); expect[13 - 1] = apr_pstrcat(pool, "Line 13: ", "Valid $Date: ", date, " $, started unexpanded.", - (char *)NULL); + SVN_VA_NULL); expect[33 - 1] = apr_pstrcat(pool, "Line 33: ", "Valid $LastChangedDate: ", date, " $, started expanded.", - (char *)NULL); + SVN_VA_NULL); expect[34 - 1] = apr_pstrcat(pool, "Line 34: ", "Valid $Date: ", date, " $, started expanded.", - (char *)NULL); + SVN_VA_NULL); expect[51 - 1] = apr_pstrcat(pool, "Line 51: ", "same, but with embedded keyword ", "$$$$$$$$Date: ", date, " $$$$$$$$$$.", - (char *)NULL); + SVN_VA_NULL); expect[52 - 1] = apr_pstrcat(pool, "Line 52: ", "same, with expanded, empty keyword ", "$$$$$$Date: ", date, " $$$$$$.", - (char *)NULL); + SVN_VA_NULL); } else /* unexpand */ { @@ -511,46 +476,46 @@ substitute_and_verify(const char *test_name, "Valid $LastChangedBy: ", author, " $, started unexpanded.", - (char *)NULL); + SVN_VA_NULL); expect[9 - 1] = apr_pstrcat(pool, "Line 9: ", "Valid $Author: ", author, " $, started unexpanded.", - (char *)NULL); + SVN_VA_NULL); expect[37 - 1] = apr_pstrcat(pool, "Line 37: ", "Valid $LastChangedBy: ", author, - " $, started expanded.", (char *)NULL); + " $, started expanded.", SVN_VA_NULL); expect[38 - 1] = apr_pstrcat(pool, "Line 38: ", "Valid $Author: ", author, " $, started expanded.", - (char *)NULL); + SVN_VA_NULL); expect[46 - 1] = apr_pstrcat(pool, "Line 46: ", "Empty $Author: ", author, " $, started expanded.", - (char *)NULL); + SVN_VA_NULL); expect[71 - 1] = - apr_pstrcat(pool, ".$veR$Author: ", author, " $", (char *)NULL); + apr_pstrcat(pool, ".$veR$Author: ", author, " $", SVN_VA_NULL); expect[74 - 1] = apr_pstrcat(pool, "Line 74: ", "Valid $Author: ", author, " $, started expanded.", - (char *)NULL); + SVN_VA_NULL); expect[79 - 1] = apr_pstrcat(pool, "Line 79: ", "Valid $Author: ", author, " $, started expanded.", - (char *)NULL); + SVN_VA_NULL); expect[80 - 1] = apr_pstrcat(pool, "Line 80: ", "Valid $Author: ", author, " $, started expanded.", - (char *)NULL); + SVN_VA_NULL); expect[81 - 1] = apr_pstrcat(pool, "Line 81: ", "Valid $Author: ", author, " $, started expanded.", - (char *)NULL); + SVN_VA_NULL); expect[82 - 1] = apr_pstrcat(pool, "Line 82: ", "Valid $Author: ", author, " $, started expanded.", - (char *)NULL); + SVN_VA_NULL); } else /* unexpand */ { @@ -581,23 +546,23 @@ substitute_and_verify(const char *test_name, expect[16 - 1] = apr_pstrcat(pool, "Line 16: ", "Valid $HeadURL: ", url, " $, started unexpanded.", - (char *)NULL); + SVN_VA_NULL); expect[17 - 1] = apr_pstrcat(pool, "Line 17: ", "Valid $URL: ", url, " $, started unexpanded.", - (char *)NULL); + SVN_VA_NULL); expect[41 - 1] = apr_pstrcat(pool, "Line 41: ", "Valid $HeadURL: ", url, " $, started expanded.", - (char *)NULL); + SVN_VA_NULL); expect[42 - 1] = apr_pstrcat(pool, "Line 42: ", "Valid $URL: ", url, " $, started expanded.", - (char *)NULL); + SVN_VA_NULL); expect[75 - 1] = apr_pstrcat(pool, "Line 75: ", "Valid $URL: ", url, " $, started expanded.", - (char *)NULL); + SVN_VA_NULL); } else /* unexpand */ { @@ -622,14 +587,14 @@ substitute_and_verify(const char *test_name, "Two keywords back to back: " "$Author: ", author, " $" "$Rev: ", rev, " $.", - (char *)NULL); + SVN_VA_NULL); expect[49 - 1] = apr_pstrcat(pool, "Line 49: ", "One keyword, one not, back to back: " "$Author: ", author, " $Rev$.", - (char *)NULL); + SVN_VA_NULL); expect[70 - 1] = - apr_pstrcat(pool, "$Author: ", author, " $Rev$.", (char *)NULL); + apr_pstrcat(pool, "$Author: ", author, " $Rev$.", SVN_VA_NULL); } /* Else Lines 48, 49, and 70 remain unchanged. */ } @@ -641,14 +606,14 @@ substitute_and_verify(const char *test_name, apr_pstrcat(pool, "Line 48: ", "Two keywords back to back: " "$Author$$Rev: ", rev, " $.", - (char *)NULL); + SVN_VA_NULL); expect[49 - 1] = apr_pstrcat(pool, "Line 49: ", "One keyword, one not, back to back: " "$Author$Rev: ", rev, " $.", - (char *)NULL); + SVN_VA_NULL); expect[70 - 1] = - apr_pstrcat(pool, "$Author$Rev: ", rev, " $.", (char *)NULL); + apr_pstrcat(pool, "$Author$Rev: ", rev, " $.", SVN_VA_NULL); } /* Else Lines 48, 49, and 70 remain unchanged. */ } @@ -660,14 +625,14 @@ substitute_and_verify(const char *test_name, apr_pstrcat(pool, "Line 48: ", "Two keywords back to back: " "$Author: ", author, " $$Rev$.", - (char *)NULL); + SVN_VA_NULL); expect[49 - 1] = apr_pstrcat(pool, "Line 49: ", "One keyword, one not, back to back: " "$Author: ", author, " $Rev$.", - (char *)NULL); + SVN_VA_NULL); expect[70 - 1] = - apr_pstrcat(pool, "$Author: ", author, " $Rev$.", (char *)NULL); + apr_pstrcat(pool, "$Author: ", author, " $Rev$.", SVN_VA_NULL); } /* Else Lines 48, 49, and 70 remain unchanged. */ } @@ -684,14 +649,14 @@ substitute_and_verify(const char *test_name, "keyword in a keyword: $Author: ", author, " $Date$ $", - (char *)NULL); + SVN_VA_NULL); } else /* unexpand */ { expect[24 - 1] = apr_pstrcat(pool, "Line 24: ", "keyword in a keyword: $Author$Date$ $", - (char *)NULL); + SVN_VA_NULL); } } else if (date && (! author)) @@ -703,7 +668,7 @@ substitute_and_verify(const char *test_name, "keyword in a keyword: $Author: $Date: ", date, " $ $", - (char *)NULL); + SVN_VA_NULL); } /* Else Line 24 remains unchanged. */ } @@ -716,14 +681,14 @@ substitute_and_verify(const char *test_name, "keyword in a keyword: $Author: ", author, " $Date$ $", - (char *)NULL); + SVN_VA_NULL); } else /* unexpand */ { expect[24 - 1] = apr_pstrcat(pool, "Line 24: ", "keyword in a keyword: $Author$Date$ $", - (char *)NULL); + SVN_VA_NULL); } } /* Else neither author nor date, so Line 24 remains unchanged. */ @@ -769,8 +734,8 @@ substitute_and_verify(const char *test_name, } /* Clean up this test, since successful. */ - SVN_ERR(remove_file(src_fname, pool)); - SVN_ERR(remove_file(dst_fname, pool)); + SVN_ERR(svn_io_remove_file2(src_fname, FALSE, pool)); + SVN_ERR(svn_io_remove_file2(dst_fname, FALSE, pool)); return SVN_NO_ERROR; } @@ -862,7 +827,7 @@ static svn_error_t * mixed_to_lf(apr_pool_t *pool) { return substitute_and_verify - ("cr_to_lf", NULL, "\n", 1, NULL, NULL, NULL, NULL, 1, pool); + ("mixed_to_lf", NULL, "\n", 1, NULL, NULL, NULL, NULL, 1, pool); } @@ -1096,10 +1061,10 @@ static svn_error_t * unexpand_author(apr_pool_t *pool) { SVN_ERR(substitute_and_verify - ("author", "\n", NULL, 0, NULL, NULL, "jrandom", NULL, 0, pool)); + ("unexpand_author", "\n", NULL, 0, NULL, NULL, "jrandom", NULL, 0, pool)); SVN_ERR(substitute_and_verify - ("author", "\r\n", NULL, 0, NULL, NULL, "jrandom", NULL, 0, pool)); + ("unexpand_author", "\r\n", NULL, 0, NULL, NULL, "jrandom", NULL, 0, pool)); return SVN_NO_ERROR; } @@ -1109,11 +1074,11 @@ static svn_error_t * unexpand_date(apr_pool_t *pool) { SVN_ERR(substitute_and_verify - ("date", "\n", NULL, 0, + ("unexpand_date", "\n", NULL, 0, NULL, "Wed Jan 9 07:49:05 2002", NULL, NULL, 0, pool)); SVN_ERR(substitute_and_verify - ("date", "\r\n", NULL, 0, + ("unexpand_date", "\r\n", NULL, 0, NULL, "Wed Jan 9 07:49:05 2002", NULL, NULL, 0, pool)); return SVN_NO_ERROR; @@ -1124,11 +1089,11 @@ static svn_error_t * unexpand_author_date(apr_pool_t *pool) { SVN_ERR(substitute_and_verify - ("author_date", "\n", NULL, 0, + ("unexpand_author_date", "\n", NULL, 0, NULL, "Wed Jan 9 07:49:05 2002", "jrandom", NULL, 0, pool)); SVN_ERR(substitute_and_verify - ("author_date", "\r\n", NULL, 0, + ("unexpand_author_date", "\r\n", NULL, 0, NULL, "Wed Jan 9 07:49:05 2002", "jrandom", NULL, 0, pool)); return SVN_NO_ERROR; @@ -1139,11 +1104,11 @@ static svn_error_t * unexpand_author_rev(apr_pool_t *pool) { SVN_ERR(substitute_and_verify - ("author_rev", "\n", NULL, 0, + ("unexpand_author_rev", "\n", NULL, 0, "1729", NULL, "jrandom", NULL, 0, pool)); SVN_ERR(substitute_and_verify - ("author_rev", "\r\n", NULL, 0, + ("unexpand_author_rev", "\r\n", NULL, 0, "1729", NULL, "jrandom", NULL, 0, pool)); return SVN_NO_ERROR; @@ -1154,11 +1119,11 @@ static svn_error_t * unexpand_rev(apr_pool_t *pool) { SVN_ERR(substitute_and_verify - ("rev", "\n", NULL, 0, + ("unexpand_rev", "\n", NULL, 0, "1729", NULL, NULL, NULL, 0, pool)); SVN_ERR(substitute_and_verify - ("rev", "\r\n", NULL, 0, + ("unexpand_rev", "\r\n", NULL, 0, "1729", NULL, NULL, NULL, 0, pool)); return SVN_NO_ERROR; @@ -1169,11 +1134,11 @@ static svn_error_t * unexpand_rev_url(apr_pool_t *pool) { SVN_ERR(substitute_and_verify - ("rev_url", "\n", NULL, 0, + ("unexpand_rev_url", "\n", NULL, 0, "1729", NULL, NULL, "http://subversion.tigris.org", 0, pool)); SVN_ERR(substitute_and_verify - ("rev_url", "\r\n", NULL, 0, + ("unexpand_rev_url", "\r\n", NULL, 0, "1729", NULL, NULL, "http://subversion.tigris.org", 0, pool)); return SVN_NO_ERROR; @@ -1184,7 +1149,7 @@ static svn_error_t * unexpand_author_date_rev_url(apr_pool_t *pool) { SVN_ERR(substitute_and_verify - ("author_date_rev_url", "\n", NULL, 0, + ("unexpand_author_date_rev_url", "\n", NULL, 0, "1729", "Wed Jan 9 07:49:05 2002", "jrandom", @@ -1192,7 +1157,7 @@ unexpand_author_date_rev_url(apr_pool_t *pool) 1, pool)); SVN_ERR(substitute_and_verify - ("author_date_rev_url", "\r\n", NULL, 0, + ("unexpand_author_date_rev_url", "\r\n", NULL, 0, "1729", "Wed Jan 9 07:49:05 2002", "jrandom", @@ -1210,7 +1175,7 @@ static svn_error_t * lf_to_crlf_unexpand_author(apr_pool_t *pool) { return substitute_and_verify - ("lf_to_crlf_author", "\n", "\r\n", 0, + ("lf_to_crlf_unexpand_author", "\n", "\r\n", 0, NULL, NULL, "jrandom", NULL, 0, pool); } @@ -1219,7 +1184,7 @@ static svn_error_t * mixed_to_lf_unexpand_author_date(apr_pool_t *pool) { return substitute_and_verify - ("mixed_to_lf_author_date", NULL, "\n", 1, + ("mixed_to_lf_unexpand_author_date", NULL, "\n", 1, NULL, "Wed Jan 9 07:49:05 2002", "jrandom", NULL, 0, pool); } @@ -1228,7 +1193,7 @@ static svn_error_t * crlf_to_cr_unexpand_author_rev(apr_pool_t *pool) { return substitute_and_verify - ("crlf_to_cr_author_rev", "\r\n", "\r", 0, + ("crlf_to_cr_unexpand_author_rev", "\r\n", "\r", 0, "1729", NULL, "jrandom", NULL, 0, pool); } @@ -1237,7 +1202,7 @@ static svn_error_t * cr_to_crlf_unexpand_rev(apr_pool_t *pool) { return substitute_and_verify - ("cr_to_crlf_rev", "\r", "\r\n", 0, + ("cr_to_crlf_unexpand_rev", "\r", "\r\n", 0, "1729", NULL, NULL, NULL, 0, pool); } @@ -1246,7 +1211,7 @@ static svn_error_t * cr_to_crlf_unexpand_rev_url(apr_pool_t *pool) { return substitute_and_verify - ("cr_to_crlf_rev_url", "\r", "\r\n", 0, + ("cr_to_crlf_unexpand_rev_url", "\r", "\r\n", 0, "1729", NULL, NULL, "http://subversion.tigris.org", 0, pool); } @@ -1255,7 +1220,7 @@ static svn_error_t * mixed_to_crlf_unexpand_author_date_rev_url(apr_pool_t *pool) { return substitute_and_verify - ("mixed_to_crlf_author_date_rev_url", NULL, "\r\n", 1, + ("mixed_to_crlf_unexpand_author_date_rev_url", NULL, "\r\n", 1, "1729", "Wed Jan 9 07:49:05 2002", "jrandom", @@ -1268,7 +1233,9 @@ mixed_to_crlf_unexpand_author_date_rev_url(apr_pool_t *pool) /* The test table. */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 7; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, /* The no-op conversion. */ @@ -1362,3 +1329,5 @@ struct svn_test_descriptor_t test_funcs[] = "mixed_to_crlf; unexpand author, date, rev, url"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/utf-test.c b/subversion/tests/libsvn_subr/utf-test.c index 2028e14..dd81ccd 100644 --- a/subversion/tests/libsvn_subr/utf-test.c +++ b/subversion/tests/libsvn_subr/utf-test.c @@ -25,6 +25,7 @@ #include "svn_utf.h" #include "svn_pools.h" +#include "private/svn_string_private.h" #include "private/svn_utf_private.h" /* Random number seed. Yes, it's global, just pretend you can't see it. */ @@ -226,7 +227,7 @@ test_utf_cstring_to_utf8_ex2(apr_pool_t *pool) const char *expected_result; const char *from_page; } tests[] = { - {"ascii text\n", "ascii text\n", "unexistant-page"}, + {"ascii text\n", "ascii text\n", "unexistent-page"}, {"Edelwei\xdf", "Edelwei\xc3\x9f", "ISO-8859-1"} }; @@ -266,7 +267,7 @@ test_utf_cstring_from_utf8_ex2(apr_pool_t *pool) const char *expected_result; const char *to_page; } tests[] = { - {"ascii text\n", "ascii text\n", "unexistant-page"}, + {"ascii text\n", "ascii text\n", "unexistent-page"}, {"Edelwei\xc3\x9f", "Edelwei\xdf", "ISO-8859-1"} }; @@ -294,10 +295,540 @@ test_utf_cstring_from_utf8_ex2(apr_pool_t *pool) return SVN_NO_ERROR; } +/* Test normalization-independent UTF-8 string comparison */ +static svn_error_t * +test_utf_collated_compare(apr_pool_t *pool) +{ + /* Normalized: NFC */ + static const char nfc[] = + "\xe1\xb9\xa8" /* S with dot above and below */ + "\xc5\xaf" /* u with ring */ + "\xe1\xb8\x87" /* b with macron below */ + "\xe1\xb9\xbd" /* v with tilde */ + "\xe1\xb8\x9d" /* e with breve and cedilla */ + "\xc8\x91" /* r with double grave */ + "\xc5\xa1" /* s with caron */ + "\xe1\xb8\xaf" /* i with diaeresis and acute */ + "\xe1\xbb\x9d" /* o with grave and hook */ + "\xe1\xb9\x8b"; /* n with circumflex below */ + + /* Normalized: NFD */ + static const char nfd[] = + "S\xcc\xa3\xcc\x87" /* S with dot above and below */ + "u\xcc\x8a" /* u with ring */ + "b\xcc\xb1" /* b with macron below */ + "v\xcc\x83" /* v with tilde */ + "e\xcc\xa7\xcc\x86" /* e with breve and cedilla */ + "r\xcc\x8f" /* r with double grave */ + "s\xcc\x8c" /* s with caron */ + "i\xcc\x88\xcc\x81" /* i with diaeresis and acute */ + "o\xcc\x9b\xcc\x80" /* o with grave and hook */ + "n\xcc\xad"; /* n with circumflex below */ + + /* Mixed, denormalized */ + static const char mixup[] = + "S\xcc\x87\xcc\xa3" /* S with dot above and below */ + "\xc5\xaf" /* u with ring */ + "b\xcc\xb1" /* b with macron below */ + "\xe1\xb9\xbd" /* v with tilde */ + "e\xcc\xa7\xcc\x86" /* e with breve and cedilla */ + "\xc8\x91" /* r with double grave */ + "s\xcc\x8c" /* s with caron */ + "\xe1\xb8\xaf" /* i with diaeresis and acute */ + "o\xcc\x80\xcc\x9b" /* o with grave and hook */ + "\xe1\xb9\x8b"; /* n with circumflex below */ + + static const char longer[] = + "\xe1\xb9\xa8" /* S with dot above and below */ + "\xc5\xaf" /* u with ring */ + "\xe1\xb8\x87" /* b with macron below */ + "\xe1\xb9\xbd" /* v with tilde */ + "\xe1\xb8\x9d" /* e with breve and cedilla */ + "\xc8\x91" /* r with double grave */ + "\xc5\xa1" /* s with caron */ + "\xe1\xb8\xaf" /* i with diaeresis and acute */ + "\xe1\xbb\x9d" /* o with grave and hook */ + "\xe1\xb9\x8b" /* n with circumflex below */ + "X"; + + static const char shorter[] = + "\xe1\xb9\xa8" /* S with dot above and below */ + "\xc5\xaf" /* u with ring */ + "\xe1\xb8\x87" /* b with macron below */ + "\xe1\xb9\xbd" /* v with tilde */ + "\xe1\xb8\x9d" /* e with breve and cedilla */ + "\xc8\x91" /* r with double grave */ + "\xc5\xa1" /* s with caron */ + "\xe1\xb8\xaf" /* i with diaeresis and acute */ + "\xe1\xbb\x9d"; /* o with grave and hook */ + + static const char lowcase[] = + "s\xcc\x87\xcc\xa3" /* s with dot above and below */ + "\xc5\xaf" /* u with ring */ + "b\xcc\xb1" /* b with macron below */ + "\xe1\xb9\xbd" /* v with tilde */ + "e\xcc\xa7\xcc\x86" /* e with breve and cedilla */ + "\xc8\x91" /* r with double grave */ + "s\xcc\x8c" /* s with caron */ + "\xe1\xb8\xaf" /* i with diaeresis and acute */ + "o\xcc\x80\xcc\x9b" /* o with grave and hook */ + "\xe1\xb9\x8b"; /* n with circumflex below */ + + static const struct utfcmp_test_t { + const char *stra; + char op; + const char *strb; + const char *taga; + const char *tagb; + } utfcmp_tests[] = { + /* Empty key */ + {"", '=', "", "empty", "empty"}, + {"", '<', "a", "empty", "nonempty"}, + {"a", '>', "", "nonempty", "empty"}, + + /* Deterministic ordering */ + {"a", '<', "b", "a", "b"}, + {"b", '<', "c", "b", "c"}, + {"a", '<', "c", "a", "c"}, + + /* Normalized equality */ + {nfc, '=', nfd, "nfc", "nfd"}, + {nfd, '=', nfc, "nfd", "nfc"}, + {nfc, '=', mixup, "nfc", "mixup"}, + {nfd, '=', mixup, "nfd", "mixup"}, + {mixup, '=', nfd, "mixup", "nfd"}, + {mixup, '=', nfc, "mixup", "nfc"}, + + /* Key length */ + {nfc, '<', longer, "nfc", "longer"}, + {longer, '>', nfc, "longer", "nfc"}, + {nfd, '>', shorter, "nfd", "shorter"}, + {shorter, '<', nfd, "shorter", "nfd"}, + {mixup, '<', lowcase, "mixup", "lowcase"}, + {lowcase, '>', mixup, "lowcase", "mixup"}, + + {NULL, 0, NULL, NULL, NULL} + }; + + + const struct utfcmp_test_t *ut; + svn_membuf_t bufa, bufb; + svn_membuf__create(&bufa, 0, pool); + svn_membuf__create(&bufb, 0, pool); + + srand(111); + for (ut = utfcmp_tests; ut->stra; ++ut) + { + const svn_boolean_t implicit_size = (rand() % 17) & 1; + const apr_size_t lena = (implicit_size + ? SVN_UTF__UNKNOWN_LENGTH : strlen(ut->stra)); + const apr_size_t lenb = (implicit_size + ? SVN_UTF__UNKNOWN_LENGTH : strlen(ut->strb)); + int result; + + SVN_ERR(svn_utf__normcmp(&result, + ut->stra, lena, ut->strb, lenb, + &bufa, &bufb)); + + /* UCS-4 debugging dump of the decomposed strings + { + const apr_int32_t *const ucsbufa = bufa.data; + const apr_int32_t *const ucsbufb = bufb.data; + apr_size_t i; + + printf("(%c)%7s %c %s\n", ut->op, + ut->taga, (!result ? '=' : (result < 0 ? '<' : '>')), ut->tagb); + + for (i = 0; i < bufa.size || i < bufb.size; ++i) + { + if (i < bufa.size && i < bufb.size) + printf(" U+%04X U+%04X\n", ucsbufa[i], ucsbufb[i]); + else if (i < bufa.size) + printf(" U+%04X\n", ucsbufa[i]); + else + printf(" U+%04X\n", ucsbufb[i]); + } + } + */ + + if (('=' == ut->op && 0 != result) + || ('<' == ut->op && 0 <= result) + || ('>' == ut->op && 0 >= result)) + { + return svn_error_createf + (SVN_ERR_TEST_FAILED, NULL, + "Ut->Op '%s' %c '%s' but '%s' %c '%s'", + ut->taga, ut->op, ut->tagb, + ut->taga, (!result ? '=' : (result < 0 ? '<' : '>')), ut->tagb); + } + } + + return SVN_NO_ERROR; +} + + + +static svn_error_t * +test_utf_pattern_match(apr_pool_t *pool) +{ + static const struct glob_test_t { + svn_boolean_t sql_like; + svn_boolean_t matches; + const char *pattern; + const char *string; + const char *escape; + } glob_tests[] = { +#define LIKE_MATCH TRUE, TRUE +#define LIKE_FAIL TRUE, FALSE +#define GLOB_MATCH FALSE, TRUE +#define GLOB_FAIL FALSE, FALSE + + {LIKE_FAIL, "", "test", NULL}, + {GLOB_FAIL, "", "test", NULL}, + {LIKE_FAIL, "", "%", NULL}, + {GLOB_FAIL, "", "*", NULL}, + {LIKE_FAIL, "test", "%", NULL}, + {GLOB_FAIL, "test", "*", NULL}, + {LIKE_MATCH, "test", "test", NULL}, + {GLOB_MATCH, "test", "test", NULL}, + {LIKE_MATCH, "t\xe1\xb8\x9dst", "te\xcc\xa7\xcc\x86st", NULL}, + {GLOB_MATCH, "te\xcc\xa7\xcc\x86st", "t\xe1\xb8\x9dst", NULL}, + + {LIKE_FAIL, "test", "test", "\xe1\xb8\x9d"}, /* escape char not ascii */ + {LIKE_FAIL, "test", "test", ""}, /* empty escape string */ + + {LIKE_MATCH, "te#st", "test", "#"}, + {LIKE_FAIL, "te#st", "test", NULL}, + {GLOB_MATCH, "te\\st", "test", NULL}, + {LIKE_MATCH, "te##st", "te#st", "#"}, + {LIKE_FAIL, "te##st", "te#st", NULL}, + {GLOB_MATCH, "te\\\\st", "te\\st", NULL}, + {GLOB_FAIL, "te\\\\st", "te\\st", "\\"}, /* escape char with glob */ + {LIKE_FAIL, "te#%t", "te%t", NULL}, + {LIKE_MATCH, "te#%t", "te%t", "#"}, + {GLOB_MATCH, "te\\*t", "te*t", NULL}, + {LIKE_FAIL, "te#%t", "test", NULL}, + {GLOB_FAIL, "te\\*t", "test", NULL}, + {LIKE_FAIL, "te#_t", "te_t", NULL}, + {LIKE_MATCH, "te#_t", "te_t", "#"}, + {GLOB_MATCH, "te\\?t", "te?t", NULL}, + {LIKE_FAIL, "te#_t", "test", NULL}, + {LIKE_FAIL, "te#_t", "test", "#"}, + {GLOB_FAIL, "te\\?t", "test", NULL}, + + {LIKE_MATCH, "_est", "test", NULL}, + {GLOB_MATCH, "?est", "test", NULL}, + {LIKE_MATCH, "te_t", "test", NULL}, + {GLOB_MATCH, "te?t", "test", NULL}, + {LIKE_MATCH, "tes_", "test", NULL}, + {GLOB_MATCH, "tes?", "test", NULL}, + {LIKE_FAIL, "test_", "test", NULL}, + {GLOB_FAIL, "test?", "test", NULL}, + + {LIKE_MATCH, "[s%n]", "[subversion]", NULL}, + {GLOB_FAIL, "[s*n]", "[subversion]", NULL}, + {LIKE_MATCH, "#[s%n]", "[subversion]", "#"}, + {GLOB_MATCH, "\\[s*n]", "[subversion]", NULL}, + + {GLOB_MATCH, ".[\\-\\t]", ".t", NULL}, + {GLOB_MATCH, "test*?*[a-z]*", "testgoop", NULL}, + {GLOB_MATCH, "te[^x]t", "test", NULL}, + {GLOB_MATCH, "te[^abc]t", "test", NULL}, + {GLOB_MATCH, "te[^x]t", "test", NULL}, + {GLOB_MATCH, "te[!x]t", "test", NULL}, + {GLOB_FAIL, "te[^x]t", "text", NULL}, + {GLOB_FAIL, "te[^\\x]t", "text", NULL}, + {GLOB_FAIL, "te[^x\\", "text", NULL}, + {GLOB_FAIL, "te[/]t", "text", NULL}, + {GLOB_MATCH, "te[r-t]t", "test", NULL}, + {GLOB_MATCH, "te[r-Tz]t", "tezt", NULL}, + {GLOB_FAIL, "te[R-T]t", "tent", NULL}, +/* {GLOB_MATCH, "tes[]t]", "test", NULL}, */ + {GLOB_MATCH, "tes[t-]", "test", NULL}, + {GLOB_MATCH, "tes[t-]]", "test]", NULL}, + {GLOB_FAIL, "tes[t-]]", "test", NULL}, + {GLOB_FAIL, "tes[u-]", "test", NULL}, + {GLOB_FAIL, "tes[t-]", "tes[t-]", NULL}, + {GLOB_MATCH, "test[/-/]", "test/", NULL}, + {GLOB_MATCH, "test[\\/-/]", "test/", NULL}, + {GLOB_MATCH, "test[/-\\/]", "test/", NULL}, + +#undef LIKE_MATCH +#undef LIKE_FAIL +#undef GLOB_MATCH +#undef GLOB_FAIL + + {FALSE, FALSE, NULL, NULL, NULL} + }; + + const struct glob_test_t *gt; + svn_membuf_t bufa, bufb, bufc; + svn_membuf__create(&bufa, 0, pool); + svn_membuf__create(&bufb, 0, pool); + svn_membuf__create(&bufc, 0, pool); + + srand(79); + for (gt = glob_tests; gt->pattern; ++gt) + { + const svn_boolean_t implicit_size = (rand() % 13) & 1; + const apr_size_t lenptn = (implicit_size + ? SVN_UTF__UNKNOWN_LENGTH + : strlen(gt->pattern)); + const apr_size_t lenstr = (implicit_size + ? SVN_UTF__UNKNOWN_LENGTH + : strlen(gt->string)); + const apr_size_t lenesc = (implicit_size + ? SVN_UTF__UNKNOWN_LENGTH + : (gt->escape ? strlen(gt->escape) : 0)); + svn_boolean_t match; + svn_error_t *err; + + + err = svn_utf__glob(&match, + gt->pattern, lenptn, + gt->string, lenstr, + gt->escape, lenesc, + gt->sql_like, &bufa, &bufb, &bufc); + + if (!gt->sql_like && gt->escape && !err) + return svn_error_create + (SVN_ERR_TEST_FAILED, err, "Failed to detect GLOB ESCAPE"); + + if ((err && gt->matches) + || (!err && !match != !gt->matches)) + { + if (gt->sql_like) + return svn_error_createf + (SVN_ERR_TEST_FAILED, err, + "Wrong result: %s'%s' LIKE '%s'%s%s%s%s", + (gt->matches ? "NOT " : ""), gt->string, gt->pattern, + (gt->escape ? " ESCAPE " : ""), (gt->escape ? "'" : ""), + (gt->escape ? gt->escape : ""), (gt->escape ? "'" : "")); + else + return svn_error_createf + (SVN_ERR_TEST_FAILED, err, "Wrong result: %s%s GLOB %s", + (gt->matches ? "NOT " : ""), gt->string, gt->pattern); + } + + if (err) + svn_error_clear(err); + } + + return SVN_NO_ERROR; +} + + +static svn_error_t * +test_utf_fuzzy_escape(apr_pool_t *pool) +{ + + /* Accented latin, mixed normalization */ + static const char mixup[] = + "S\xcc\x87\xcc\xa3" /* S with dot above and below */ + "\xc5\xaf" /* u with ring */ + "b\xcc\xb1" /* b with macron below */ + "\xe1\xb9\xbd" /* v with tilde */ + "e\xcc\xa7\xcc\x86" /* e with breve and cedilla */ + "\xc8\x91" /* r with double grave */ + "s\xcc\x8c" /* s with caron */ + "\xe1\xb8\xaf" /* i with diaeresis and acute */ + "o\xcc\x80\xcc\x9b" /* o with grave and hook */ + "\xe1\xb9\x8b"; /* n with circumflex below */ + + /* As above, but latin lowercase 'o' replaced with Greek 'omicron' */ + static const char greekish[] = + "S\xcc\x87\xcc\xa3" /* S with dot above and below */ + "\xc5\xaf" /* u with ring */ + "b\xcc\xb1" /* b with macron below */ + "\xe1\xb9\xbd" /* v with tilde */ + "e\xcc\xa7\xcc\x86" /* e with breve and cedilla */ + "\xc8\x91" /* r with double grave */ + "s\xcc\x8c" /* s with caron */ + "\xe1\xb8\xaf" /* i with diaeresis and acute */ + "\xce\xbf\xcc\x80\xcc\x9b" /* omicron with grave and hook */ + "\xe1\xb9\x8b"; /* n with circumflex below */ + + /* More interesting invalid characters. */ + static const char invalid[] = + "Not Unicode: \xef\xb7\x91;" /* U+FDD1 */ + "Out of range: \xf4\x90\x80\x81;" /* U+110001 */ + "Not UTF-8: \xe6;" + "Null byte: \0;"; + + const char *fuzzy; + + fuzzy = svn_utf__fuzzy_escape(mixup, strlen(mixup), pool); + SVN_TEST_ASSERT(0 == strcmp(fuzzy, "Subversion")); + + fuzzy = svn_utf__fuzzy_escape(greekish, strlen(greekish), pool); + SVN_TEST_ASSERT(0 == strcmp(fuzzy, "Subversi{U+03BF}n")); + + fuzzy = svn_utf__fuzzy_escape(invalid, sizeof(invalid) - 1, pool); + /*fprintf(stderr, "%s\n", fuzzy);*/ + SVN_TEST_ASSERT(0 == strcmp(fuzzy, + "Not Unicode: {U?FDD1};" + "Out of range: ?\\F4?\\90?\\80?\\81;" + "Not UTF-8: ?\\E6;" + "Null byte: \\0;")); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_utf_is_normalized(apr_pool_t *pool) +{ + /* Normalized: NFC */ + static const char nfc[] = + "\xe1\xb9\xa8" /* S with dot above and below */ + "\xc5\xaf" /* u with ring */ + "\xe1\xb8\x87" /* b with macron below */ + "\xe1\xb9\xbd" /* v with tilde */ + "\xe1\xb8\x9d" /* e with breve and cedilla */ + "\xc8\x91" /* r with double grave */ + "\xc5\xa1" /* s with caron */ + "\xe1\xb8\xaf" /* i with diaeresis and acute */ + "\xe1\xbb\x9d" /* o with grave and hook */ + "\xe1\xb9\x8b"; /* n with circumflex below */ + + /* Normalized: NFD */ + static const char nfd[] = + "S\xcc\xa3\xcc\x87" /* S with dot above and below */ + "u\xcc\x8a" /* u with ring */ + "b\xcc\xb1" /* b with macron below */ + "v\xcc\x83" /* v with tilde */ + "e\xcc\xa7\xcc\x86" /* e with breve and cedilla */ + "r\xcc\x8f" /* r with double grave */ + "s\xcc\x8c" /* s with caron */ + "i\xcc\x88\xcc\x81" /* i with diaeresis and acute */ + "o\xcc\x9b\xcc\x80" /* o with grave and hook */ + "n\xcc\xad"; /* n with circumflex below */ + + /* Mixed, denormalized */ + static const char mixup[] = + "S\xcc\x87\xcc\xa3" /* S with dot above and below */ + "\xc5\xaf" /* u with ring */ + "b\xcc\xb1" /* b with macron below */ + "\xe1\xb9\xbd" /* v with tilde */ + "e\xcc\xa7\xcc\x86" /* e with breve and cedilla */ + "\xc8\x91" /* r with double grave */ + "s\xcc\x8c" /* s with caron */ + "\xe1\xb8\xaf" /* i with diaeresis and acute */ + "o\xcc\x80\xcc\x9b" /* o with grave and hook */ + "\xe1\xb9\x8b"; /* n with circumflex below */ + + /* Invalid UTF-8 */ + static const char invalid[] = + "\xe1\xb9\xa8" /* S with dot above and below */ + "\xc5\xaf" /* u with ring */ + "\xe1\xb8\x87" /* b with macron below */ + "\xe1\xb9\xbd" /* v with tilde */ + "\xe1\xb8\x9d" /* e with breve and cedilla */ + "\xc8\x91" /* r with double grave */ + "\xc5\xa1" /* s with caron */ + "\xe1\xb8\xaf" /* i with diaeresis and acute */ + "\xe6" /* Invalid byte */ + "\xe1\xb9\x8b"; /* n with circumflex below */ + + SVN_ERR_ASSERT(svn_utf__is_normalized(nfc, pool)); + SVN_ERR_ASSERT(!svn_utf__is_normalized(nfd, pool)); + SVN_ERR_ASSERT(!svn_utf__is_normalized(mixup, pool)); + SVN_ERR_ASSERT(!svn_utf__is_normalized(invalid, pool)); + + return SVN_NO_ERROR; +} + + +static svn_error_t * +test_utf_conversions(apr_pool_t *pool) +{ + static const struct cvt_test_t + { + svn_boolean_t sixteenbit; + svn_boolean_t bigendian; + const char *source; + const char *result; + } tests[] = { + +#define UTF_32_LE FALSE, FALSE +#define UTF_32_BE FALSE, TRUE +#define UTF_16_LE TRUE, FALSE +#define UTF_16_BE TRUE, TRUE + + /* Normal character conversion */ + { UTF_32_LE, "t\0\0\0" "e\0\0\0" "s\0\0\0" "t\0\0\0" "\0\0\0\0", "test" }, + { UTF_32_BE, "\0\0\0t" "\0\0\0e" "\0\0\0s" "\0\0\0t" "\0\0\0\0", "test" }, + { UTF_16_LE, "t\0" "e\0" "s\0" "t\0" "\0\0", "test" }, + { UTF_16_BE, "\0t" "\0e" "\0s" "\0t" "\0\0", "test" }, + + /* Valid surrogate pairs */ + { UTF_16_LE, "\x00\xD8" "\x00\xDC" "\0\0", "\xf0\x90\x80\x80" }, /* U+010000 */ + { UTF_16_LE, "\x34\xD8" "\x1E\xDD" "\0\0", "\xf0\x9d\x84\x9e" }, /* U+01D11E */ + { UTF_16_LE, "\xFF\xDB" "\xFD\xDF" "\0\0", "\xf4\x8f\xbf\xbd" }, /* U+10FFFD */ + + { UTF_16_BE, "\xD8\x00" "\xDC\x00" "\0\0", "\xf0\x90\x80\x80" }, /* U+010000 */ + { UTF_16_BE, "\xD8\x34" "\xDD\x1E" "\0\0", "\xf0\x9d\x84\x9e" }, /* U+01D11E */ + { UTF_16_BE, "\xDB\xFF" "\xDF\xFD" "\0\0", "\xf4\x8f\xbf\xbd" }, /* U+10FFFD */ + + /* Swapped, single and trailing surrogate pairs */ + { UTF_16_LE, "*\0" "\x00\xDC" "\x00\xD8" "*\0\0\0", "*\xed\xb0\x80" "\xed\xa0\x80*" }, + { UTF_16_LE, "*\0" "\x1E\xDD" "*\0\0\0", "*\xed\xb4\x9e*" }, + { UTF_16_LE, "*\0" "\xFF\xDB" "*\0\0\0", "*\xed\xaf\xbf*" }, + { UTF_16_LE, "\x1E\xDD" "\0\0", "\xed\xb4\x9e" }, + { UTF_16_LE, "\xFF\xDB" "\0\0", "\xed\xaf\xbf" }, + + { UTF_16_BE, "\0*" "\xDC\x00" "\xD8\x00" "\0*\0\0", "*\xed\xb0\x80" "\xed\xa0\x80*" }, + { UTF_16_BE, "\0*" "\xDD\x1E" "\0*\0\0", "*\xed\xb4\x9e*" }, + { UTF_16_BE, "\0*" "\xDB\xFF" "\0*\0\0", "*\xed\xaf\xbf*" }, + { UTF_16_BE, "\xDD\x1E" "\0\0", "\xed\xb4\x9e" }, + { UTF_16_BE, "\xDB\xFF" "\0\0", "\xed\xaf\xbf" }, + +#undef UTF_32_LE +#undef UTF_32_BE +#undef UTF_16_LE +#undef UTF_16_BE + + { 0 } + }; + + const struct cvt_test_t *tc; + const svn_string_t *result; + int i; + + for (i = 1, tc = tests; tc->source; ++tc, ++i) + { + if (tc->sixteenbit) + SVN_ERR(svn_utf__utf16_to_utf8(&result, (const void*)tc->source, + SVN_UTF__UNKNOWN_LENGTH, + tc->bigendian, pool, pool)); + else + SVN_ERR(svn_utf__utf32_to_utf8(&result, (const void*)tc->source, + SVN_UTF__UNKNOWN_LENGTH, + tc->bigendian, pool, pool)); + SVN_ERR_ASSERT(0 == strcmp(result->data, tc->result)); + } + + /* Test counted strings with NUL characters */ + SVN_ERR(svn_utf__utf16_to_utf8( + &result, (void*)("x\0" "\0\0" "y\0" "*\0"), 3, + FALSE, pool, pool)); + SVN_ERR_ASSERT(0 == memcmp(result->data, "x\0y", 3)); + + SVN_ERR(svn_utf__utf32_to_utf8( + &result, + (void*)("\0\0\0x" "\0\0\0\0" "\0\0\0y" "\0\0\0*"), 3, + TRUE, pool, pool)); + SVN_ERR_ASSERT(0 == memcmp(result->data, "x\0y", 3)); + + return SVN_NO_ERROR; +} + + /* The test table. */ -struct svn_test_descriptor_t test_funcs[] = +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = { SVN_TEST_NULL, SVN_TEST_PASS2(utf_validate, @@ -308,5 +839,17 @@ struct svn_test_descriptor_t test_funcs[] = "test svn_utf_cstring_to_utf8_ex2"), SVN_TEST_PASS2(test_utf_cstring_from_utf8_ex2, "test svn_utf_cstring_from_utf8_ex2"), + SVN_TEST_PASS2(test_utf_collated_compare, + "test svn_utf__normcmp"), + SVN_TEST_PASS2(test_utf_pattern_match, + "test svn_utf__glob"), + SVN_TEST_PASS2(test_utf_fuzzy_escape, + "test svn_utf__fuzzy_escape"), + SVN_TEST_PASS2(test_utf_is_normalized, + "test svn_utf__is_normalized"), + SVN_TEST_PASS2(test_utf_conversions, + "test svn_utf__utf{16,32}_to_utf8"), SVN_TEST_NULL }; + +SVN_TEST_MAIN diff --git a/subversion/tests/libsvn_subr/x509-test.c b/subversion/tests/libsvn_subr/x509-test.c new file mode 100644 index 0000000..a3806b8 --- /dev/null +++ b/subversion/tests/libsvn_subr/x509-test.c @@ -0,0 +1,848 @@ +/* + * x509-test.c -- test the x509 parser functions + * + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + */ + +#include <string.h> +#include "svn_x509.h" +#include "svn_base64.h" +#include "svn_time.h" +#include "svn_pools.h" +#include "svn_string.h" + +#include "../svn_test.h" + +struct x509_test { + const char *base64_cert; /* Base64 encoded DER X.509 cert */ + const char *subject; /* Subject Distinguished Name */ + const char *subject_oids; /* Space separated list of oids in Subject */ + const char *issuer; /* Issuer Distinguished Name */ + const char *issuer_oids; /* Space separated list of oids in Issuer */ + + /* These timesamps are in the format that svn_time_to_cstring() produces. + * This is not the same string as the parser returns since it returns + * the ressult of svn_time_to_human_cstring(), which is in the local + * timezone. So we can't store exactly what the parser will output. */ + const char *valid_from; + const char *valid_to; + const char *hostnames; + const char *sha1_digest; +}; + +static struct x509_test cert_tests[] = { + /* contains extensions and uses a sha256 algorithm */ + { "MIIEtzCCA5+gAwIBAgIQWGBOrapkezd+BWVsAtmtmTANBgkqhkiG9w0BAQsFADA8" + "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMVGhhd3RlLCBJbmMuMRYwFAYDVQQDEw1U" + "aGF3dGUgU1NMIENBMB4XDTE0MDQxMTAwMDAwMFoXDTE2MDQwNzIzNTk1OVowgYsx" + "CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxQLRm9yZXN0" + "IEhpbGwxIzAhBgNVBAoUGkFwYWNoZSBTb2Z0d2FyZSBGb3VuZGF0aW9uMRcwFQYD" + "VQQLFA5JbmZyYXN0cnVjdHVyZTEVMBMGA1UEAxQMKi5hcGFjaGUub3JnMIIBIjAN" + "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Tq4mH+stRoxe4xth8tUCgLt+P4L" + "D/JWZz4a2IecaaAk57vIlTxEyP16fUShUfxVJnD0KV11zv2qaEUXNaA6hKd4H/oB" + "u2OyGev+quRM+aFCjWqASkXt7fLGsIkHAwP3XwBVBpARbcXJeCjCBxqaYrQqS8LT" + "wfPUD9eYncGlQ+ixb3Bosy7TmkWKeLsRdS90cAO/rdgQ8OI7kLT/1tr5GpF9RmXo" + "RnVqMP+U0zGd/BNNSneg7emb7TxLzxeMKZ7QbF4MZi8RRN11spvx8/f92CiYrGGu" + "y67VdOGPaomYc+VZ2syLwduHGK40ADrEK3+MQpsRFB0dM08j9bhpr5A44wIDAQAB" + "o4IBYzCCAV8wFwYDVR0RBBAwDoIMKi5hcGFjaGUub3JnMAkGA1UdEwQCMAAwQgYD" + "VR0gBDswOTA3BgpghkgBhvhFAQc2MCkwJwYIKwYBBQUHAgEWG2h0dHBzOi8vd3d3" + "LnRoYXd0ZS5jb20vY3BzLzAOBgNVHQ8BAf8EBAMCBaAwHwYDVR0jBBgwFoAUp6KD" + "uzRFQD381TBPErk+oQGf9tswOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL3N2ci1v" + "di1jcmwudGhhd3RlLmNvbS9UaGF3dGVPVi5jcmwwHQYDVR0lBBYwFAYIKwYBBQUH" + "AwEGCCsGAQUFBwMCMGkGCCsGAQUFBwEBBF0wWzAiBggrBgEFBQcwAYYWaHR0cDov" + "L29jc3AudGhhd3RlLmNvbTA1BggrBgEFBQcwAoYpaHR0cDovL3N2ci1vdi1haWEu" + "dGhhd3RlLmNvbS9UaGF3dGVPVi5jZXIwDQYJKoZIhvcNAQELBQADggEBAF52BLvl" + "x5or9/aO7+cPhxuPxwiNRgbvHdCakD7n8vzjNyct9fKp6/XxB6GQiTZ0nZPJOyIu" + "Pi1QDLKOXvaPeLKDBilL/+mrn/ev3s/aRQSrUsieKDoQnqtmlxEHc/T3+Ni/RZob" + "PD4GzPuNKpK3BIc0fk/95T8R1DjBSQ5/clvkzOKtcl3VffAwnHiE9TZx9js7kZwO" + "b9nOKX8DFao3EpQcS7qn63Ibzbq5A6ry8ZNRQSIJK/xlCAWoyUd1uxnqGFnus8wb" + "9RVZJQe8YvyytBjgbE3QjnfPOxoEJA3twupnPmH+OCTM6V3TZqpRZj/sZ5rtIQ++" + "hI5FdJWUWVSgnSw=", + "C=US, ST=Maryland, L=Forest Hill, O=Apache Software Foundation, " + "OU=Infrastructure, CN=*.apache.org", + "2.5.4.6 2.5.4.8 2.5.4.7 2.5.4.10 2.5.4.11 2.5.4.3", + "C=US, O=Thawte, Inc., CN=Thawte SSL CA", + "2.5.4.6 2.5.4.10 2.5.4.3", + "2014-04-11T00:00:00.000000Z", + "2016-04-07T23:59:59.000000Z", + "*.apache.org", + "151d8ad1e1bac21466bc2836ba80b5fcf872f37c" }, + /* the expiration is after 2049 so the expiration is in the + * generalized format, while the start date is still in the UTC + * format. Note this is actually a CA cert but that really doesn't + * matter here. */ + { "MIIDtzCCAp+gAwIBAgIJAJKX85dqh3RvMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV" + "BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX" + "aWRnaXRzIFB0eSBMdGQwIBcNMTQwNjI3MTczMTUxWhgPMjExNDA2MDMxNzMxNTFa" + "MEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJ" + "bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw" + "ggEKAoIBAQDaa4gwNBB6vgWrlOIEMdzvD06zmmiocEt6UnTHtmAcfrBuDnKrBwEh" + "f5JxneL16XIuKwK6n/4omBtem/PPjjpOLM9PMQuoO0cpQ0UGFnfpmko6PSQoqRHl" + "qTbDGv4usn7qdZV+FKz/B9CMonRSzWHMz5YPmqfob6BqaaJY/qJEzHJA24bm4jPH" + "IsaVCInEGpqAUpejwBzNujfbLibBNrVX7K846zk+tnsNR90kP5h3IRP3SdWVywKC" + "AMN2izzhmaDhuPzaTBobovr+ySJShmX6gdB5PpWkm6rcBl6RJ+tM0ZBSJjQvkYp4" + "seV+rcXFgpJP/aQL3vhDON32tjWh3A2JAgMBAAGjgacwgaQwHQYDVR0OBBYEFF+N" + "7TyDI8THpAbx1pfzFFtl5z4iMHUGA1UdIwRuMGyAFF+N7TyDI8THpAbx1pfzFFtl" + "5z4ioUmkRzBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8G" + "A1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkggkAkpfzl2qHdG8wDAYDVR0T" + "BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAo4t9fYe2I+XIQn8i/KI9UFEE9fue" + "w6rQMnf9yyd8nwL+IcV84hvyNrq0+7SptUBMq3rsEf5UIBIBI4Oa614mJ/Kt976O" + "S7Sa1IPH7j+zb/jqH/xGskEVi25dZz7psFCmi7Hm9dnVz9YKa2yLW6R2KZcTVxCx" + "SSdDRlD7SonsYeq2fGrAo7Y9xfZsiJ2ZbJ18kHs2coMWuhgSrN9jrML6mb5B+k22" + "/rgsCJgFsBDPBYR3ju0Ahqg7v6kwg9O2PJzyb4ljsw8oI0sCwHTZW5I5FMq2D9g6" + "hj80N2fhS9QWoLyeKoMTNB2Do6VaNrLrCJiscZWrsnM1f+XBqV8hMuHX8A==", + "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd", + "2.5.4.6 2.5.4.8 2.5.4.10", + "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd", + "2.5.4.6 2.5.4.8 2.5.4.10", + "2014-06-27T17:31:51.000000Z", + "2114-06-03T17:31:51.000000Z", + NULL, + "db3a959e145acc2741f9eeecbeabce53cc5b7362" }, + /* The subject (except for country code) is UTF-8 encoded. + * created with openssl using utf8-yes and string_mask=utf8only */ + { "MIIDrTCCApWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJBVTET" + "MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ" + "dHkgTHRkMB4XDTE0MDcwMjE4MzYxMFoXDTE1MDcwMjE4MzYxMFowcjELMAkGA1UE" + "BhMCR1IxFTATBgNVBAgMDM6Rz4TPhM65zrrOrjETMBEGA1UEBwwKzpHOuM6uzr3O" + "sTEdMBsGA1UECgwUz4DOsc+BzqzOtM61zrnOs868zrExGDAWBgNVBAMMD3d3dy5l" + "eGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVPuQPz" + "INjsiXl+GeiXMzXV1Bfm8vzbQnMLAFY/ZKKK4gpy58xcNrmur//Fd38naTM/DetO" + "PEoDa+vQ48CnUWCDT3CKUA3BnrjtR3/EITC7XRcfk5lyk0IZr9RZB1WedQxK1n5E" + "Ecz8EBrm9+1442Nmg/y1F8d/2F2CjKB+PgfOP1WWaIQcsjLsftXec+kGjc34kwbS" + "9D9H+bRrPVcOzBZOqC+K0K7MMOxKA5mMi4b/Nlep76gTaUyonclRIADanAyaK5WG" + "0IkEI/nxufaP3AcPksCbroWLTkPKIe97Yj6mnzNhK9TA9w5RgdBrjNyfrwUaYiYR" + "FxVJN0VrHWSsRnECAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYd" + "T3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFNOobRTPfoWP" + "EGgXVkHfwrqz7PVzMB8GA1UdIwQYMBaAFIV8JZkZ88X7MTQSsJ6/qF3KboHKMA0G" + "CSqGSIb3DQEBBQUAA4IBAQAam6vJUv6kcWWrEAfdnwwRmmJ4X1Jey3Sp48G35MOE" + "KkHtwqbtL+QU1VA2X98bEYobqZinM3e3zrlbpgbe1xoJ00MnT9CgQObXr+cum/Ql" + "PwWXB5fK3BrNwqRMRGc9w27FevyFeybdKhc47jEKMOANrB/aziNHaq9gBtU/HZdy" + "rm9TEaOHMy6vNrdpOZKpwXPxYqsQxMLpen9D64t/3P6hsV5FMQTaxSFhszidG44t" + "xaU4O0BOq4x//THCWguMxzO5RxW/V8wI/rkpvhAH1wljHTusnsAZea4PpstZ7+W7" + "43GME1DwjYdUK9HhqRNrDkiJLox4Tmegw9A7m4XLt4zu", + "C=GR, ST=\xce\x91\xcf\x84\xcf\x84\xce\xb9\xce\xba\xce\xae, " + "L=\xce\x91\xce\xb8\xce\xae\xce\xbd\xce\xb1, " + "O=\xcf\x80\xce\xb1\xcf\x81\xce\xac\xce\xb4\xce\xb5\xce\xb9\xce\xb3" + "\xce\xbc\xce\xb1, CN=www.example.com", + "2.5.4.6 2.5.4.8 2.5.4.7 2.5.4.10 2.5.4.3", + "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd", + "2.5.4.6 2.5.4.8 2.5.4.10", + "2014-07-02T18:36:10.000000Z", + "2015-07-02T18:36:10.000000Z", + "www.example.com", + "b3b9789d8a53868f418619565f6b56af0033bdd3" }, + /* The issuer and subject (except for the country code) is + * UnversalString encoded. Created with a hacked version of openssl + * using utf8=yes and string_mask=MASK:256. In order for that to + * output UniversalString encoded data you need to change the + * DIRSTRING_TYPE in crypto/asn1/asn1.h to be defined as + * B_ASN1_DIRECTORYSTRING so that UnviersalString is available to be + * used in the DirectoryStrings. OpenSSL by default avoids + * this type (for the reasonable reason that it's wasteful and + * UTF-8 can encoded everything it can in the most efficient way). + * OU uses the mathematical monospace digits 0-9 to test characters + * outside of the range of the Basic Multilingual Plane */ + { "MIIEnzCCA4egAwIBAgIBATANBgkqhkiG9w0BAQUFADCBqzELMAkGA1UEBhMCQVUx" + "MTAvBgNVBAgcKAAAAFMAAABvAAAAbQAAAGUAAAAtAAAAUwAAAHQAAABhAAAAdAAA" + "AGUxaTBnBgNVBAocYAAAAEkAAABuAAAAdAAAAGUAAAByAAAAbgAAAGUAAAB0AAAA" + "IAAAAFcAAABpAAAAZAAAAGcAAABpAAAAdAAAAHMAAAAgAAAAUAAAAHQAAAB5AAAA" + "IAAAAEwAAAB0AAAAZDAeFw0xNDA3MjIyMjM3MzBaFw0xNTA3MjIyMjM3MzBaMIH8" + "MQswCQYDVQQGEwJHUjEhMB8GA1UECBwYAAADkQAAA8QAAAPEAAADuQAAA7oAAAOu" + "MR0wGwYDVQQHHBQAAAORAAADuAAAA64AAAO9AAADsTExMC8GA1UEChwoAAADwAAA" + "A7EAAAPBAAADrAAAA7QAAAO1AAADuQAAA7MAAAO8AAADsTExMC8GA1UECxwoAAHX" + "9gAB1/cAAdf4AAHX+QAB1/oAAdf7AAHX/AAB1/0AAdf+AAHX/zFFMEMGA1UEAxw8" + "AAAAdwAAAHcAAAB3AAAALgAAAGUAAAB4AAAAYQAAAG0AAABwAAAAbAAAAGUAAAAu" + "AAAAYwAAAG8AAABtMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuYUb" + "aNt22rsR5Qc/2zsenSvrlbvv1CwwRPNxcWTKdLl4lJEUy5YCnQXIq3qTi+eAFetQ" + "MwUOZem6kgNdwmGvCz3lrLwOobd1D5mG9agzKLVUVj72csbNNFzHr8z/7oaHvYYs" + "eYxW3oRm6vDYtHw5spXrxTzRIAnG6foxXFYAtDDHQpdjsofxqXO67aUmmGvE5ffX" + "gD3dvTvjejzcjjVsLQP/HG4MQOqeIyvyyHg1E3dyOrG+3qR6RN1ZveROdvU38Udm" + "s0KSGVX2lDLsUTQSKg5L8CLWDHqgGQWjLZQRgRiKZId/f9ubaJdLN6KfAQ3UvYAP" + "bKL5/k2GpsPDE21X0QIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQf" + "Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUccHhM6C7" + "nGMpclkG7YLIRuFueYQwHwYDVR0jBBgwFoAUz0X1b2Ok9MVVzxqxX6MgtTwSKmYw" + "DQYJKoZIhvcNAQEFBQADggEBAEpqEa08JkPG+XBlLemnoJsnoaRuQnLZvSCoAwIt" + "fugTE8686EigTZyYVFQ+GaI+EqVeiMjpAEhS3IMbhx5VIr61S3Nta2BG9OPjr4Xf" + "01oUeh4egL93CpIGNwu6M1SrQv2UVAKTwahxNmNuvx6Ojx5P2tne+KJtRUiwM3dE" + "of78/0NJD27OwjW0ruZAifF5CAR7mhy3NOMARpE2kqZk5695OF+QCahe00Y/9ulz" + "sCjgjpCUYv87OTbBGC5XGRd/ZopTRqtBVxpEHX/fux5/wqxBawrCuQsVw1Kfw0Ur" + "30aYWLsOsRwhiQkukjQfcMra1AHLujWaAHuLIDls1ozc8xo=", + "C=GR, ST=\xce\x91\xcf\x84\xcf\x84\xce\xb9\xce\xba\xce\xae, " + "L=\xce\x91\xce\xb8\xce\xae\xce\xbd\xce\xb1, " + "O=\xcf\x80\xce\xb1\xcf\x81\xce\xac\xce\xb4\xce\xb5\xce\xb9\xce\xb3" + "\xce\xbc\xce\xb1, " + "OU=\xf0\x9d\x9f\xb6\xf0\x9d\x9f\xb7\xf0\x9d\x9f\xb8\xf0\x9d\x9f\xb9" + "\xf0\x9d\x9f\xba\xf0\x9d\x9f\xbb\xf0\x9d\x9f\xbc\xf0\x9d\x9f\xbd" + "\xf0\x9d\x9f\xbe\xf0\x9d\x9f\xbf, " + "CN=www.example.com", + "2.5.4.6 2.5.4.8 2.5.4.7 2.5.4.10 2.5.4.11 2.5.4.3", + "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd", + "2.5.4.6 2.5.4.8 2.5.4.10", + "2014-07-22T22:37:30.000000Z", + "2015-07-22T22:37:30.000000Z", + "www.example.com", + "cfa15310189cf89f1dadc9c989db46f287fff7a7" + }, + /* The issuer and subject (except for the country code) is BMPString + * encoded. Created with openssl using utf8-yes and string_mask=MASK:2048. + */ + { "MIID3zCCAsegAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJBVTEd" + "MBsGA1UECB4UAFMAbwBtAGUALQBTAHQAYQB0AGUxOTA3BgNVBAoeMABJAG4AdABl" + "AHIAbgBlAHQAIABXAGkAZABnAGkAdABzACAAUAB0AHkAIABMAHQAZDAeFw0xNDA3" + "MjIyMzAyMDlaFw0xNTA3MjIyMzAyMDlaMIGBMQswCQYDVQQGEwJHUjEVMBMGA1UE" + "CB4MA5EDxAPEA7kDugOuMRMwEQYDVQQHHgoDkQO4A64DvQOxMR0wGwYDVQQKHhQD" + "wAOxA8EDrAO0A7UDuQOzA7wDsTEnMCUGA1UEAx4eAHcAdwB3AC4AZQB4AGEAbQBw" + "AGwAZQAuAGMAbwBtMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqzof" + "mf9YANAl2I5AcUjfAAJhqc2BL6z6k0J9bWyDL7DZf6AJtD5stRjs8cgiSGfJt9Cg" + "YQ0Cvnwz9ztNVXLliMmiJ4V0HzG80GI6SBK0PoCVbddUV/PN7REgPNjTwMYlys5w" + "Yt/GR8OJJV+eb02rpAfVigDlh7CFjY/uKMs2ThPi+yQb2V6qxLk3ZKIHh5IbKQjt" + "zIX/W1t+hiBjojnuOmhAoEefZ583k7amR5GBZO4GS5Qfj+4kjL5xiwB3bjTC8pnV" + "Iv4+mN2F6xKW/9IOWZtdySDADaU2ioyuMDzzjp5N5Nt0ZGhrEG2cDC3CatZaV4U7" + "9yBbi6kzlo3fCbCOlQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQf" + "Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUNvwKR1v/" + "R0FQU1WnzqT3brNxaQQwHwYDVR0jBBgwFoAUSM/JbJVWuYFp+awSOEXZcKn1ddQw" + "DQYJKoZIhvcNAQEFBQADggEBABna/SiYMBJvbnI+lj7j8ddSFihaFheqtouxOB2d" + "tiVz5mcc5KsAFlkrxt7YcYB7SEc+K28nqGb3bfbZ18JayRBY3JS/h4WGu4eL5XkX" + "rceWUy60zF7DHs6p8E8HZVF1CdCC/LXr2BAdYTc/y1f37bLKVFF4mMJMP4b8/nSL" + "z8+oOO9CxaEjzRoCawf2+jaajXTSTDXBgIx1t6bJMAS6S6RKPaCketyAmpsOZVBS" + "VtBVfVIOB2zFqs6iqkXtdiOXWlZ0DBQRX0G1VD5G80RlZXs0yEfufCwLUl/TyOhM" + "WisUSEOzd4RlbsBj30JQkVG9+jXb2KChPkiMpg0tFi8HU3s=", + "C=GR, ST=\xce\x91\xcf\x84\xcf\x84\xce\xb9\xce\xba\xce\xae, " + "L=\xce\x91\xce\xb8\xce\xae\xce\xbd\xce\xb1, " + "O=\xcf\x80\xce\xb1\xcf\x81\xce\xac\xce\xb4\xce\xb5\xce\xb9\xce\xb3" + "\xce\xbc\xce\xb1, CN=www.example.com", + "2.5.4.6 2.5.4.8 2.5.4.7 2.5.4.10 2.5.4.3", + "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd", + "2.5.4.6 2.5.4.8 2.5.4.10", + "2014-07-22T23:02:09.000000Z", + "2015-07-22T23:02:09.000000Z", + "www.example.com", + "6e2cd969350979d3741b9abb66c71159a94ff971" + }, + /* The issuer and subject (except for the country code) is T61String + * (aka TeletexString) encoded. Created with openssl using utf8=yes + * and string_mask=MASK:4. Note that the example chosen specifically + * includes the Norwegian OE (slashed O) to highlight that this is + * being treated as ISO-8859-1 despite what the X.509 says. + * See the following for the horrible details on + * this encoding: https://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt + */ + { "MIIDnTCCAoWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJBVTET" + "MBEGA1UECBQKU29tZS1TdGF0ZTEhMB8GA1UEChQYSW50ZXJuZXQgV2lkZ2l0cyBQ" + "dHkgTHRkMB4XDTE0MDcyMjIzNDQxOFoXDTE1MDcyMjIzNDQxOFowYjELMAkGA1UE" + "BhMCTk8xGDAWBgNVBAgUD034cmUgb2cgUm9tc2RhbDEQMA4GA1UEBxQHxWxlc3Vu" + "ZDENMAsGA1UEChQEZPhtZTEYMBYGA1UEAxQPd3d3LmV4YW1wbGUuY29tMIIBIjAN" + "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz8uD5f2KRXvB//mKOpCXM3h/MOjK" + "xUgC4TIHi3BmnYR0IDElMPJrC263/eU0hKycyegyMjXkwIN5eEx4/Nl///RrzJBQ" + "+uXKfEJ4hTJ5x1uUYxhmtq4djZFxfjFH5yobT/LRDkEw9b/+NiRb30P+WrxhrAKW" + "7GRsE2pIdPdbM2IB5v/wORB4TK0kLYkmeEPWNJd63SmX4BEC6dRAaMxLIXKn75r5" + "GhMHKbUdt2Yy+5s0JlN9hMWqhnavCmGquzl7y/1E1OOUIm0jhL0sJn6wVTc+UO+Q" + "7u/w0xf38J8SU7lW6zbcQyYaSIQCMikgpprUSXdQZZUZGmHS7Gis39SiLwIDAQAB" + "o3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRl" + "ZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUQa2QLy+4QUH8hKNdR2LcvDKYImcwHwYD" + "VR0jBBgwFoAUpX6YP04yWqNiziUM7h0KgrRHMF4wDQYJKoZIhvcNAQEFBQADggEB" + "AElYUTQp5MOQk+ykIV0MHTw9OsEvLc1ZDmChls5WKYAu6KWgBbcjcTlkTpDlydrO" + "6JFxvCCg0K13dYOI3K/O9icGRauIrxrJOTtaIMryj7F51C52TOVPzkjL05eZTh+q" + "MmP3KI3uYSpXI6D6RI6hOKIRnFiUOQuXW3I8Z7s03KScBc9PSsVrMBLBz/Vpklaf" + "Tv/3jVBVIZwCW67SnFQ+vqEzaM4Ns2TBodlVqB1w0enPpow8bNnUwElLQJx3GXnl" + "z0JTpA6AwIRCF8n+VJgNN218fo2t2vvDDW/cZ+XMXzGNVhAqQ1F8B36esxy3P8+o" + "Bcwx241dxeGSYFHerqrTJIU=", + "C=NO, ST=M\xc3\xb8re og Romsdal, L=\xc3\x85lesund, O=d\xc3\xb8me, " + "CN=www.example.com", + "2.5.4.6 2.5.4.8 2.5.4.7 2.5.4.10 2.5.4.3", + "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd", + "2.5.4.6 2.5.4.8 2.5.4.10", + "2014-07-22T23:44:18.000000Z", + "2015-07-22T23:44:18.000000Z", + "www.example.com", + "787d1577ae77b79649d8f99cf4ed58a332dc48da" + }, + /* Certificate with several Subject Alt Name dNSNames. Note that + * the CommonName is not duplicated in the Subject Alt Name to + * test that the Common Name is excluded when Subject Alt Name + * exists. */ + { "MIIEMTCCAxmgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJBVTET" + "MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ" + "dHkgTHRkMRwwGgYDVQQDExNJbnRlcm5ldCBXaWRnaXRzIENBMB4XDTE0MDcyNTE3" + "NDEwNFoXDTE1MDcyNTE3NDEwNFowdDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh" + "c2hpbmd0b24xEzARBgNVBAcTCk5vcnRoIEJlbmQxITAfBgNVBAoTGEludGVybmV0" + "IFdpZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPd3d3LmV4YW1wbGUuY29tMIIBIjAN" + "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxlryoK6hMhGI/UlHi7v1m+Z3tCvg" + "ZG1twDFNvBACpFVbJtC/v+fiy1eG7ooZ1PsdCINQ1iXLh1igevlw/4w6iTDpeSZg" + "OCPYqK6ejnS0bKtSB4TuP8yiQtqwaVz4yPP88lXuQJDRJzgaAR0VAhooLgEpl1z1" + "n9wQO15AW5swzpKcEOi4n6Zmf1t7oxOt9awAOhkL1FfFwkpbiK9yQv3TPVo+xzbx" + "BJxwx55RY8Dpiu0kuiTYWsd02pocb0uIqd7a5B4y05PhJseqwyX0Mw57HBBnbru1" + "lCetP4PkoM2gf7Uoj9e61nmM1mustKTIPvh7tZHWW3UW9JxAFG+6FkKDewIDAQAB" + "o4HeMIHbMAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJh" + "dGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBQ4A9k8VwI0wv7u5rB4+1D9cuHiqTAf" + "BgNVHSMEGDAWgBS6O+MdRDDrD715AXdrnuNZ7wDSyjALBgNVHQ8EBAMCBeAwUwYD" + "VR0RBEwwSoINKi5leGFtcGxlLmNvbYIRKi5mb28uZXhhbXBsZS5jb22CESouYmFy" + "LmV4YW1wbGUuY29tghN6aWctemFnLmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBBQUA" + "A4IBAQAf4IrSOL741IUkyFQrDdof39Cp87VdNEo4Bl8fUSuCjqZONxJfiAFx7GcB" + "Cd7h7Toe6CYCeQLHSEXQ1S1eWYLIq0ZoP3Q/huJdoH7yskDyC5Faexph0obKM5hj" + "+EYGW2W/UYBzEZai+eePBovARDlupiMaTJGvtdU/AcgMhXCoGNK6egesXoiNgfFh" + "h+lXUNWUWm2gZlKwRJff8tkR7bIG7MGzyL6Rqav2/tQdbFVXN5AFPdYPFLf0Vo5m" + "eGYM87TILfSo7n7Kh0aZovwcuF/vPUWRJl3B1HaPt9k6DhcFyAji0SJyZWyM4v88" + "GSq5Dk8dnTdL2otToll+r4IqFLlp", + "C=US, ST=Washington, L=North Bend, O=Internet Widgits Pty Ltd, " + "CN=www.example.com", + "2.5.4.6 2.5.4.8 2.5.4.7 2.5.4.10 2.5.4.3", + "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=Internet Widgits CA", + "2.5.4.6 2.5.4.8 2.5.4.10 2.5.4.3", + "2014-07-25T17:41:04.000000Z", + "2015-07-25T17:41:04.000000Z", + "*.example.com, *.foo.example.com, *.bar.example.com, zig-zag.example.com", + "9c365d27b7b6cc438576a8e465685ea7a4f61129" + }, + /* This is a CA cert that has a Common Name that doesn't look like + * a hostname. Make sure that the hostnames field remains blank for it. */ + { "MIIEEjCCAvqgAwIBAgIJAKJarRWbvbCjMA0GCSqGSIb3DQEBBQUAMGMxCzAJBgNV" + "BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX" + "aWRnaXRzIFB0eSBMdGQxHDAaBgNVBAMTE0ludGVybmV0IFdpZGdpdHMgQ0EwHhcN" + "MTQwNzI1MTc0MTAzWhcNMjQwNzIyMTc0MTAzWjBjMQswCQYDVQQGEwJBVTETMBEG" + "A1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkg" + "THRkMRwwGgYDVQQDExNJbnRlcm5ldCBXaWRnaXRzIENBMIIBIjANBgkqhkiG9w0B" + "AQEFAAOCAQ8AMIIBCgKCAQEAv0f0TAiE13WHaFv8j6M9uuniO40+Aj8cuhZtJ1GC" + "GI/mW56wq2BJrP6N4+jyxYbZ/13S3ypPu+N087Nc/4xaPtUD/eKqMlU+o8gHM/Lf" + "BEs2dUuBsvkNM0KoC04NPNTOYDnfHOrzx8iHhqlDedwmP8FeQn3rNS8k4qDyJpG3" + "Ay8ICz5mB07Cy6NISohTxMtatfW5yKmhnhiS92X42QAEgI1pGB7jJl1g3u+KY1Bf" + "/10kcramYSYIM1uB7XHQjZI4bhEhQwuIWePMOSCOykdmbemM3ijF9f531Olq+0Nz" + "t7lA1b/aW4PGGJsZ6uIIjKMaX4npP+HHUaNGVssgTnTehQIDAQABo4HIMIHFMB0G" + "A1UdDgQWBBS6O+MdRDDrD715AXdrnuNZ7wDSyjCBlQYDVR0jBIGNMIGKgBS6O+Md" + "RDDrD715AXdrnuNZ7wDSyqFnpGUwYzELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNv" + "bWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEcMBoG" + "A1UEAxMTSW50ZXJuZXQgV2lkZ2l0cyBDQYIJAKJarRWbvbCjMAwGA1UdEwQFMAMB" + "Af8wDQYJKoZIhvcNAQEFBQADggEBAI442H8CpePFvOtdvcosu2N8juJrzACuayDI" + "Ze32EtHFN611azduqkWBgMJ3Fv74o0A7u5Gl8A7RZnfBTMX7cvpfHvWefau0xqgm" + "Mn8CcTUGel0qudCCMe+kPppmkgNaZFvawSqcAA/u2yni2yx8BakYYDZzyfmEf9dm" + "hZi5SmxFFba5UhNKOye0GKctT13s/7EgfFNyVhZA7hWU26Xm88QnGnN/qxJdpq+e" + "+Glctn9tyke4b1VZ2Yr+R4OktrId44ZQcRD44+88v5ThP8DQsvkXcjREMFAIPkvG" + "CEDOIem4l9KFfnsHn8/4KvoBRkmCkGaSwOwUdUG+jIjBpY/82kM=", + "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=Internet Widgits CA", + "2.5.4.6 2.5.4.8 2.5.4.10 2.5.4.3", + "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=Internet Widgits CA", + "2.5.4.6 2.5.4.8 2.5.4.10 2.5.4.3", + "2014-07-25T17:41:03.000000Z", + "2024-07-22T17:41:03.000000Z", + NULL, + "b9decce236aa1da07b2bf088160bffe1469b9a4a" + }, + /* Cert with a IP SAN entry. Make sure we properly skip them. */ + { "MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJBVTET" + "MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ" + "dHkgTHRkMRwwGgYDVQQDExNJbnRlcm5ldCBXaWRnaXRzIENBMB4XDTE0MDcyNTE4" + "NDMyOFoXDTE1MDcyNTE4NDMyOFowczELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh" + "c2hpbmd0b24xEzARBgNVBAcTCk5vcnRoIEJlbmQxITAfBgNVBAoTGEludGVybmV0" + "IFdpZGdpdHMgUHR5IEx0ZDEXMBUGA1UEAxMOaXAuZXhhbXBsZS5jb20wggEiMA0G" + "CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDXKkSxg89tu5/n+lIC8ajj1T9vsO5B" + "nRH5Sne7UPc6pGMTNFi1MOVjdDWkmuCUzoI+HKLDc69/4V5RU12N1QNgsgcOzCSo" + "qgxa+dQk2s1shz1zhyaHkpdeMZU3/p9D4v+nRGAdYifwl/VOTwjWWucNzHDBwvb6" + "+Wm4pXE94Y5p8fY/lZi7VgtxdoPdSHGkIAps8psZGPjqKpLEjnLMp1n0v9cZhBF6" + "OoMUZpQuwcjT8vMQppgIWhZFLiH2jn7FTYWZyB0Dh9nMd097NQA87VtVfNc+g0oY" + "qLe3YldJgvVfyeSLhnyv68fBfGcTj310pNrGeE/m4tyxupiUT8BitfxPAgMBAAGj" + "geQwgeEwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0" + "ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFI09JZlhKV44Z+I5d58V/ZDqQ7yZMB8G" + "A1UdIwQYMBaAFDjQVnIU9pQI1nM8jjmxYiicMTdGMAsGA1UdDwQEAwIF4DBZBgNV" + "HREEUjBQgg0qLmV4YW1wbGUuY29tghEqLmZvby5leGFtcGxlLmNvbYcEfwAAAYIR" + "Ki5iYXIuZXhhbXBsZS5jb22CE3ppZy16YWcuZXhhbXBsZS5jb20wDQYJKoZIhvcN" + "AQEFBQADggEBAEK+XIGwavf+5Ht44ifHrGog0CDr4ESg7wFjzk+BJwYDtIPp9b8A" + "EG8qbfmOS+2trG3zc74baf2rmrfn0YGZ/GV826NMTaf7YU1/tJQTo+RX9g3aHg6f" + "pUBfIyAV8ELq84sgwd1PIgleVgIiDrz+a0UZ05Z5S+GbR2pwNH6+fO0O5E9clt2a" + "Cute1UMBqAMGKiFaP8HD6SUFTdTKZNxHtQzYmmuvoC1nzVatMFdkTuQgSQ/uNlzg" + "+yUFoufMZhs3gPx9PfXGOQ7f3nKE+WCK4KNGv+OILYsk4zUjMznfAwBRs9PyITN2" + "BKe64WsF6ZxTq3zLVGy5I8LpbtlvSmAaBp4=", + "C=US, ST=Washington, L=North Bend, O=Internet Widgits Pty Ltd, " + "CN=ip.example.com", + "2.5.4.6 2.5.4.8 2.5.4.7 2.5.4.10 2.5.4.3", + "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=Internet Widgits CA", + "2.5.4.6 2.5.4.8 2.5.4.10 2.5.4.3", + "2014-07-25T18:43:28.000000Z", + "2015-07-25T18:43:28.000000Z", + "*.example.com, *.foo.example.com, *.bar.example.com, zig-zag.example.com", + "3525fb617c232fdc738d736c1cbd5d97b19b51e4" + }, + /* Cert with the signature algorithm OID set to sha1WithRSA instead of + * sha1WithRSAEncryption. Both have the same meaning but the sha1WithRSA + * doesn't seem to be used anymore and is shorter */ + { "MIIDgDCCAmygAwIBAgIBATAJBgUrDgMCHQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYD" + "VQQIFApTb21lLVN0YXRlMSEwHwYDVQQKFBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBM" + "dGQwHhcNMTQwODE4MDk1OTQ1WhcNMTUwODE4MDk1OTQ1WjBNMQswCQYDVQQGEwJV" + "SzEQMA4GA1UECBQHRW5nbGFuZDESMBAGA1UEBxQJU2hlZmZpZWxkMRgwFgYDVQQD" + "FA93d3cuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB" + "AQCkvtieKg33RSzhn5JMDPPRlDS8Q16CN96A4lLI9YrJCy33z46PrbR2mq2hOz5l" + "MdgbAaRF0MUGhcKv4msJ0bsWhkybaSBAVgnoC7ObQWPNF7ppMzUjeDAlUBXNfheR" + "ZcgcgGWqUkoB1uUMhvmVuPrzvxn+WCwyoP6zQCviYLsR8AygGQgdhV6c9wJ/x9HS" + "MRUvUOeo7SCmx9GK5Hc11QV2K3rwKXABeAxXNzbyQe7hFfQYCI2SB5s3bEnhIvg7" + "BG0BQmoprHjXWBftc0+msKQTFw7+jZ21NsfwGoPonuVsCOJjJ51jp2oKqk3b1GGc" + "DEmmMQ0JtqfHO5a7JACBaHbTAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4" + "QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBSo" + "jICtcIgZL6OCCB5BJ5PGf1UIyTAfBgNVHSMEGDAWgBT5KQMLMylrXSQvhMtONHZc" + "22Jm9TAJBgUrDgMCHQUAA4IBAQCvCJ4i2kRzSRhnlDxd0UbQtytVIJFFJlfREPTM" + "j8+VqqtCVyPSX8T5NU+HCiEmhVrTlm/W0i8ygJXr8izyIMGRqbyhn2M9b8hAY6Jl" + "0edztu/FV/YHsJbPznWkXWpMMaXDEX4wI329f5odccIbB5VSaaoAdKZ6Ne4nf6oV" + "95KRFWkXoYjm24TnpALsNnK1Kjjed6h5ApB+IANOpXYFbGcsfbuKhWbFd2nd6t5U" + "NpUcv4H9Tgdl6KgrfsbQtAeouWCgoiNzrul8FOaQTdJLZfCsjuE+IkGpM+DX8PiF" + "5M41EqkSKia8sChFIln+lkRY41OWP9uQ1VXCfdRIzOnXWh9U", + "C=UK, ST=England, L=Sheffield, CN=www.example.com", + "2.5.4.6 2.5.4.8 2.5.4.7 2.5.4.3", + "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd", + "2.5.4.6 2.5.4.8 2.5.4.10", + "2014-08-18T09:59:45.000000Z", + "2015-08-18T09:59:45.000000Z", + "www.example.com", + "0e0869961d508b13bb22aa8da675b2e9951c0e70" + }, + /* X.509 v1 certificate, we used to crash on these prior to r1619861. */ + { "MIIDDTCCAfUCAQEwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQVUxEzARBgNV" + "BAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0" + "ZDAeFw0xNTAxMTkyMjEyNDhaFw0xNjAxMTkyMjEyNDhaMFQxCzAJBgNVBAYTAlVT" + "MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRMwEQYDVQQHEwpOb3J0aCBCZW5kMRswGQYD" + "VQQDExJ4NTA5djEuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw" + "ggEKAoIBAQDniW3DmGGtA0MoYqE9H55/RmjtTJD2WVmM/STEsw+RW74UGsZ62qfi" + "ADedl4ukZYKlk3TwJrGEwDBKOMWHuzCYVxhclyHkHwX7QqamvZRgaOonEu82KHuE" + "dZo4FhOWDC9D0yS4RFbfqvSu/JG19FYsnRQn1RPFYji6jG9TRwavplVBiMhR68kc" + "8HTW1Wu7uJ5SV0UtTicFes8MGek3+zWceGt+Egwd2UlIYXwTPzB5m7UPuufEdvFL" + "ED3pusVatohFzjCbYsuJIR5ppYd49uTxPWGvRidJ2C8GbDf9PCgDduS0Gz91Txnw" + "h+WiVYCQ6SxAJWp/xeZWE71k88N0vJEzAgMBAAEwDQYJKoZIhvcNAQEFBQADggEB" + "ABoBaObsHnIrkd3RvvGb5q7fnEfiT1DXsufS3ypf4Z8IST/z+NeaUaiRN1oLcvDz" + "qC7ygTYZ2BZoEw3ReCGqQWT4iYET+lH8DM+U5val3gVlSWqx1jj/wiV1OAxQsakM" + "BnmNs/MDshiv54irvSlqnxEp2o/BU/vMrN656C5DJkZpYoMpIWxdFnd+bzNzuN1k" + "pJfTjzWlGckKfdblNPOfdtccTqtQ5d4mWtYNJ8DfL5rRRwCuzXvZtbVHKxqkXaXr" + "CYUfFUobapgPfvvMc1QcDY+2nvhC2ij+HAPIHgZPuzJsjZRC1zwg074cfgjZbgbm" + "R0HVF486p3vS8HFv4lndRZA=", + "C=US, ST=Washington, L=North Bend, CN=x509v1.example.com", + "2.5.4.6 2.5.4.8 2.5.4.7 2.5.4.3", + "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd", + "2.5.4.6 2.5.4.8 2.5.4.10", + "2015-01-19T22:12:48.000000Z", + "2016-01-19T22:12:48.000000Z", + "x509v1.example.com", + "5730dd65a7f77fdf0dfd90e5a53119f38854af29" + }, + /* X.509 v1 certificate with an X.509 v3 Subject Alternative Name + * extension. Although these are ill-formed per RFC 5280 s. 4.1, we + * suspect that they could exist in the real world. Make sure we do + * not error out, and that we pick up SAN (b.example.com) from the + * extension. */ + { "MIIDLzCCAhcCAQ8wDQYJKoZIhvcNAQEFBQAwKzEpMCcGA1UEAwwgSW50ZXJuZXQg" + "V2lkZ2l0cyBJbnRlcm1lZGlhdGUgQ0EwHhcNMTUwMTI5MDAzMzU1WhcNMTYwMTI5" + "MDAzMzU1WjByMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjETMBEG" + "A1UEBwwKTm9ydGggQmVuZDEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkg" + "THRkMRYwFAYDVQQDDA1hLmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC" + "AQ8AMIIBCgKCAQEAs0hj2xPRQZpecqk0Ih1l4juAuQZeSgv3yD/VtSq/9sTBH6iA" + "4XjJQcHROYxYaK0QS/qlCjpl+Q3mOaVIu+59TLy3T2YVgqMYmgB453ntuJPkdF1C" + "fJ2j19YAQZHHdOFaP1G+auBwjmHns3+MkG4s7EPuJP7TBCcSFlOmz5D4GUui3NVG" + "LBYUog1ZhF4oe/7d4jc2Cn8uypNT/Hc1ViIlCT4rFoAirv9Uob+4zjQ3Z18I1Ql1" + "t8oszVCj3kKDboEty2RduwPLx/2ztWYBCvFhd49JGdi/nzMi+j2d5HCI3V8W06pN" + "mvrVU4G0ImVRa8wpmQCSm2Tp0s42FAVHWw8yMwIDAQABoxwwGjAYBgNVHREEETAP" + "gg1iLmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBBQUAA4IBAQDI/n0NYakuRP/485/A" + "dan71qBy3sljjOreq71IfBdtq+GEjCL1B0TD0V338LXki9NicCLeD/MWfceDjV0u" + "AjPTxaZEn/NWqXo0mpNC535Y6G46mIHYDGC8JyvCJjaXF+GVstNt6lXzZp2Yn3Si" + "K57uVb+zz5zAGSO982I2HACZPnF/oAtp7bwxzwvBsLqSLw3hh0ATVPp6ktE+WMoI" + "X75CVcDmU0zjXqzKiFPKeTVjQG6YxgvplMaag/iNngkgEhX4PIrxdIEsHf8l9ogC" + "dz51MFxetsC4D2KRq8IblF9i+9r3hlv+Dbf9ovYe9Hu0usloSinImoWOw42iWWmP" + "vT4l", + "C=US, ST=Washington, L=North Bend, O=Internet Widgits Pty Ltd, " + "CN=a.example.com", + "2.5.4.6 2.5.4.8 2.5.4.7 2.5.4.10 2.5.4.3", + "CN=Internet Widgits Intermediate CA", + "2.5.4.3", + "2015-01-29T00:33:55.000000Z", + "2016-01-29T00:33:55.000000Z", + "b.example.com", + "47fa5c76fee6e21e37def6da3746bba84a5a09bf" + }, + /* X.509 certificate with multiple Relative Distinguished Names + * Borrowed form the Chromium test suite see thier bug here + * https://code.google.com/p/chromium/issues/detail?id=101009 + */ + { "MIICsDCCAhmgAwIBAgIJAO9sL1fZ/VoPMA0GCSqGSIb3DQEBBQUAMHExbzAJBgNV" + "BAYTAlVTMA8GA1UECgwIQ2hyb21pdW0wFgYKCZImiZPyLGQBGRYIQ2hyb21pdW0w" + "GgYDVQQDDBNNdWx0aXZhbHVlIFJETiBUZXN0MB0GA1UECwwWQ2hyb21pdW0gbmV0" + "X3VuaXR0ZXN0czAeFw0xMTEyMDIwMzQ3MzlaFw0xMjAxMDEwMzQ3MzlaMHExbzAJ" + "BgNVBAYTAlVTMA8GA1UECgwIQ2hyb21pdW0wFgYKCZImiZPyLGQBGRYIQ2hyb21p" + "dW0wGgYDVQQDDBNNdWx0aXZhbHVlIFJETiBUZXN0MB0GA1UECwwWQ2hyb21pdW0g" + "bmV0X3VuaXR0ZXN0czCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAnSMQ7YeC" + "sOuk+0n128F7TfDtG/X48sG10oTe65SC8N6LBLfo7YYiQZlWVHEzjsFpaiv0dx4k" + "cIFbVghXAky/r5qgM1XiAGuzzFw7R27cBTC9DPlRwHArP3CiEKO3iz8i+qu9x0il" + "/9N70LcSSAu/kGLxikDbHRoM9d2SKhy2LGsCAwEAAaNQME4wHQYDVR0OBBYEFI1e" + "cfoqc7qfjmMyHF2rh9CrR6u3MB8GA1UdIwQYMBaAFI1ecfoqc7qfjmMyHF2rh9Cr" + "R6u3MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAGKwN01A47nxVHOkw" + "wFdbT8t9FFkY3pIg5meoqO3aATNaSEzkZoUljWtWgWfzr+n4ElwZBxeYv9cPurVk" + "a+wXygzWzsOzCUMKBI/aS8ijRervyvh6LpGojPGn1HttnXNLmhy+BLECs7cq6f0Z" + "hvImrEWhD5uZGlOxaZk+bFEjQHA=", + "C=US, O=Chromium, 0.9.2342.19200300.100.1.25=Chromium, " + "CN=Multivalue RDN Test, OU=Chromium net_unittests", + "2.5.4.6 2.5.4.10 0.9.2342.19200300.100.1.25 2.5.4.3 2.5.4.11", + "C=US, O=Chromium, 0.9.2342.19200300.100.1.25=Chromium, " + "CN=Multivalue RDN Test, OU=Chromium net_unittests", + "2.5.4.6 2.5.4.10 0.9.2342.19200300.100.1.25 2.5.4.3 2.5.4.11", + "2011-12-02T03:47:39.000000Z", + "2012-01-01T03:47:39.000000Z", + NULL, + "99302ca2824f585a117bb41302a388daa0519765" + }, + /* certificate with subject that includes an attribute that has an + * object id that has leading zeros. This isn't technically legal + * but a simplistic parser might parser it the same as an object + * id that doesn't have a leading zero. In this case the object id + * with a leading zero could parse to the same object id as the + * Common Name. Make sure we don't treat it as such. */ + { "MIIDDjCCAfYCAQEwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQVUxEzARBgNV" + "BAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0" + "ZDAeFw0xNTAxMjcwNzQ5MDhaFw0xNjAxMjcwNzQ5MDhaMFUxCzAJBgNVBAYTAlVT" + "MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRMwEQYDVQQHEwpOb3J0aCBCZW5kMRwwGgYE" + "VQSAAxMSbm90YWNuLmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A" + "MIIBCgKCAQEAvXCJv0gr9d3GNYiukPrbse0FdXmuBx2mPf665WyZVHk9JiPnDcb2" + "ng8gHLgJe8izou6I0vN2iJgy91rUPvX9zA3qVhml+cboVY2jHCPWo/v5PQsXAgLV" + "5gVjp2POn3N0O1xcS1yNe249LkP0Di3kAMp5gkzdprm3fD3JDW1Q+ocQylnbjzG0" + "FtNQSUJLITvPXjR7ny46Fci2mv8scHOvlEXTK5/2RoBaoK2jWQimqGfFj1sr1vqZ" + "Wcb6NAdZso64Xg1V6CWX8zymlA7gAhTQWveq+ovUWcXpmR8aj9pYNuy0aZW3BANz" + "N6L0G7OZiVUvvzpfnn0V3Z/sR/iQs7q3nQIDAQABMA0GCSqGSIb3DQEBBQUAA4IB" + "AQACZwruCiesCRkT08AtHl0WQnQui58e9/7En+iqxNQO6+fx84SfWGcUFYZtvzdO" + "KkHNTs06km+471OjLSDcotRkdqO1JxQCkNxbrPat7T6FrO9n2JFivx6eijRqK/jB" + "cBYW92dK4BfXU4+FyeB2OIpyPjuqLU2j7S5p7qNU50i/1J7Qt669nXeaPINIfZdW" + "sDjjWkFR1VOgXS/zeu/GOxlQFmmcde+X/qkFI+L352VX7Ktf95j4ms4vG2yZgNfe" + "jbNb9a7LMcqlop/PlX5WBGv8GGKUNZO0LvukFYOULf1oL8VQsN0x/gRHGC7m9kVM" + "3hojWZDXAY4mYqdBCRX7/gkt", + "C=US, ST=Washington, L=North Bend, 2.5.4.03=notacn.example.com", + "2.5.4.6 2.5.4.8 2.5.4.7 2.5.4.03", + "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd", + "2.5.4.6 2.5.4.8 2.5.4.10", + "2015-01-27T07:49:08.000000Z", + "2016-01-27T07:49:08.000000Z", + NULL, + "6f24b834ba00fb4ef863df63b8fbeddab25e4838" + }, + /* certificate with subject that includes an attribute that has an + * object id that has an overflow such that it calculates to + * the same object id as the Common Name (2.5.4.3). OpenSSL + * with its bignum support shows this as 2.5.4.2361183241434822606851. + * It would be wrong to display this as a Common Name to the user. */ + { "MIIDGTCCAgECAQEwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQVUxEzARBgNV" + "BAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0" + "ZDAeFw0xNTAxMjcwODMxNDNaFw0xNjAxMjcwODMxNDNaMGAxCzAJBgNVBAYTAlVT" + "MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRMwEQYDVQQHEwpOb3J0aCBCZW5kMScwJQYN" + "VQSCgICAgICAgICAAxMUb3ZlcmZsb3cuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3" + "DQEBAQUAA4IBDwAwggEKAoIBAQDHL1e8zSPyRND3tI42Vqca2FoCiWn881Czv2ct" + "tGFwyjUM8R1yHXEP+doS9KN9L29xRWZRxyCQ18S+QbjNQCh6Ay22qnkBu0uPdVB6" + "iIVKiW9RzU8dZSFMnveUZYLloG12kK++ooJGIstTJwkI8Naw1X1D29gZaY9oSKAc" + "Gs5c92po61RoetB744dUfUbAXi8eEd4ShdsdnCoswpEI4WTLdYLZ/cH/sU1a5Djm" + "cAfEBzZSOseEQSG7Fa/HvHyW+jDNnKG2r73M45TDcXAunSFcAYl1ioBaRwwdcTbK" + "SMGORThIX5UwpJDZI5sTVmTTRuCjbMxXXki/g9fTYD6mlaavAgMBAAEwDQYJKoZI" + "hvcNAQEFBQADggEBABvZSzFniMK4lqJcubzzk410NqZQEDBxdNZTNGrQYIDV8fDU" + "LLoQ2/2Y6kOQbx8r3RNcaJ6JtJeVqAq05It9oR5lMJFA2r0YMl4eB2V6o35+eaKY" + "FXrJzwx0rki2mX+iKsgRbJTv6mFb4I7vny404WKHNgYIfB8Z5jgbwWgrXH9M6BMb" + "FL9gZHMmU+6uqvCPYeIIZaAjT4J4E9322gpcumI9KGVApmbQhi5lC1hBh+eUprG7" + "4Brl9GeCLSTnTTf4GHIpqaUsKMtJ1sN/KJGwEB7Z4aszr80P5/sjHXOyqJ78tx46" + "pwH7/Fx0pM7nZjJVGvcxGBBOMeKy/o2QUVvEYPU=", + "C=US, ST=Washington, L=North Bend, \?\?=overflow.example.com", + "2.5.4.6 2.5.4.8 2.5.4.7 \?\?", + "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd", + "2.5.4.6 2.5.4.8 2.5.4.10", + "2015-01-27T08:31:43.000000Z", + "2016-01-27T08:31:43.000000Z", + NULL, + "c1f063daf23e402fe58bab1a3fa2ba05c1106158" + }, + /* certificate with multiple common names, make sure this behaves + * the same way as serf. */ + { "MIIDJjCCAg4CAQEwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQVUxEzARBgNV" + "BAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0" + "ZDAeFw0xNTAxMjExNzUwMDZaFw0xNjAxMjExNzUwMDZaMG0xCzAJBgNVBAYTAlVT" + "MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRMwEQYDVQQHEwpOb3J0aCBCZW5kMRkwFwYD" + "VQQDExBnb29kLmV4YW1wbGUuY29tMRkwFwYDVQQDExBldmlsLmV4YW1wbGUuY29t" + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5pfrXkiiDGCWSYhMQNHJ" + "gNBLEBNcFzsGpW8i6rMKVephwG7p4VqIvc0pSsmpD9IYuIxxq/2E2cziaTWyqCBp" + "hKKipqt8eMcu6u45LduHGiCcnN7rHORbQZTdvwzTmiVN1eI1oCVejB4zgHNkHUko" + "DyaALCHGRz8l7Qq6hSbiOnhH1qlscIIEsgQEyDlMZpbsWVTQKPxluhtgqVEn7wPN" + "qScrf2evq050NuNYYFzCmuqOGKq2gKbD/BlUqCNmEM2JPg/bdcAQxFCf0HcvDiS9" + "e29suMKWZAzJkbzrWhlDMG1Xt5c7dd82PcGwnL//Q7muE57luCw38Gp2vQQ3/Uki" + "vQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQBry9wfxYia/dCSKvDXOBKUgWFQtI8j" + "7vYHuouTvIb5m6b62kiUdtuaVKi3jnUbHUFohOi/6o+HIwbXSgz5CbiLjgUvONBU" + "BLekaguIYX9tTmg+vhWchcmVMHufj6HdQkzWtyojSQD9GjHGInNDG102KlN1cdL8" + "jGTrru4vnef+xA24EvYPdcS2+H2yYH0THL3JPKo1GtO4NCEGWQbS6Ygwcy+BQpbU" + "TBIWhlbleuCalB8qhWyijcHeszT7mFR0CarEaSLeZj6FaQpZB636iHuELmxcgiFw" + "j3r3QZyAMEGvPPBPKYSTgmol31pX9LYvuFGA9ADQ2in/n9WdMfYzFzOn", + "C=US, ST=Washington, L=North Bend, " + "CN=good.example.com, CN=evil.example.com", + "2.5.4.6 2.5.4.8 2.5.4.7 2.5.4.3 2.5.4.3", + "C=AU, ST=Some-State, O=Internet Widgits Pty Ltd", + "2.5.4.6 2.5.4.8 2.5.4.10", + "2015-01-21T17:50:06.000000Z", + "2016-01-21T17:50:06.000000Z", + "good.example.com", + "9693f17e59205f41ca2e14450d151b945651b2d7" + }, + { NULL } +}; + +static svn_error_t * +compare_dates(const char *expected, + apr_time_t actual, + const char *type, + const char *subject, + apr_pool_t *pool) +{ + apr_time_t expected_tm; + + if (!actual) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "No %s for cert '%s'", type, subject); + + SVN_ERR(svn_time_from_cstring(&expected_tm, expected, pool)); + if (!expected_tm) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "Problem converting expected %s '%s' to text " + "output for cert '%s'", type, expected, + subject); + + if (expected_tm != actual) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "The %s didn't match expected '%s'," + " got '%s' for cert '%s'", + type, expected, + svn_time_to_cstring(actual, pool), + subject); + + return SVN_NO_ERROR; +} + +static svn_error_t * +compare_hostnames(const char *expected, + const apr_array_header_t *actual, + const char *subject, + apr_pool_t *pool) +{ + + int i; + svn_stringbuf_t *buf; + + if (!actual) + { + if (expected) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "The hostnames didn't match expected '%s'," + " got NULL for cert '%s'", + expected, subject); + return SVN_NO_ERROR; + } + + buf = svn_stringbuf_create_empty(pool); + for (i = 0; i < actual->nelts; ++i) + { + const char *hostname = APR_ARRAY_IDX(actual, i, const char*); + if (i > 0) + svn_stringbuf_appendbytes(buf, ", ", 2); + svn_stringbuf_appendbytes(buf, hostname, strlen(hostname)); + } + + if (strcmp(expected, buf->data)) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "The hostnames didn't match expected '%s'," + " got '%s' for cert '%s'", + expected, buf->data, subject); + return SVN_NO_ERROR; +} + +static svn_error_t * +compare_oids(const char *expected, + const apr_array_header_t *actual, + const char *subject, + apr_pool_t *pool) +{ + int i; + svn_stringbuf_t *buf; + + if (!actual) + { + if (expected) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "The oids didn't match expected '%s'," + " got NULL for cert '%s'", + expected, subject); + return SVN_NO_ERROR; + } + + buf = svn_stringbuf_create_empty(pool); + for (i = 0; i < actual->nelts; ++i) + { + apr_size_t len; + const svn_x509_name_attr_t *attr = APR_ARRAY_IDX(actual, i, const svn_x509_name_attr_t *); + const void *oid = svn_x509_name_attr_get_oid(attr, &len); + const char *oid_string = svn_x509_oid_to_string(oid, len, pool, pool); + if (i > 0) + svn_stringbuf_appendbyte(buf, ' '); + if (oid_string) + svn_stringbuf_appendcstr(buf, oid_string); + else + svn_stringbuf_appendcstr(buf, "??"); + } + + if (strcmp(expected, buf->data)) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "The oids didn't match expected '%s'," + " got '%s' for cert '%s'", + expected, buf->data, subject); + return SVN_NO_ERROR; + +} + + +static svn_error_t * +compare_results(struct x509_test *xt, + svn_x509_certinfo_t *certinfo, + apr_pool_t *pool) +{ + const char *v; + + v = svn_x509_certinfo_get_subject(certinfo, pool); + if (!v) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "No subject for cert '%s'", xt->subject); + if (strcmp(v, xt->subject)) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "Subject didn't match for cert '%s', " + "expected '%s', got '%s'", xt->subject, + xt->subject, v); + + SVN_ERR(compare_oids(xt->subject_oids, svn_x509_certinfo_get_subject_attrs(certinfo), + xt->subject, pool)); + + v = svn_x509_certinfo_get_issuer(certinfo, pool); + if (!v) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "No issuer for cert '%s'", xt->subject); + if (strcmp(v, xt->issuer)) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "Issuer didn't match for cert '%s', " + "expected '%s', got '%s'", xt->subject, + xt->issuer, v); + + SVN_ERR(compare_oids(xt->issuer_oids, svn_x509_certinfo_get_issuer_attrs(certinfo), + xt->subject, pool)); + + SVN_ERR(compare_dates(xt->valid_from, + svn_x509_certinfo_get_valid_from(certinfo), + "valid-from", + xt->subject, + pool)); + + SVN_ERR(compare_dates(xt->valid_to, + svn_x509_certinfo_get_valid_to(certinfo), + "valid-to", + xt->subject, + pool)); + + SVN_ERR(compare_hostnames(xt->hostnames, + svn_x509_certinfo_get_hostnames(certinfo), + xt->subject, + pool)); + + v = svn_checksum_to_cstring_display( + svn_x509_certinfo_get_digest(certinfo), pool); + if (!v) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "No SHA1 digest for cert '%s'", xt->subject); + if (strcmp(v, xt->sha1_digest)) + return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, + "SHA1 digest didn't match for cert '%s', " + "expected '%s', got '%s'", xt->subject, + xt->sha1_digest, v); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_x509_parse_cert(apr_pool_t *pool) +{ + struct x509_test *xt; + apr_pool_t *iterpool = svn_pool_create(pool); + + for (xt = cert_tests; xt->base64_cert; xt++) + { + const svn_string_t *der_cert; + svn_x509_certinfo_t *certinfo; + + svn_pool_clear(iterpool); + + /* Convert header-less PEM to DER by undoing base64 encoding. */ + der_cert = svn_base64_decode_string(svn_string_create(xt->base64_cert, + pool), + iterpool); + + SVN_ERR(svn_x509_parse_cert(&certinfo, der_cert->data, der_cert->len, + iterpool, iterpool)); + + SVN_ERR(compare_results(xt, certinfo, iterpool)); + } + + return SVN_NO_ERROR; +} + +#if 0 +static struct x509_test broken_cert_tests[] = { + { NULL } +}; + +static svn_error_t * +test_x509_parse_cert_broken(apr_pool_t *pool) +{ + struct x509_test *xt; + apr_pool_t *iterpool = svn_pool_create(pool); + + for (xt = broken_cert_tests; xt->base64_cert; xt++) + { + const svn_string_t *der_cert; + svn_x509_certinfo_t *certinfo; + + svn_pool_clear(iterpool); + + /* Convert header-less PEM to DER by undoing base64 encoding. */ + der_cert = svn_base64_decode_string(svn_string_create(xt->base64_cert, + pool), + iterpool); + + SVN_ERR(svn_x509_parse_cert(&certinfo, der_cert->data, der_cert->len, + iterpool, iterpool)); + + SVN_ERR(compare_results(xt, certinfo, iterpool)); + } + + return SVN_NO_ERROR; +} +#endif + +/* The test table. */ + +static int max_threads = 1; + +static struct svn_test_descriptor_t test_funcs[] = + { + SVN_TEST_NULL, + SVN_TEST_PASS2(test_x509_parse_cert, + "test svn_x509_parse_cert"), +/* SVN_TEST_XFAIL2(test_x509_parse_cert_broken, + "test broken certs"), */ + SVN_TEST_NULL + }; + +SVN_TEST_MAIN |