File size: 4,335 Bytes
e996a55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "unity/unity.h"
#include "zlib.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

/*
  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();
}