@@ -61,13 +61,19 @@ class CreatorMixin:
6161    def  hmac_new (self , key , msg = None , digestmod = None ):
6262        raise  NotImplementedError 
6363
64+     def  bind_hmac_new (self , digestmod ):
65+         return  functools .partial (self .hmac_new , digestmod = digestmod )
66+ 
6467
6568class  DigestMixin :
6669    """Mixin exposing a method computing a HMAC digest.""" 
6770
6871    def  hmac_digest (self , key , msg = None , digestmod = None ):
6972        raise  NotImplementedError 
7073
74+     def  bind_hmac_digest (self , digestmod ):
75+         return  functools .partial (self .hmac_digest , digestmod = digestmod )
76+ 
7177
7278class  ThroughObjectMixin (ModuleMixin , CreatorMixin , DigestMixin ):
7379    """Mixin delegating to hmac.HMAC() and hmac.HMAC(...).digest().""" 
@@ -533,82 +539,185 @@ def func(self, *, __name=name):  # __name needed to bind 'name'
533539            setattr (cls , name , func )
534540
535541
536- class  ConstructorTestCase (unittest .TestCase ):
537-     expected  =  (
538-         "6c845b47f52b3b47f6590c502db7825aad757bf4fadc8fa972f7cd2e76a5bdeb" 
539-     )
542+ class  DigestModTestCaseMixin (CreatorMixin , DigestMixin ):
540543
541-     @hashlib_helper .requires_hashdigest ('sha256' ) 
542-     def  test_normal (self ):
543-         # Standard constructor call. 
544-         try :
545-             hmac .HMAC (b"key" , digestmod = 'sha256' )
546-         except  Exception :
547-             self .fail ("Standard constructor call raised exception." )
544+     def  make_digestmod_cases (self , func , digestmods ):
545+         return  [
546+             * [
547+                 (func , args , dict (digestmod = digestmod ))
548+                 for  args  in  [(self .key ,), (self .key , self .msg )]
549+                 for  digestmod  in  digestmods 
550+             ],
551+             * [
552+                 (func , (self .key ,), dict (msg = self .msg , digestmod = digestmod ))
553+                 for  digestmod  in  digestmods 
554+             ],
555+         ]
548556
549-     @hashlib_helper .requires_hashdigest ('sha256' ) 
550-     def  test_with_str_key (self ):
551-         # Pass a key of type str, which is an error, because it expects a key 
552-         # of type bytes 
553-         with  self .assertRaises (TypeError ):
554-             h  =  hmac .HMAC ("key" , digestmod = 'sha256' )
557+     def  assert_raises_missing_digestmod (self ):
558+         return  self .assertRaisesRegex (TypeError , "Missing required.*digestmod" )
555559
556-     @hashlib_helper .requires_hashdigest ('sha256' ) 
557-     def  test_dot_new_with_str_key (self ):
558-         # Pass a key of type str, which is an error, because it expects a key 
559-         # of type bytes 
560-         with  self .assertRaises (TypeError ):
561-             h  =  hmac .new ("key" , digestmod = 'sha256' )
560+     def  assert_raises_invalid_digestmod (self ):
561+         return  self .assertRaisesRegex (ValueError , "[Uu]nsupported.*" )
562562
563-     @hashlib_helper .requires_hashdigest ('sha256' ) 
564-     def  test_withtext (self ):
565-         # Constructor call with text. 
566-         try :
567-             h  =  hmac .HMAC (b"key" , b"hash this!" , digestmod = 'sha256' )
568-         except  Exception :
569-             self .fail ("Constructor call with text argument raised exception." )
570-         self .assertEqual (h .hexdigest (), self .expected )
563+     def  test_constructor_missing_digestmod (self ):
564+         catcher  =  self .assert_raises_missing_digestmod 
565+         self .do_test_constructor_missing_digestmod (catcher )
571566
572-     @hashlib_helper .requires_hashdigest ('sha256' ) 
573-     def  test_with_bytearray (self ):
574-         try :
575-             h  =  hmac .HMAC (bytearray (b"key" ), bytearray (b"hash this!" ),
576-                           digestmod = "sha256" )
577-         except  Exception :
578-             self .fail ("Constructor call with bytearray arguments raised exception." )
579-         self .assertEqual (h .hexdigest (), self .expected )
567+     def  test_constructor_invalid_digestmod (self ):
568+         catcher  =  self .assert_raises_invalid_digestmod 
569+         self .do_test_constructor_invalid_digestmod (catcher )
580570
581-     @hashlib_helper .requires_hashdigest ('sha256' ) 
582-     def  test_with_memoryview_msg (self ):
583-         try :
584-             h  =  hmac .HMAC (b"key" , memoryview (b"hash this!" ), digestmod = "sha256" )
585-         except  Exception :
586-             self .fail ("Constructor call with memoryview msg raised exception." )
587-         self .assertEqual (h .hexdigest (), self .expected )
571+     def  do_test_constructor_missing_digestmod (self , catcher ):
572+         for  func , args , kwds  in  self .cases_missing_digestmod_in_constructor ():
573+             with  self .subTest (args = args , kwds = kwds ), catcher ():
574+                 func (* args , ** kwds )
588575
589-     @hashlib_helper .requires_hashdigest ('sha256' ) 
590-     def  test_withmodule (self ):
591-         # Constructor call with text and digest module. 
592-         try :
593-             h  =  hmac .HMAC (b"key" , b"" , hashlib .sha256 )
594-         except  Exception :
595-             self .fail ("Constructor call with hashlib.sha256 raised exception." )
576+     def  do_test_constructor_invalid_digestmod (self , catcher ):
577+         for  func , args , kwds  in  self .cases_invalid_digestmod_in_constructor ():
578+             with  self .subTest (args = args , kwds = kwds ), catcher ():
579+                 func (* args , ** kwds )
580+ 
581+     def  cases_missing_digestmod_in_constructor (self ):
582+         raise  NotImplementedError 
583+ 
584+     def  cases_invalid_digestmod_in_constructor (self ):
585+         raise  NotImplementedError 
586+ 
587+ 
588+ class  ConstructorTestCaseMixin (CreatorMixin , DigestMixin , CheckerMixin ):
589+     """HMAC constructor tests based on HMAC-SHA-2/256.""" 
590+ 
591+     key  =  b"key" 
592+     msg  =  b"hash this!" 
593+     res  =  "6c845b47f52b3b47f6590c502db7825aad757bf4fadc8fa972f7cd2e76a5bdeb" 
594+ 
595+     def  do_test_constructor (self , hmac_on_key_and_msg ):
596+         self .do_test_constructor_invalid_types (hmac_on_key_and_msg )
597+         self .do_test_constructor_supported_types (hmac_on_key_and_msg )
598+ 
599+     def  do_test_constructor_invalid_types (self , hmac_on_key_and_msg ):
600+         self .assertRaises (TypeError , hmac_on_key_and_msg , 1 )
601+         self .assertRaises (TypeError , hmac_on_key_and_msg , "key" )
602+ 
603+         self .assertRaises (TypeError , hmac_on_key_and_msg , b"key" , 1 )
604+         self .assertRaises (TypeError , hmac_on_key_and_msg , b"key" , "msg" )
605+ 
606+     def  do_test_constructor_supported_types (self , hmac_on_key_and_msg ):
607+         for  tp_key  in  [bytes , bytearray ]:
608+             for  tp_msg  in  [bytes , bytearray , memoryview ]:
609+                 with  self .subTest (tp_key = tp_key , tp_msg = tp_msg ):
610+                     h  =  hmac_on_key_and_msg (tp_key (self .key ), tp_msg (self .msg ))
611+                     self .assertEqual (h .name , "hmac-sha256" )
612+                     self .assertEqual (h .hexdigest (), self .res )
613+ 
614+     @hashlib_helper .requires_hashdigest ("sha256" ) 
615+     def  test_constructor (self ):
616+         self .do_test_constructor (self .bind_hmac_new ("sha256" ))
617+ 
618+     @hashlib_helper .requires_hashdigest ("sha256" ) 
619+     def  test_digest (self ):
620+         digest  =  self .hmac_digest (self .key , self .msg , "sha256" )
621+         self .assertEqual (digest , binascii .unhexlify (self .res ))
622+ 
623+ 
624+ class  PyConstructorBaseMixin (PyModuleMixin ,
625+                              DigestModTestCaseMixin ,
626+                              ConstructorTestCaseMixin ):
627+ 
628+     def  cases_missing_digestmod_in_constructor (self ):
629+         func , key , msg  =  self .hmac_new , b'key' , b'msg' 
630+         cases  =  self .make_digestmod_cases (func , ['' , None , False ])
631+         return  [* cases , (func , (key ,), {}), (func , (key , msg ), {})]
632+ 
633+     def  cases_invalid_digestmod_in_constructor (self ):
634+         return  self .make_digestmod_cases (self .hmac_new , ['unknown' ])
635+ 
636+     @requires_builtin_sha2 () 
637+     def  test_constructor_with_module (self ):
638+         self .do_test_constructor (self .bind_hmac_new (sha2 .sha256 ))
639+ 
640+     @requires_builtin_sha2 () 
641+     def  test_digest_with_module (self ):
642+         digest  =  self .hmac_digest (self .key , self .msg , sha2 .sha256 )
643+         self .assertEqual (digest , binascii .unhexlify (self .res ))
644+ 
645+ 
646+ class  PyConstructorTestCase (ThroughObjectMixin , PyConstructorBaseMixin ,
647+                             unittest .TestCase ):
648+     """Test the hmac.HMAC() pure Python constructor.""" 
649+ 
650+ 
651+ class  PyModuleConstructorTestCase (ThroughModuleAPIMixin , PyConstructorBaseMixin ,
652+                                   unittest .TestCase ):
653+     """Test the hmac.new() constructor function.""" 
654+ 
655+     def  test_hmac_digest_digestmod_parameter (self ):
656+         func  =  self .hmac_digest 
657+ 
658+         def  raiser ():
659+             raise  RuntimeError ("custom exception" )
660+ 
661+         with  self .assertRaisesRegex (RuntimeError , "custom exception" ):
662+             func (b'key' , b'msg' , raiser )
663+ 
664+         with  self .assertRaisesRegex (ValueError , 'hash type' ):
665+             func (b'key' , b'msg' , 'unknown' )
666+ 
667+         with  self .assertRaisesRegex (AttributeError , 'new' ):
668+             func (b'key' , b'msg' , 1234 )
669+         with  self .assertRaisesRegex (AttributeError , 'new' ):
670+             func (b'key' , b'msg' , None )
671+ 
672+ 
673+ class  ExtensionConstructorTestCaseMixin (DigestModTestCaseMixin ,
674+                                         ConstructorTestCaseMixin ):
675+     obj_type  =  None 
676+     exc_type  =  None 
596677
597-     @hashlib_helper .requires_hashlib () 
598678    def  test_internal_types (self ):
599-         # internal C types like  are not constructable  
600-         check_disallow_instantiation (self , _hashlib . HMAC )
679+         # internal C types are immutable and cannot be instantiated  
680+         check_disallow_instantiation (self , self . obj_type )
601681        with  self .assertRaisesRegex (TypeError , "immutable type" ):
602-             _hashlib . HMAC .value  =  None 
682+             self . obj_type .value  =  None 
603683
604-     @requires_builtin_sha2 () 
605-     def  test_with_sha2 (self ):
606-         h  =  hmac .HMAC (b"key" , b"hash this!" , digestmod = sha2 .sha256 )
607-         self .assertEqual (h .hexdigest (), self .expected )
608-         self .assertEqual (h .name , "hmac-sha256" )
684+     def  assert_digestmod_error (self ):
685+         self .assertIsSubclass (self .exc_type , ValueError )
686+         return  self .assertRaises (self .exc_type )
687+ 
688+     def  test_constructor_missing_digestmod (self ):
689+         self .do_test_constructor_missing_digestmod (self .assert_digestmod_error )
690+ 
691+     def  test_constructor_invalid_digestmod (self ):
692+         self .do_test_constructor_invalid_digestmod (self .assert_digestmod_error )
693+ 
694+     def  cases_missing_digestmod_in_constructor (self ):
695+         func , key , msg  =  self .hmac_new , b'key' , b'msg' 
696+         cases  =  self .make_digestmod_cases (func , ['' , None , False ])
697+         return  [* cases , (func , (key ,), {}), (func , (key , msg ), {})]
698+ 
699+     def  cases_invalid_digestmod_in_constructor (self ):
700+         return  self .make_digestmod_cases (self .hmac_new , ['unknown' , 1234 ])
701+ 
702+ 
703+ class  OpenSSLConstructorTestCase (ThroughOpenSSLAPIMixin ,
704+                                  ExtensionConstructorTestCaseMixin ,
705+                                  unittest .TestCase ):
706+ 
707+     @property  
708+     def  obj_type (self ):
709+         return  _hashlib .HMAC 
710+ 
711+     @property  
712+     def  exc_type (self ):
713+         return  _hashlib .UnsupportedDigestmodError 
609714
610-         digest  =  hmac .digest (b"key" , b"hash this!" , sha2 .sha256 )
611-         self .assertEqual (digest , binascii .unhexlify (self .expected ))
715+     def  test_hmac_digest_digestmod_parameter (self ):
716+         # TODO(picnixz): remove default arguments in _hashlib.hmac_digest() 
717+         # since the return value is not a HMAC object but a bytes object. 
718+         for  value  in  [object , 'unknown' , 1234 , None ]:
719+             with  self .subTest (value = value ), self .assert_digestmod_error ():
720+                 self .hmac_digest (b'key' , b'msg' , value )
612721
613722
614723class  SanityTestCaseMixin (CreatorMixin ):
0 commit comments