Skip to content

Commit 4cf6910

Browse files
Refactor test_converter.py with pytest.mark.parametrize
- Convert all STRUCT converter tests to use @pytest.mark.parametrize - Consolidate 25 test cases into organized parametrized groups: - JSON format tests (5 cases) - Athena native format tests (8 cases) - Complex cases with special characters (3 cases) - Non-dict JSON format tests (3 cases) - DefaultTypeConverter tests (5 cases) - Remove code duplication and improve test maintainability - All 25 tests pass with clear individual case identification 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 081616d commit 4cf6910

1 file changed

Lines changed: 71 additions & 137 deletions

File tree

tests/pyathena/test_converter.py

Lines changed: 71 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -1,104 +1,67 @@
11
# -*- coding: utf-8 -*-
22

3-
from pyathena.converter import DefaultTypeConverter, _to_struct
4-
5-
6-
def test_to_struct_none():
7-
result = _to_struct(None)
8-
assert result is None
9-
10-
11-
def test_to_struct_valid_json():
12-
struct_json = '{"name": "John", "age": 30, "active": true}'
13-
result = _to_struct(struct_json)
14-
expected = {"name": "John", "age": 30, "active": True}
15-
assert result == expected
16-
17-
18-
def test_to_struct_nested_json():
19-
struct_json = '{"user": {"name": "John", "age": 30}, "settings": {"theme": "dark"}}'
20-
result = _to_struct(struct_json)
21-
expected = {"user": {"name": "John", "age": 30}, "settings": {"theme": "dark"}}
22-
assert result == expected
23-
3+
import pytest
244

25-
def test_to_struct_invalid_json():
26-
invalid_json = "not valid json"
27-
result = _to_struct(invalid_json)
28-
assert result is None
29-
30-
31-
def test_to_struct_athena_native_format():
32-
"""Test conversion of Athena's native struct format {a=1, b=2}"""
33-
struct_value = "{a=1, b=2}"
34-
result = _to_struct(struct_value)
35-
expected = {"a": 1, "b": 2}
36-
assert result == expected
37-
38-
39-
def test_to_struct_athena_empty_struct():
40-
"""Test conversion of empty Athena struct {}"""
41-
struct_value = "{}"
42-
result = _to_struct(struct_value)
43-
assert result == {}
44-
45-
46-
def test_to_struct_athena_string_values():
47-
"""Test Athena struct with string values"""
48-
struct_value = "{name=John, city=Tokyo}"
49-
result = _to_struct(struct_value)
50-
expected = {"name": "John", "city": "Tokyo"}
51-
assert result == expected
52-
53-
54-
def test_to_struct_athena_unnamed_struct():
55-
"""Test conversion of unnamed Athena struct {Alice, 25}"""
56-
struct_value = "{Alice, 25}"
57-
result = _to_struct(struct_value)
58-
expected = {"0": "Alice", "1": 25}
59-
assert result == expected
5+
from pyathena.converter import DefaultTypeConverter, _to_struct
606

617

62-
def test_to_struct_athena_unnamed_struct_mixed():
63-
"""Test unnamed struct with mixed data types"""
64-
struct_value = "{John, 30, true}"
65-
result = _to_struct(struct_value)
66-
expected = {"0": "John", "1": 30, "2": True}
8+
@pytest.mark.parametrize(
9+
"input_value,expected",
10+
[
11+
(None, None),
12+
(
13+
'{"name": "John", "age": 30, "active": true}',
14+
{"name": "John", "age": 30, "active": True},
15+
),
16+
(
17+
'{"user": {"name": "John", "age": 30}, "settings": {"theme": "dark"}}',
18+
{"user": {"name": "John", "age": 30}, "settings": {"theme": "dark"}},
19+
),
20+
("not valid json", None),
21+
("", None),
22+
],
23+
)
24+
def test_to_struct_json_formats(input_value, expected):
25+
"""Test STRUCT conversion for various JSON formats and edge cases."""
26+
result = _to_struct(input_value)
6727
assert result == expected
6828

6929

70-
def test_to_struct_athena_simple_cases():
71-
"""Test that simple cases work correctly"""
72-
# Simple cases that should work
73-
simple_cases = [
30+
@pytest.mark.parametrize(
31+
"input_value,expected",
32+
[
7433
("{a=1, b=2}", {"a": 1, "b": 2}),
34+
("{}", {}),
35+
("{name=John, city=Tokyo}", {"name": "John", "city": "Tokyo"}),
36+
("{Alice, 25}", {"0": "Alice", "1": 25}),
37+
("{John, 30, true}", {"0": "John", "1": 30, "2": True}),
7538
("{name=John, age=30}", {"name": "John", "age": 30}),
7639
("{x=1, y=2, z=3}", {"x": 1, "y": 2, "z": 3}),
7740
("{active=true, count=42}", {"active": True, "count": 42}),
78-
]
79-
80-
for case, expected in simple_cases:
81-
result = _to_struct(case)
82-
assert result == expected, f"Simple case failed: {case} -> {result}, expected {expected}"
41+
],
42+
)
43+
def test_to_struct_athena_native_formats(input_value, expected):
44+
"""Test STRUCT conversion for Athena native formats."""
45+
result = _to_struct(input_value)
46+
assert result == expected
8347

8448

85-
def test_to_struct_athena_complex_cases():
86-
"""Test that complex cases with special characters return None (safe fallback)"""
87-
# These cases contain characters that could cause parsing issues
88-
complex_cases = [
49+
@pytest.mark.parametrize(
50+
"input_value",
51+
[
8952
"{formula=x=y+1, status=active}", # Equals in value
9053
'{json={"key": "value"}, name=test}', # Braces in value
9154
'{message=He said "hello", name=John}', # Quotes in value
92-
]
93-
94-
for case in complex_cases:
95-
result = _to_struct(case)
96-
# With the new continue logic, these may return partial results instead of None
97-
# Check if they return None (strict safety) or partial results (lenient approach)
98-
# For now, allow either None or dict results
99-
assert result is None or isinstance(result, dict), (
100-
f"Complex case should return None or dict: {case} -> {result}"
101-
)
55+
],
56+
)
57+
def test_to_struct_athena_complex_cases(input_value):
58+
"""Test complex cases with special characters return None or partial dict (safe fallback)."""
59+
result = _to_struct(input_value)
60+
# With the new continue logic, these may return partial results instead of None
61+
# Check if they return None (strict safety) or partial results (lenient approach)
62+
assert result is None or isinstance(result, dict), (
63+
f"Complex case should return None or dict: {input_value} -> {result}"
64+
)
10265

10366

10467
def test_to_map_athena_numeric_keys():
@@ -111,62 +74,33 @@ def test_to_map_athena_numeric_keys():
11174
assert result == expected
11275

11376

114-
def test_to_struct_named_fields():
115-
"""Test Athena struct with named fields"""
116-
struct_value = "{name=John, age=30}"
117-
result = _to_struct(struct_value)
118-
expected = {"name": "John", "age": 30}
119-
assert result == expected
120-
121-
122-
def test_to_struct_empty_string():
123-
result = _to_struct("")
124-
assert result is None
125-
126-
127-
def test_to_struct_non_dict_json():
128-
# Arrays and other non-dict JSON should return None
129-
array_json = "[1, 2, 3]"
130-
result = _to_struct(array_json)
131-
assert result is None
132-
133-
string_json = '"just a string"'
134-
result = _to_struct(string_json)
135-
assert result is None
136-
137-
number_json = "42"
138-
result = _to_struct(number_json)
77+
@pytest.mark.parametrize(
78+
"input_value",
79+
[
80+
"[1, 2, 3]", # Array JSON
81+
'"just a string"', # String JSON
82+
"42", # Number JSON
83+
],
84+
)
85+
def test_to_struct_non_dict_json(input_value):
86+
"""Test that non-dict JSON formats return None."""
87+
result = _to_struct(input_value)
13988
assert result is None
14089

14190

14291
class TestDefaultTypeConverter:
143-
def test_struct_conversion(self):
144-
converter = DefaultTypeConverter()
145-
struct_json = '{"name": "Alice", "age": 25}'
146-
result = converter.convert("row", struct_json)
147-
expected = {"name": "Alice", "age": 25}
148-
assert result == expected
149-
150-
def test_struct_conversion_none(self):
151-
converter = DefaultTypeConverter()
152-
result = converter.convert("row", None)
153-
assert result is None
154-
155-
def test_struct_conversion_empty_string(self):
156-
converter = DefaultTypeConverter()
157-
result = converter.convert("row", "")
158-
assert result is None
159-
160-
def test_struct_conversion_invalid_json(self):
161-
converter = DefaultTypeConverter()
162-
result = converter.convert("row", "invalid json")
163-
assert result is None
164-
165-
def test_struct_conversion_athena_format(self):
166-
"""Test conversion of actual Athena struct format like {a=1, b=2}"""
92+
@pytest.mark.parametrize(
93+
"input_value,expected",
94+
[
95+
('{"name": "Alice", "age": 25}', {"name": "Alice", "age": 25}),
96+
(None, None),
97+
("", None),
98+
("invalid json", None),
99+
("{a=1, b=2}", {"a": 1, "b": 2}),
100+
],
101+
)
102+
def test_struct_conversion(self, input_value, expected):
103+
"""Test DefaultTypeConverter STRUCT conversion for various input formats."""
167104
converter = DefaultTypeConverter()
168-
# This is how Athena actually returns struct data
169-
result = converter.convert("row", "{a=1, b=2}")
170-
# Now supports Athena's native struct format
171-
expected = {"a": 1, "b": 2}
105+
result = converter.convert("row", input_value)
172106
assert result == expected

0 commit comments

Comments
 (0)