@@ -119,6 +119,114 @@ def test_same_as_binascii_crc32(self):
119
119
self .assertEqual (binascii .crc32 (b'spam' ), zlib .crc32 (b'spam' ))
120
120
121
121
122
+ class ChecksumCombineMixin :
123
+ """Mixin class for testing checksum combination."""
124
+
125
+ N = 1000
126
+ default_iv : int
127
+
128
+ def parse_iv (self , iv ):
129
+ """Parse an IV value.
130
+
131
+ - The default IV is returned if *iv* is None.
132
+ - A random IV is returned if *iv* is -1.
133
+ - Otherwise, *iv* is returned as is.
134
+ """
135
+ if iv is None :
136
+ return self .default_iv
137
+ if iv == - 1 :
138
+ return random .randint (1 , 0x80000000 )
139
+ return iv
140
+
141
+ def checksum (self , data , init = None ):
142
+ """Compute the checksum of data with a given initial value.
143
+
144
+ The *init* value is parsed by ``parse_iv``.
145
+ """
146
+ iv = self .parse_iv (init )
147
+ return self ._checksum (data , iv )
148
+
149
+ def _checksum (self , data , init ):
150
+ raise NotImplementedError
151
+
152
+ def combine (self , a , b , blen ):
153
+ """Combine two checksums together."""
154
+ raise NotImplementedError
155
+
156
+ def get_random_data (self , data_len , * , iv = None ):
157
+ """Get a triplet (data, iv, checksum)."""
158
+ data = random .randbytes (data_len )
159
+ init = self .parse_iv (iv )
160
+ checksum = self .checksum (data , init )
161
+ return data , init , checksum
162
+
163
+ def test_combine_empty (self ):
164
+ for _ in range (self .N ):
165
+ a , iv , checksum = self .get_random_data (32 , iv = - 1 )
166
+ res = self .combine (iv , self .checksum (a ), len (a ))
167
+ self .assertEqual (res , checksum )
168
+
169
+ def test_combine_no_iv (self ):
170
+ for _ in range (self .N ):
171
+ a , _ , chk_a = self .get_random_data (32 )
172
+ b , _ , chk_b = self .get_random_data (64 )
173
+ res = self .combine (chk_a , chk_b , len (b ))
174
+ self .assertEqual (res , self .checksum (a + b ))
175
+
176
+ def test_combine_no_iv_invalid_length (self ):
177
+ a , _ , chk_a = self .get_random_data (32 )
178
+ b , _ , chk_b = self .get_random_data (64 )
179
+ checksum = self .checksum (a + b )
180
+ for invalid_len in [1 , len (a ), 48 , len (b ) + 1 , 191 ]:
181
+ invalid_res = self .combine (chk_a , chk_b , invalid_len )
182
+ self .assertNotEqual (invalid_res , checksum )
183
+
184
+ self .assertRaises (TypeError , self .combine , 0 , 0 , "len" )
185
+
186
+ def test_combine_with_iv (self ):
187
+ for _ in range (self .N ):
188
+ a , iv_a , chk_a_with_iv = self .get_random_data (32 , iv = - 1 )
189
+ chk_a_no_iv = self .checksum (a )
190
+ b , iv_b , chk_b_with_iv = self .get_random_data (64 , iv = - 1 )
191
+ chk_b_no_iv = self .checksum (b )
192
+
193
+ # We can represent c = COMBINE(CHK(a, iv_a), CHK(b, iv_b)) as:
194
+ #
195
+ # c = CHK(CHK(b'', iv_a) + CHK(a) + CHK(b'', iv_b) + CHK(b))
196
+ # = COMBINE(
197
+ # COMBINE(CHK(b'', iv_a), CHK(a)),
198
+ # COMBINE(CHK(b'', iv_b), CHK(b)),
199
+ # )
200
+ # = COMBINE(COMBINE(iv_a, CHK(a)), COMBINE(iv_b, CHK(b)))
201
+ tmp0 = self .combine (iv_a , chk_a_no_iv , len (a ))
202
+ tmp1 = self .combine (iv_b , chk_b_no_iv , len (b ))
203
+ expected = self .combine (tmp0 , tmp1 , len (b ))
204
+ checksum = self .combine (chk_a_with_iv , chk_b_with_iv , len (b ))
205
+ self .assertEqual (checksum , expected )
206
+
207
+
208
+ class CRC32CombineTestCase (ChecksumCombineMixin , unittest .TestCase ):
209
+
210
+ default_iv = 0
211
+
212
+ def _checksum (self , data , init ):
213
+ return zlib .crc32 (data , init )
214
+
215
+ def combine (self , a , b , blen ):
216
+ return zlib .crc32_combine (a , b , blen )
217
+
218
+
219
+ class Adler32CombineTestCase (ChecksumCombineMixin , unittest .TestCase ):
220
+
221
+ default_iv = 1
222
+
223
+ def _checksum (self , data , init ):
224
+ return zlib .adler32 (data , init )
225
+
226
+ def combine (self , a , b , blen ):
227
+ return zlib .adler32_combine (a , b , blen )
228
+
229
+
122
230
# Issue #10276 - check that inputs >=4 GiB are handled correctly.
123
231
class ChecksumBigBufferTestCase (unittest .TestCase ):
124
232
0 commit comments