|
4 | 4 | from datetime import timedelta |
5 | 5 | from decimal import Decimal |
6 | 6 | from logging import getLogger |
| 7 | +from uuid import UUID |
7 | 8 |
|
8 | 9 | import numpy |
9 | 10 | import pytest |
@@ -133,3 +134,78 @@ def test_year_month_interval_to_timedelta(months): |
133 | 134 | assert converter.INTERVAL_YEAR_MONTH_to_numpy_timedelta( |
134 | 135 | months, scale=0 |
135 | 136 | ) == numpy.timedelta64(months, "M") |
| 137 | + |
| 138 | + |
| 139 | +def test_converter_to_snowflake_bytes(): |
| 140 | + """Test that bytes in a list are properly hex-encoded.""" |
| 141 | + uuid = UUID("12345678-1234-5678-1234-567812345678") |
| 142 | + |
| 143 | + converter = SnowflakeConverter() |
| 144 | + # After fix for GH-2311: bytes are now properly hex-encoded via to_snowflake() |
| 145 | + assert converter.to_snowflake([uuid.bytes]) == [ |
| 146 | + "X'12345678123456781234567812345678'" |
| 147 | + ] |
| 148 | + |
| 149 | + |
| 150 | +def test_converter_list_with_binary_to_snowflake(): |
| 151 | + """Test that bytes values in lists are properly converted to hex format. |
| 152 | +
|
| 153 | + Regression test for GitHub Issue #2311. |
| 154 | + When binary data (bytes) is passed in a list parameter, each item in the list |
| 155 | + should have to_snowflake called on it, converting bytes to hex format. |
| 156 | + Without this fix, a UnicodeDecodeError occurs when bytes contain non-ASCII values. |
| 157 | + """ |
| 158 | + # Use a UUID that generates non-ASCII bytes (contains bytes > 127) |
| 159 | + test_uuid = UUID("4363f57d-c9ca-4e63-92c7-3e67786c8a30") |
| 160 | + |
| 161 | + converter = SnowflakeConverter() |
| 162 | + |
| 163 | + # Single bytes should work - this calls _bytes_to_snowflake which hex-encodes |
| 164 | + single_result = converter.to_snowflake(test_uuid.bytes) |
| 165 | + # The result should be hex-encoded bytes (ASCII safe) |
| 166 | + assert isinstance(single_result, (bytes, bytearray)) |
| 167 | + expected_hex = single_result.decode("ascii") |
| 168 | + assert expected_hex == "4363F57DC9CA4E6392C73E67786C8A30" |
| 169 | + |
| 170 | + # List of bytes should also work - currently fails with UnicodeDecodeError |
| 171 | + # because _list_to_snowflake doesn't call to_snowflake on each item. |
| 172 | + # After fix, each item in the list should be properly quoted with hex format. |
| 173 | + list_result = converter.to_snowflake([test_uuid.bytes]) |
| 174 | + assert list_result == [f"X'{expected_hex}'"] |
| 175 | + |
| 176 | + |
| 177 | +def test_converter_list_with_non_ascii_bytes_to_snowflake(): |
| 178 | + """Test that non-ASCII bytes in lists don't cause UnicodeDecodeError. |
| 179 | +
|
| 180 | + Regression test for GitHub Issue #2311. |
| 181 | + This test specifically uses bytes that contain values > 127 which cannot |
| 182 | + be decoded as ASCII, ensuring the fix properly hex-encodes them first. |
| 183 | + """ |
| 184 | + # These bytes contain values that cannot be decoded as ASCII |
| 185 | + non_ascii_bytes = bytes([0xF5, 0xAB, 0xCD, 0xEF]) |
| 186 | + |
| 187 | + converter = SnowflakeConverter() |
| 188 | + |
| 189 | + # Single bytes should work |
| 190 | + single_result = converter.to_snowflake(non_ascii_bytes) |
| 191 | + assert single_result == b"F5ABCDEF" |
| 192 | + |
| 193 | + # List of non-ASCII bytes should also work without UnicodeDecodeError |
| 194 | + list_result = converter.to_snowflake([non_ascii_bytes]) |
| 195 | + assert list_result == ["X'F5ABCDEF'"] |
| 196 | + |
| 197 | + |
| 198 | +def test_converter_list_with_mixed_types_to_snowflake(): |
| 199 | + """Test that lists with mixed types including bytes work correctly.""" |
| 200 | + converter = SnowflakeConverter() |
| 201 | + |
| 202 | + # Mix of strings and bytes |
| 203 | + mixed_list = [b"\x00\xFF", "hello", 42, None, True] |
| 204 | + result = converter.to_snowflake(mixed_list) |
| 205 | + |
| 206 | + # Verify each element is properly converted |
| 207 | + assert "X'00FF'" in result # bytes should be hex-encoded |
| 208 | + assert "'hello'" in result # string should be quoted |
| 209 | + assert "42" in result # number should be stringified |
| 210 | + assert "NULL" in result # None should become NULL |
| 211 | + assert "TRUE" in result # bool should become TRUE/FALSE |
0 commit comments