#include "unity/unity.h" #include "zlib.h" #include #include #include /* Independent naive Adler-32 for expected values. Does per-byte modulo with BASE = 65521. */ static uLong adler32_naive(uLong adler, const Bytef *buf, size_t len) { const unsigned long BASE = 65521UL; unsigned long sum1 = adler & 0xFFFFUL; unsigned long sum2 = (adler >> 16) & 0xFFFFUL; for (size_t i = 0; i < len; i++) { sum1 += buf[i]; if (sum1 >= BASE) sum1 -= BASE; /* one subtraction is sufficient */ sum2 += sum1; if (sum2 >= BASE) sum2 -= BASE; /* one subtraction is sufficient */ } return (uLong)(sum1 | (sum2 << 16)); } void setUp(void) { /* Setup code here, or leave empty */ } void tearDown(void) { /* Cleanup code here, or leave empty */ } /* buf == Z_NULL should return 1 regardless of adler or len (as long as len != 1). */ void test_adler32_z_null_buf_len_nonzero_returns_one(void) { uLong start = 0xDEADBEEFul; uLong got = adler32_z(start, Z_NULL, (z_size_t)100); TEST_ASSERT_EQUAL_HEX32(1UL, got); } void test_adler32_z_null_buf_len_zero_returns_one(void) { uLong start = 0x12345678ul; uLong got = adler32_z(start, Z_NULL, (z_size_t)0); TEST_ASSERT_EQUAL_HEX32(1UL, got); } /* len == 1 fast path: simple single byte from initial adler 1. */ void test_adler32_z_single_byte_from_initial(void) { const unsigned char b = 'A'; /* 65 */ uLong got = adler32_z(1UL, (const Bytef *)&b, (z_size_t)1); uLong exp = adler32_naive(1UL, (const Bytef *)&b, 1); TEST_ASSERT_EQUAL_HEX32(exp, got); /* expected 0x00420042 */ } /* len == 1 fast path with wrap of sum1 (start sum1 near BASE). */ void test_adler32_z_single_byte_wrap_sum1(void) { /* Start with sum1 = 65520, sum2 = 0 */ uLong start = ((uLong)0 << 16) | 65520UL; const unsigned char b = 10; /* pushes sum1 over BASE */ uLong got = adler32_z(start, (const Bytef *)&b, (z_size_t)1); uLong exp = adler32_naive(start, (const Bytef *)&b, 1); TEST_ASSERT_EQUAL_HEX32(exp, got); } /* len < 16 path: small string */ void test_adler32_z_small_string_lt_16(void) { const char *msg = "Hello, world!"; /* 13 bytes */ size_t len = strlen(msg); uLong got = adler32_z(1UL, (const Bytef *)msg, (z_size_t)len); uLong exp = adler32_naive(1UL, (const Bytef *)msg, len); TEST_ASSERT_EQUAL_HEX32(exp, got); } /* len < 16 with wrap scenario: start sum1 near BASE to force a wrap */ void test_adler32_z_small_len_wrap_sum1(void) { unsigned char data[4] = {10, 20, 30, 40}; /* Start with sum1 = 65520, sum2 = 1234 (arbitrary) */ uLong start = ((uLong)1234 << 16) | 65520UL; uLong got = adler32_z(start, (const Bytef *)data, (z_size_t)sizeof(data)); uLong exp = adler32_naive(start, (const Bytef *)data, sizeof(data)); TEST_ASSERT_EQUAL_HEX32(exp, got); } /* len == 0 with non-null buf should normalize start sums: check 0xFFFFFFFF -> 0x000E000E */ void test_adler32_z_len_zero_normalizes_state(void) { uLong start = 0xFFFFFFFFUL; /* sum1 = 65535, sum2 = 65535 */ unsigned char dummy = 0; uLong got = adler32_z(start, (const Bytef *)&dummy, (z_size_t)0); /* Expect normalization: sum1 = 65535 - 65521 = 14, sum2 = 65535 % 65521 = 14 */ uLong exp = ((uLong)14 << 16) | 14; TEST_ASSERT_EQUAL_HEX32(exp, got); } /* len >= NMAX path: pick length > 5552 to trigger block processing */ void test_adler32_z_large_len_over_NMAX(void) { const size_t len = 6000; /* > NMAX (5552) */ unsigned char *buf = (unsigned char *)malloc(len); TEST_ASSERT_NOT_NULL(buf); for (size_t i = 0; i < len; i++) { buf[i] = (unsigned char)(i % 251); } uLong start = 1UL; uLong got = adler32_z(start, (const Bytef *)buf, (z_size_t)len); uLong exp = adler32_naive(start, (const Bytef *)buf, len); free(buf); TEST_ASSERT_EQUAL_HEX32(exp, got); } /* Multiple full blocks plus remainder: 2*NMAX + 123 (with NMAX = 5552) */ void test_adler32_z_multiple_blocks_plus_remainder(void) { const size_t NMAX_VAL = 5552; const size_t len = NMAX_VAL * 2 + 123; unsigned char *buf = (unsigned char *)malloc(len); TEST_ASSERT_NOT_NULL(buf); for (size_t i = 0; i < len; i++) { buf[i] = (unsigned char)(i % 13); } uLong start = ((uLong)0x1357 << 16) | 0x2468; /* arbitrary non-initial start */ uLong got = adler32_z(start, (const Bytef *)buf, (z_size_t)len); uLong exp = adler32_naive(start, (const Bytef *)buf, len); free(buf); TEST_ASSERT_EQUAL_HEX32(exp, got); } int main(void) { UNITY_BEGIN(); RUN_TEST(test_adler32_z_null_buf_len_nonzero_returns_one); RUN_TEST(test_adler32_z_null_buf_len_zero_returns_one); RUN_TEST(test_adler32_z_single_byte_from_initial); RUN_TEST(test_adler32_z_single_byte_wrap_sum1); RUN_TEST(test_adler32_z_small_string_lt_16); RUN_TEST(test_adler32_z_small_len_wrap_sum1); RUN_TEST(test_adler32_z_len_zero_normalizes_state); RUN_TEST(test_adler32_z_large_len_over_NMAX); RUN_TEST(test_adler32_z_multiple_blocks_plus_remainder); return UNITY_END(); }