blob: 164e4bf51b83d3b8a88b0b00c7944d7cee6738ee [file] [log] [blame]
/*
* checksum-test.c: tests checksum 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 <apr_pools.h>
#include <zlib.h>
#include "svn_error.h"
#include "svn_io.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 *
checksum_parse_kind(const char *digest,
svn_checksum_kind_t kind,
const char *name,
apr_pool_t *pool)
{
const char *checksum_display;
svn_checksum_t *checksum;
SVN_ERR(svn_checksum_parse_hex(&checksum, kind, digest, pool));
checksum_display = svn_checksum_to_cstring_display(checksum, pool);
if (strcmp(checksum_display, digest) != 0)
return svn_error_createf
(SVN_ERR_CHECKSUM_MISMATCH, NULL,
"verify-checksum: %s checksum mismatch:\n"
" expected: %s\n"
" actual: %s\n", name, digest, checksum_display);
return SVN_NO_ERROR;
}
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;
}
static svn_error_t *
test_checksum_empty(apr_pool_t *pool)
{
svn_checksum_kind_t kind;
for (kind = svn_checksum_md5; kind <= svn_checksum_fnv1a_32x4; ++kind)
{
svn_checksum_t *checksum;
char data = '\0';
checksum = svn_checksum_empty_checksum(kind, 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 *
zero_match_kind(svn_checksum_kind_t kind, apr_pool_t *pool)
{
svn_checksum_t *zero;
svn_checksum_t *A;
svn_checksum_t *B;
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));
/* Different non-zero don't match. */
SVN_TEST_ASSERT(!svn_checksum_match(A, B));
/* Zero matches anything of the same kind. */
SVN_TEST_ASSERT(svn_checksum_match(A, zero));
SVN_TEST_ASSERT(svn_checksum_match(zero, B));
return SVN_NO_ERROR;
}
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_cross_match(apr_pool_t *pool)
{
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;
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));
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;
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));
/* 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));
/* ...even another zero. */
SVN_TEST_ASSERT(!svn_checksum_match(i_zero, k_zero));
}
}
return SVN_NO_ERROR;
}
static svn_error_t *
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;
uInt sz;
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;
/* Try to decompress the same data with different blocksizes */
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 */);
stream.avail_in = sz;
stream.next_in = src_buffer;
stream.avail_out = sizeof(dst_buffer);
stream.next_out = dst_buffer;
do
{
int zr = inflate(&stream, Z_NO_FLUSH);
if (zr != Z_OK && zr != Z_STREAM_END)
{
return svn_error_createf(
SVN_ERR_TEST_FAILED, NULL,
"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 = (uInt) (deflated->len - stream.total_in);
{
int zr = inflate(&stream, Z_NO_FLUSH);
if (zr != Z_STREAM_END)
{
return svn_error_createf(
SVN_ERR_TEST_FAILED, NULL,
"Final flush failed with blocksize %u", sz);
}
crc = crc32(crc, dst_buffer, sizeof(dst_buffer) - stream.avail_out);
zr = inflateEnd(&stream);
if (zr != Z_OK)
{
return svn_error_createf(
SVN_ERR_TEST_FAILED, NULL,
"End of stream handling failed with blocksize %u",
sz);
}
}
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;
}
static svn_error_t *
test_checksum_parse_all_zero(apr_pool_t *pool)
{
svn_checksum_kind_t kind;
for (kind = svn_checksum_md5; kind <= svn_checksum_fnv1a_32x4; ++kind)
{
svn_checksum_t *checksum;
const char *hex;
checksum = svn_checksum_create(kind, pool);
hex = svn_checksum_to_cstring_display(checksum, pool);
SVN_ERR(svn_checksum_parse_hex(&checksum, kind, hex, pool));
/* All zeroes checksum is NULL by definition. See
svn_checksum_parse_hex().*/
SVN_TEST_ASSERT(checksum == NULL);
}
return SVN_NO_ERROR;
}
static svn_error_t *
test_checksummed_stream_read(apr_pool_t *pool)
{
const svn_string_t *str = svn_string_create("abcde", pool);
svn_checksum_kind_t kind;
for (kind = svn_checksum_md5; kind <= svn_checksum_fnv1a_32x4; ++kind)
{
svn_stream_t *stream;
svn_checksum_t *expected_checksum;
svn_checksum_t *actual_checksum;
char buf[64];
apr_size_t len;
stream = svn_stream_from_string(str, pool);
stream = svn_stream_checksummed2(stream, &actual_checksum, NULL,
kind, TRUE, pool);
len = str->len;
SVN_ERR(svn_stream_read_full(stream, buf, &len));
SVN_TEST_INT_ASSERT((int) len, str->len);
SVN_ERR(svn_stream_close(stream));
SVN_ERR(svn_checksum(&expected_checksum, kind,
str->data, str->len, pool));
SVN_TEST_ASSERT(svn_checksum_match(expected_checksum, actual_checksum));
}
return SVN_NO_ERROR;
}
static svn_error_t *
test_checksummed_stream_reset(apr_pool_t *pool)
{
const svn_string_t *str = svn_string_create("abcde", pool);
svn_checksum_kind_t kind;
for (kind = svn_checksum_md5; kind <= svn_checksum_fnv1a_32x4; ++kind)
{
svn_stream_t *stream;
svn_checksum_t *expected_checksum;
svn_checksum_t *actual_checksum;
char buf[64];
apr_size_t len;
stream = svn_stream_from_string(str, pool);
stream = svn_stream_checksummed2(stream, &actual_checksum, NULL,
kind, TRUE, pool);
len = str->len;
SVN_ERR(svn_stream_read_full(stream, buf, &len));
SVN_TEST_INT_ASSERT((int) len, str->len);
SVN_ERR(svn_stream_reset(stream));
len = str->len;
SVN_ERR(svn_stream_read_full(stream, buf, &len));
SVN_TEST_INT_ASSERT((int) len, str->len);
SVN_ERR(svn_stream_close(stream));
SVN_ERR(svn_checksum(&expected_checksum, kind,
str->data, str->len, pool));
SVN_TEST_ASSERT(svn_checksum_match(expected_checksum, actual_checksum));
}
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_checksum_parse,
"checksum parse"),
SVN_TEST_PASS2(test_checksum_empty,
"checksum emptiness"),
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_PASS2(test_checksum_parse_all_zero,
"checksum parse all zero"),
SVN_TEST_PASS2(test_checksummed_stream_read,
"read from checksummed stream"),
SVN_TEST_PASS2(test_checksummed_stream_reset,
"reset checksummed stream"),
SVN_TEST_NULL
};
SVN_TEST_MAIN