#include "unity/unity.h" #include "zlib.h" #include #include #include /* Reference CRC32 implementation (IEEE 802.3, reflected, poly 0xEDB88320), independent of zlib internals. This matches zlib's crc32 with initial crc=0. */ static uint32_t ref_crc32(const unsigned char *buf, size_t len) { uint32_t crc = 0xFFFFFFFFu; for (size_t i = 0; i < len; i++) { crc ^= buf[i]; for (int k = 0; k < 8; k++) { uint32_t mask = -(crc & 1u); crc = (crc >> 1) ^ (0xEDB88320u & mask); } } return crc ^ 0xFFFFFFFFu; } /* Deterministic pseudo-random filler */ static void fill_buffer(unsigned char *buf, size_t len, uint32_t seed) { uint32_t x = seed ? seed : 1u; for (size_t i = 0; i < len; i++) { x = 1664525u * x + 1013904223u; /* LCG */ buf[i] = (unsigned char)(x >> 24); } } void setUp(void) { /* no-op */ } void tearDown(void) { /* no-op */ } /* Sanity check with a standard test vector. */ void test_local_void_braid_z_crc_t_ltl_256_z_word_t_big_256_int_n_int_w_known_vector(void) { const unsigned char msg[] = "123456789"; /* length 9 */ uint32_t expected = 0xCBF43926u; /* standard CRC-32 of "123456789" */ /* Force table initialization if dynamic. */ (void)get_crc_table(); uLong got = crc32(0L, msg, (uInt)sizeof(msg) - 1); TEST_ASSERT_EQUAL_HEX32(expected, (uint32_t)got); } /* Large aligned buffer to exercise braided path. */ void test_local_void_braid_z_crc_t_ltl_256_z_word_t_big_256_int_n_int_w_large_aligned_buffer(void) { const size_t len = 1u << 20; /* 1 MiB, ample to trigger braided path */ unsigned char *buf = (unsigned char *)malloc(len + 16); /* extra for potential alignment tests */ TEST_ASSERT_NOT_NULL(buf); fill_buffer(buf, len, 0x12345678u); /* Reference */ uint32_t ref = ref_crc32(buf, len); /* zlib */ (void)get_crc_table(); uLong got = crc32(0L, buf, (uInt)len); TEST_ASSERT_EQUAL_HEX32(ref, (uint32_t)got); free(buf); } /* Large misaligned buffer offsets to ensure pre-alignment + braided processing works. */ void test_local_void_braid_z_crc_t_ltl_256_z_word_t_big_256_int_n_int_w_large_misaligned_offsets(void) { const size_t len = (1u << 20) + 7; /* slightly over 1 MiB to vary alignments */ unsigned char *base = (unsigned char *)malloc(len + 16); TEST_ASSERT_NOT_NULL(base); fill_buffer(base, len + 8, 0xCAFEBABEu); for (size_t off = 0; off < 4; off++) { /* test a few misalignments */ const unsigned char *buf = base + off; size_t sublen = len - off; uint32_t ref = ref_crc32(buf, sublen); (void)get_crc_table(); uLong got = crc32(0L, buf, (uInt)sublen); TEST_ASSERT_EQUAL_HEX32(ref, (uint32_t)got); } free(base); } /* Incremental processing should equal single-pass CRC (also exercises braided internals on large data). */ void test_local_void_braid_z_crc_t_ltl_256_z_word_t_big_256_int_n_int_w_incremental_equals_single_pass(void) { const size_t len = (1u << 20) + 123; /* non-round size */ unsigned char *buf = (unsigned char *)malloc(len); TEST_ASSERT_NOT_NULL(buf); fill_buffer(buf, len, 0xA5A5A5A5u); /* Single pass reference (independent) */ uint32_t ref = ref_crc32(buf, len); /* zlib single pass */ (void)get_crc_table(); uLong z_single = crc32(0L, buf, (uInt)len); /* zlib incremental: split in arbitrary chunks */ size_t cut1 = len / 3; size_t cut2 = (2 * len) / 3; uLong z_inc = crc32(0L, buf, (uInt)cut1); z_inc = crc32(z_inc, buf + cut1, (uInt)(cut2 - cut1)); z_inc = crc32(z_inc, buf + cut2, (uInt)(len - cut2)); TEST_ASSERT_EQUAL_HEX32(ref, (uint32_t)z_single); TEST_ASSERT_EQUAL_HEX32((uint32_t)z_single, (uint32_t)z_inc); free(buf); } int main(void) { UNITY_BEGIN(); RUN_TEST(test_local_void_braid_z_crc_t_ltl_256_z_word_t_big_256_int_n_int_w_known_vector); RUN_TEST(test_local_void_braid_z_crc_t_ltl_256_z_word_t_big_256_int_n_int_w_large_aligned_buffer); RUN_TEST(test_local_void_braid_z_crc_t_ltl_256_z_word_t_big_256_int_n_int_w_large_misaligned_offsets); RUN_TEST(test_local_void_braid_z_crc_t_ltl_256_z_word_t_big_256_int_n_int_w_incremental_equals_single_pass); return UNITY_END(); }