| #include "unity/unity.h" |
| #include "zlib.h" |
|
|
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdio.h> |
|
|
| |
| |
| |
| static int g_fail_alloc_enabled = 0; |
| static size_t g_fail_alloc_size = 0; |
|
|
| static voidpf test_zalloc(voidpf opaque, uInt items, uInt size) { |
| (void)opaque; |
| size_t bytes = (size_t)items * (size_t)size; |
| if (g_fail_alloc_enabled && bytes == g_fail_alloc_size) { |
| return NULL; |
| } |
| return calloc(items, size); |
| } |
|
|
| static void test_zfree(voidpf opaque, voidpf address) { |
| (void)opaque; |
| free(address); |
| } |
|
|
| |
| |
| |
| static int deflate_with_input(z_stream *strm, const unsigned char *in, uInt in_len, |
| int flush, unsigned char **outbuf, size_t *outlen) { |
| *outbuf = NULL; |
| *outlen = 0; |
|
|
| |
| uLong bound = deflateBound(strm, (uLong)in_len); |
| size_t cap = (size_t)bound + 64; |
| unsigned char *buf = (unsigned char *)malloc(cap); |
| if (!buf) return Z_MEM_ERROR; |
|
|
| size_t produced_start = (size_t)strm->total_out; |
|
|
| strm->next_in = (Bytef *)in; |
| strm->avail_in = in_len; |
| strm->next_out = buf; |
| strm->avail_out = (uInt)cap; |
|
|
| int ret; |
| for (;;) { |
| ret = deflate(strm, flush); |
| if (ret == Z_STREAM_ERROR) { |
| free(buf); |
| return ret; |
| } |
| if (strm->avail_in == 0 && (flush != Z_FINISH || ret == Z_STREAM_END)) { |
| break; |
| } |
| if (strm->avail_out == 0) { |
| |
| size_t used = (size_t)(strm->total_out - produced_start); |
| size_t new_cap = cap * 2 + 1024; |
| unsigned char *new_buf = (unsigned char *)realloc(buf, new_cap); |
| if (!new_buf) { |
| free(buf); |
| return Z_MEM_ERROR; |
| } |
| buf = new_buf; |
| cap = new_cap; |
| strm->next_out = buf + used; |
| |
| strm->avail_out = (uInt)(cap - used); |
| } |
| } |
|
|
| size_t produced = (size_t)(strm->total_out - produced_start); |
| unsigned char *final_buf = (unsigned char *)realloc(buf, produced ? produced : 1); |
| if (!final_buf && produced) { |
| free(buf); |
| return Z_MEM_ERROR; |
| } |
| *outbuf = final_buf ? final_buf : buf; |
| *outlen = produced; |
| return ret; |
| } |
|
|
| |
| static unsigned char *gen_repeated(const char *pat, size_t total, size_t *out_len) { |
| size_t pat_len = strlen(pat); |
| if (pat_len == 0) pat_len = 1; |
| unsigned char *buf = (unsigned char *)malloc(total ? total : 1); |
| if (!buf) return NULL; |
| for (size_t i = 0; i < total; ++i) { |
| buf[i] = (unsigned char)pat[i % pat_len]; |
| } |
| if (out_len) *out_len = total; |
| return buf; |
| } |
|
|
| void setUp(void) { |
| |
| g_fail_alloc_enabled = 0; |
| g_fail_alloc_size = 0; |
| } |
|
|
| void tearDown(void) { |
| |
| } |
|
|
| |
| void test_deflateCopy_null_dest(void) { |
| z_stream src; |
| memset(&src, 0, sizeof(src)); |
| TEST_ASSERT_EQUAL_INT(Z_OK, deflateInit(&src, Z_DEFAULT_COMPRESSION)); |
|
|
| int ret = deflateCopy(NULL, &src); |
| TEST_ASSERT_EQUAL_INT(Z_STREAM_ERROR, ret); |
|
|
| TEST_ASSERT_EQUAL_INT(Z_OK, deflateEnd(&src)); |
| } |
|
|
| |
| void test_deflateCopy_null_source(void) { |
| z_stream dest; |
| memset(&dest, 0, sizeof(dest)); |
| int ret = deflateCopy(&dest, NULL); |
| TEST_ASSERT_EQUAL_INT(Z_STREAM_ERROR, ret); |
| } |
|
|
| |
| void test_deflateCopy_uninitialized_source(void) { |
| z_stream src, dest; |
| memset(&src, 0, sizeof(src)); |
| memset(&dest, 0, sizeof(dest)); |
| int ret = deflateCopy(&dest, &src); |
| TEST_ASSERT_EQUAL_INT(Z_STREAM_ERROR, ret); |
| } |
|
|
| |
| void test_deflateCopy_success_equal_outputs(void) { |
| |
| size_t len1, len2; |
| unsigned char *data1 = gen_repeated("The quick brown fox jumps over the lazy dog\n", 4096, &len1); |
| unsigned char *data2 = gen_repeated("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 4096, &len2); |
| TEST_ASSERT_NOT_NULL(data1); |
| TEST_ASSERT_NOT_NULL(data2); |
|
|
| z_stream src; |
| memset(&src, 0, sizeof(src)); |
| TEST_ASSERT_EQUAL_INT(Z_OK, deflateInit(&src, 6)); |
|
|
| |
| unsigned char *out1 = NULL; size_t out1_len = 0; |
| int ret = deflate_with_input(&src, data1, (uInt)len1, Z_SYNC_FLUSH, &out1, &out1_len); |
| TEST_ASSERT(ret == Z_OK || ret == Z_BUF_ERROR); |
|
|
| unsigned pending = 0; int bits = 0; |
| TEST_ASSERT_EQUAL_INT(Z_OK, deflatePending(&src, &pending, &bits)); |
| TEST_ASSERT_EQUAL_UINT(0u, pending); |
|
|
| |
| z_stream dst; |
| |
| memset(&dst, 0, sizeof(dst)); |
| TEST_ASSERT_EQUAL_INT(Z_OK, deflateCopy(&dst, &src)); |
|
|
| |
| unsigned char *out2_src = NULL, *out2_dst = NULL; |
| size_t out2_src_len = 0, out2_dst_len = 0; |
|
|
| int ret_src = deflate_with_input(&src, data2, (uInt)len2, Z_FINISH, &out2_src, &out2_src_len); |
| int ret_dst = deflate_with_input(&dst, data2, (uInt)len2, Z_FINISH, &out2_dst, &out2_dst_len); |
|
|
| TEST_ASSERT_EQUAL_INT(Z_STREAM_END, ret_src); |
| TEST_ASSERT_EQUAL_INT(Z_STREAM_END, ret_dst); |
| TEST_ASSERT_EQUAL_size_t(out2_src_len, out2_dst_len); |
| TEST_ASSERT_EQUAL_INT(0, memcmp(out2_src, out2_dst, out2_src_len)); |
|
|
| |
| TEST_ASSERT_EQUAL_INT(Z_OK, deflateEnd(&src)); |
| TEST_ASSERT_EQUAL_INT(Z_OK, deflateEnd(&dst)); |
|
|
| free(data1); |
| free(data2); |
| free(out1); |
| free(out2_src); |
| free(out2_dst); |
| } |
|
|
| |
| |
| |
| void test_deflateCopy_alloc_failure_on_state(void) { |
| |
| z_stream src; |
| memset(&src, 0, sizeof(src)); |
| src.zalloc = test_zalloc; |
| src.zfree = test_zfree; |
|
|
| TEST_ASSERT_EQUAL_INT(Z_OK, deflateInit(&src, Z_DEFAULT_COMPRESSION)); |
|
|
| |
| g_fail_alloc_enabled = 1; |
| g_fail_alloc_size = sizeof(struct internal_state); |
|
|
| z_stream dest; |
| memset(&dest, 0, sizeof(dest)); |
|
|
| int ret = deflateCopy(&dest, &src); |
| TEST_ASSERT_EQUAL_INT(Z_MEM_ERROR, ret); |
|
|
| |
| const char *msg = "hello world"; |
| unsigned char *out = NULL; size_t out_len = 0; |
| int r2 = deflate_with_input(&src, (const unsigned char *)msg, (uInt)strlen(msg), Z_FINISH, &out, &out_len); |
| TEST_ASSERT_EQUAL_INT(Z_STREAM_END, r2); |
|
|
| TEST_ASSERT_EQUAL_INT(Z_OK, deflateEnd(&src)); |
| free(out); |
|
|
| |
| g_fail_alloc_enabled = 0; |
| g_fail_alloc_size = 0; |
| } |
|
|
| int main(void) { |
| UNITY_BEGIN(); |
| RUN_TEST(test_deflateCopy_null_dest); |
| RUN_TEST(test_deflateCopy_null_source); |
| RUN_TEST(test_deflateCopy_uninitialized_source); |
| RUN_TEST(test_deflateCopy_success_equal_outputs); |
| RUN_TEST(test_deflateCopy_alloc_failure_on_state); |
| return UNITY_END(); |
| } |