11import unittest
22from test import support
33from test .support import import_helper
4+ from test .support .hypothesis_helper import hypothesis
45import binascii
56import copy
67import pickle
@@ -182,20 +183,18 @@ def test_same_as_binascii_crc32(self):
182183class ChecksumCombineMixin :
183184 """Mixin class for testing checksum combination."""
184185
185- N = 1000
186186 default_iv : int
187+ # Initial values that are valid checksums for the algorithm.
188+ iv_strategy : object
187189
188190 def parse_iv (self , iv ):
189191 """Parse an IV value.
190192
191193 - The default IV is returned if *iv* is None.
192- - A random IV is returned if *iv* is -1.
193194 - Otherwise, *iv* is returned as is.
194195 """
195196 if iv is None :
196197 return self .default_iv
197- if iv == - 1 :
198- return random .randint (1 , 0x80000000 )
199198 return iv
200199
201200 def checksum (self , data , init = None ):
@@ -220,18 +219,24 @@ def get_random_data(self, data_len, *, iv=None):
220219 checksum = self .checksum (data , init )
221220 return data , init , checksum
222221
223- def test_combine_empty (self ):
224- for _ in range (self .N ):
225- a , iv , checksum = self .get_random_data (32 , iv = - 1 )
226- res = self .combine (iv , self .checksum (a ), len (a ))
227- self .assertEqual (res , checksum )
228-
229- def test_combine_no_iv (self ):
230- for _ in range (self .N ):
231- a , _ , chk_a = self .get_random_data (32 )
232- b , _ , chk_b = self .get_random_data (64 )
233- res = self .combine (chk_a , chk_b , len (b ))
234- self .assertEqual (res , self .checksum (a + b ))
222+ @hypothesis .given (a = hypothesis .strategies .binary (max_size = 256 ),
223+ iv = hypothesis .strategies .runner ().flatmap (
224+ lambda self : self .iv_strategy ))
225+ @hypothesis .example (a = b'' , iv = 0 )
226+ @hypothesis .example (a = b'\x00 ' * 32 , iv = 1 )
227+ @hypothesis .example (a = bytes (range (256 )), iv = 0x7fffffff )
228+ def test_combine_empty (self , a , iv ):
229+ res = self .combine (iv , self .checksum (a ), len (a ))
230+ self .assertEqual (res , self .checksum (a , iv ))
231+
232+ @hypothesis .given (a = hypothesis .strategies .binary (max_size = 256 ),
233+ b = hypothesis .strategies .binary (max_size = 256 ))
234+ @hypothesis .example (a = b'' , b = b'' )
235+ @hypothesis .example (a = b'\x00 ' * 32 , b = b'\xff ' * 64 )
236+ @hypothesis .example (a = bytes (range (256 )), b = bytes (range (255 , - 1 , - 1 )))
237+ def test_combine_no_iv (self , a , b ):
238+ res = self .combine (self .checksum (a ), self .checksum (b ), len (b ))
239+ self .assertEqual (res , self .checksum (a + b ))
235240
236241 def test_combine_no_iv_invalid_length (self ):
237242 a , _ , chk_a = self .get_random_data (32 )
@@ -246,31 +251,48 @@ def test_combine_no_iv_invalid_length(self):
246251 self .assertRaises (OverflowError , self .combine , 0 , 0 , 2 ** 1000 )
247252 self .assertRaises (OverflowError , self .combine , 0 , 0 , - 2 ** 1000 )
248253
249- def test_combine_with_iv (self ):
250- for _ in range (self .N ):
251- a , iv_a , chk_a_with_iv = self .get_random_data (32 , iv = - 1 )
252- chk_a_no_iv = self .checksum (a )
253- b , iv_b , chk_b_with_iv = self .get_random_data (64 , iv = - 1 )
254- chk_b_no_iv = self .checksum (b )
255-
256- # We can represent c = COMBINE(CHK(a, iv_a), CHK(b, iv_b)) as:
257- #
258- # c = CHK(CHK(b'', iv_a) + CHK(a) + CHK(b'', iv_b) + CHK(b))
259- # = COMBINE(
260- # COMBINE(CHK(b'', iv_a), CHK(a)),
261- # COMBINE(CHK(b'', iv_b), CHK(b)),
262- # )
263- # = COMBINE(COMBINE(iv_a, CHK(a)), COMBINE(iv_b, CHK(b)))
264- tmp0 = self .combine (iv_a , chk_a_no_iv , len (a ))
265- tmp1 = self .combine (iv_b , chk_b_no_iv , len (b ))
266- expected = self .combine (tmp0 , tmp1 , len (b ))
267- checksum = self .combine (chk_a_with_iv , chk_b_with_iv , len (b ))
268- self .assertEqual (checksum , expected )
254+ @hypothesis .given (a = hypothesis .strategies .binary (max_size = 256 ),
255+ b = hypothesis .strategies .binary (max_size = 256 ),
256+ iv_a = hypothesis .strategies .runner ().flatmap (
257+ lambda self : self .iv_strategy ),
258+ iv_b = hypothesis .strategies .runner ().flatmap (
259+ lambda self : self .iv_strategy ))
260+ @hypothesis .example (a = b'' , b = b'' , iv_a = 0 , iv_b = 0 )
261+ @hypothesis .example (a = b'\x00 ' * 32 , b = b'\xff ' * 64 , iv_a = 1 ,
262+ iv_b = 0x7fffffff )
263+ @hypothesis .example (a = bytes (range (256 )), b = bytes (range (255 , - 1 , - 1 )),
264+ iv_a = 0x12345678 , iv_b = 0x0badf00d )
265+ def test_combine_with_iv (self , a , b , iv_a , iv_b ):
266+ chk_a_with_iv = self .checksum (a , iv_a )
267+ chk_a_no_iv = self .checksum (a )
268+ chk_b_with_iv = self .checksum (b , iv_b )
269+ chk_b_no_iv = self .checksum (b )
270+
271+ # We can represent c = COMBINE(CHK(a, iv_a), CHK(b, iv_b)) as:
272+ #
273+ # c = CHK(CHK(b'', iv_a) + CHK(a) + CHK(b'', iv_b) + CHK(b))
274+ # = COMBINE(
275+ # COMBINE(CHK(b'', iv_a), CHK(a)),
276+ # COMBINE(CHK(b'', iv_b), CHK(b)),
277+ # )
278+ # = COMBINE(COMBINE(iv_a, CHK(a)), COMBINE(iv_b, CHK(b)))
279+ tmp0 = self .combine (iv_a , chk_a_no_iv , len (a ))
280+ tmp1 = self .combine (iv_b , chk_b_no_iv , len (b ))
281+ expected = self .combine (tmp0 , tmp1 , len (b ))
282+ checksum = self .combine (chk_a_with_iv , chk_b_with_iv , len (b ))
283+ self .assertEqual (checksum , expected )
284+
285+
286+ def _adler32_value (halves ):
287+ """Build a valid Adler-32 value from its two 16-bit sums."""
288+ s1 , s2 = halves
289+ return (s2 << 16 ) | s1
269290
270291
271292class CRC32CombineTestCase (ChecksumCombineMixin , unittest .TestCase ):
272293
273294 default_iv = 0
295+ iv_strategy = hypothesis .strategies .integers (0 , 0xffffffff )
274296
275297 def _checksum (self , data , init ):
276298 return zlib .crc32 (data , init )
@@ -282,6 +304,12 @@ def combine(self, a, b, blen):
282304class Adler32CombineTestCase (ChecksumCombineMixin , unittest .TestCase ):
283305
284306 default_iv = 1
307+ # Both 16-bit sums of an Adler-32 value are reduced modulo 65521, and
308+ # adler32_combine() is only defined on such values.
309+ iv_strategy = hypothesis .strategies .tuples (
310+ hypothesis .strategies .integers (0 , 65520 ),
311+ hypothesis .strategies .integers (0 , 65520 ),
312+ ).map (_adler32_value )
285313
286314 def _checksum (self , data , init ):
287315 return zlib .adler32 (data , init )
0 commit comments