@@ -36,6 +36,30 @@ def items(self):
3636 return [self ._broken_item ]
3737
3838
39+ class _BrokenStripHeaderName (str ):
40+ def strip (self , chars = None ): # type: ignore[override]
41+ _ = chars
42+ raise RuntimeError ("header strip exploded" )
43+
44+
45+ class _BrokenLowerHeaderName (str ):
46+ def strip (self , chars = None ): # type: ignore[override]
47+ _ = chars
48+ return self
49+
50+ def lower (self ): # type: ignore[override]
51+ raise RuntimeError ("header lower exploded" )
52+
53+
54+ class _NonStringLowerHeaderName (str ):
55+ def strip (self , chars = None ): # type: ignore[override]
56+ _ = chars
57+ return self
58+
59+ def lower (self ): # type: ignore[override]
60+ return object ()
61+
62+
3963def test_normalize_headers_trims_header_names ():
4064 headers = normalize_headers (
4165 {" X-Correlation-Id " : "abc123" },
@@ -53,6 +77,57 @@ def test_normalize_headers_rejects_empty_header_name():
5377 )
5478
5579
80+ def test_normalize_headers_wraps_header_name_strip_failures ():
81+ with pytest .raises (
82+ HyperbrowserError , match = "Failed to normalize header name"
83+ ) as exc_info :
84+ normalize_headers (
85+ {_BrokenStripHeaderName ("X-Trace-Id" ): "trace-1" },
86+ mapping_error_message = "headers must be a mapping of string pairs" ,
87+ )
88+
89+ assert exc_info .value .original_error is not None
90+
91+
92+ def test_normalize_headers_preserves_hyperbrowser_header_name_strip_failures ():
93+ class _BrokenStripHeaderName (str ):
94+ def strip (self , chars = None ): # type: ignore[override]
95+ _ = chars
96+ raise HyperbrowserError ("custom strip failure" )
97+
98+ with pytest .raises (HyperbrowserError , match = "custom strip failure" ) as exc_info :
99+ normalize_headers (
100+ {_BrokenStripHeaderName ("X-Trace-Id" ): "trace-1" },
101+ mapping_error_message = "headers must be a mapping of string pairs" ,
102+ )
103+
104+ assert exc_info .value .original_error is None
105+
106+
107+ def test_normalize_headers_wraps_header_name_lower_failures ():
108+ with pytest .raises (
109+ HyperbrowserError , match = "Failed to normalize header name"
110+ ) as exc_info :
111+ normalize_headers (
112+ {_BrokenLowerHeaderName ("X-Trace-Id" ): "trace-1" },
113+ mapping_error_message = "headers must be a mapping of string pairs" ,
114+ )
115+
116+ assert exc_info .value .original_error is not None
117+
118+
119+ def test_normalize_headers_wraps_non_string_header_name_lower_results ():
120+ with pytest .raises (
121+ HyperbrowserError , match = "Failed to normalize header name"
122+ ) as exc_info :
123+ normalize_headers (
124+ {_NonStringLowerHeaderName ("X-Trace-Id" ): "trace-1" },
125+ mapping_error_message = "headers must be a mapping of string pairs" ,
126+ )
127+
128+ assert exc_info .value .original_error is not None
129+
130+
56131def test_normalize_headers_rejects_overly_long_header_names ():
57132 long_header_name = "X-" + ("a" * 255 )
58133 with pytest .raises (
0 commit comments