Skip to content

Commit 190bef3

Browse files
committed
test: parametrize two clean duplicated-test clusters
Two clusters of near-identical tests that differ only by data collapse cleanly into one `@pytest.mark.parametrize`d test each — a genuine LOC reduction with every case preserved as a row carrying a readable id: - waterdata_utils_test: `_format_api_dates` — 12 one-line equality tests → 1. - waterdata_test: `TestNormalizeStrIterable` iterable-normalizes — 4 → 1 (same assertion, vary the container type: list / tuple / Series / ndarray). Deliberately NOT parametrized (reconsidered for readability): `_parse_retry_after` and the `_build_filter` / reject-type clusters. Those either encode distinct behaviors with explanatory docstrings, or didn't actually reduce LOC (long multi-line param tuples), so named tests read better there.
1 parent 8bb15a2 commit 190bef3

2 files changed

Lines changed: 57 additions & 73 deletions

File tree

tests/waterdata_test.py

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,21 +1024,20 @@ def test_string_returned_unchanged(self):
10241024
# Note: no hyphen requirement here — that's monitoring_location_id-specific.
10251025
assert _normalize_str_iterable("dog", "parameter_code") == "dog"
10261026

1027-
def test_list_returned_unchanged(self):
1028-
assert _normalize_str_iterable(["00060", "00010"], "p") == ["00060", "00010"]
1029-
1030-
def test_tuple_normalizes_to_list(self):
1031-
result = _normalize_str_iterable(("00060", "00010"), "p")
1032-
assert result == ["00060", "00010"]
1033-
assert isinstance(result, list)
1034-
1035-
def test_pandas_series_normalizes_to_list(self):
1036-
result = _normalize_str_iterable(pd.Series(["00060", "00010"]), "p")
1037-
assert result == ["00060", "00010"]
1038-
assert isinstance(result, list)
1039-
1040-
def test_numpy_array_normalizes_to_list(self):
1041-
result = _normalize_str_iterable(np.array(["00060", "00010"]), "p")
1027+
@pytest.mark.parametrize(
1028+
"value",
1029+
[
1030+
["00060", "00010"],
1031+
("00060", "00010"),
1032+
pd.Series(["00060", "00010"]),
1033+
np.array(["00060", "00010"]),
1034+
],
1035+
ids=["list", "tuple", "series", "ndarray"],
1036+
)
1037+
def test_iterable_normalizes_to_list(self, value):
1038+
"""Any iterable of strings (list / tuple / Series / ndarray) comes back
1039+
as a plain ``list``."""
1040+
result = _normalize_str_iterable(value, "p")
10421041
assert result == ["00060", "00010"]
10431042
assert isinstance(result, list)
10441043

tests/waterdata_utils_test.py

Lines changed: 43 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -671,64 +671,49 @@ def test_arrange_cols_keeps_geometry_when_present():
671671
# --- _format_api_dates -------------------------------------------------------
672672

673673

674-
def test_format_api_dates_iso8601_with_z():
675-
"""ISO 8601 datetimes with a 'Z' suffix must be parsed, not dropped to None."""
676-
assert _format_api_dates("2018-02-12T23:20:50Z") == "2018-02-12T23:20:50Z"
677-
678-
679-
def test_format_api_dates_iso8601_with_fractional_seconds():
680-
assert _format_api_dates("2018-02-12T23:20:50.123Z") == "2018-02-12T23:20:50Z"
681-
682-
683-
def test_format_api_dates_iso8601_with_offset():
684-
"""Numeric offsets must be converted to UTC."""
685-
assert _format_api_dates("2018-02-12T19:20:50-04:00") == "2018-02-12T23:20:50Z"
686-
687-
688-
def test_format_api_dates_iso8601_pair():
689-
"""A list of two ISO 8601 datetimes must be parsed into a UTC interval."""
690-
result = _format_api_dates(["2018-02-12T23:20:50Z", "2018-03-18T12:31:12Z"])
691-
assert result == "2018-02-12T23:20:50Z/2018-03-18T12:31:12Z"
692-
693-
694-
def test_format_api_dates_passthrough_interval():
695-
assert _format_api_dates("2018-02-12T00:00:00Z/..") == "2018-02-12T00:00:00Z/.."
696-
697-
698-
def test_format_api_dates_passthrough_duration():
699-
assert _format_api_dates("P7D") == "P7D"
700-
701-
702-
def test_format_api_dates_passthrough_time_only_duration():
703-
"""ISO 8601 time-only durations (PT...) are passed through unchanged."""
704-
assert _format_api_dates("PT36H") == "PT36H"
705-
706-
707-
def test_format_api_dates_word_with_p_is_not_a_duration():
708-
"""Strings containing the letter 'p' must not be misclassified as durations."""
709-
assert _format_api_dates("Apr") is None
710-
711-
712-
def test_format_api_dates_date_only():
713-
assert _format_api_dates("2024-01-01", date=True) == "2024-01-01"
714-
715-
716-
def test_format_api_dates_date_only_pair():
717-
assert (
718-
_format_api_dates(["2024-01-01", "2024-02-01"], date=True)
719-
== "2024-01-01/2024-02-01"
720-
)
721-
722-
723-
def test_format_api_dates_space_separated_still_works():
724-
"""The legacy space-separated format must still parse."""
725-
assert _format_api_dates("2024-01-01 00:00:00", date=True) == "2024-01-01"
726-
727-
728-
def test_format_api_dates_open_ended_range_with_none():
729-
"""A None / NaN endpoint becomes '..' in the output range."""
730-
assert _format_api_dates(["2024-01-01", None], date=True) == "2024-01-01/.."
731-
assert _format_api_dates([None, "2024-01-01"], date=True) == "../2024-01-01"
674+
@pytest.mark.parametrize(
675+
"value, date, expected",
676+
[
677+
("2018-02-12T23:20:50Z", False, "2018-02-12T23:20:50Z"),
678+
("2018-02-12T23:20:50.123Z", False, "2018-02-12T23:20:50Z"),
679+
("2018-02-12T19:20:50-04:00", False, "2018-02-12T23:20:50Z"),
680+
(
681+
["2018-02-12T23:20:50Z", "2018-03-18T12:31:12Z"],
682+
False,
683+
"2018-02-12T23:20:50Z/2018-03-18T12:31:12Z",
684+
),
685+
("2018-02-12T00:00:00Z/..", False, "2018-02-12T00:00:00Z/.."),
686+
("P7D", False, "P7D"),
687+
("PT36H", False, "PT36H"),
688+
("Apr", False, None),
689+
("2024-01-01", True, "2024-01-01"),
690+
(["2024-01-01", "2024-02-01"], True, "2024-01-01/2024-02-01"),
691+
("2024-01-01 00:00:00", True, "2024-01-01"),
692+
(["2024-01-01", None], True, "2024-01-01/.."),
693+
([None, "2024-01-01"], True, "../2024-01-01"),
694+
],
695+
ids=[
696+
"iso8601_z",
697+
"fractional_seconds",
698+
"offset_to_utc",
699+
"iso8601_pair_to_interval",
700+
"passthrough_interval",
701+
"passthrough_duration",
702+
"time_only_duration",
703+
"word_with_p_not_duration",
704+
"date_only",
705+
"date_only_pair",
706+
"space_separated",
707+
"open_ended_none_end",
708+
"open_ended_none_start",
709+
],
710+
)
711+
def test_format_api_dates(value, date, expected):
712+
"""``_format_api_dates`` normalizes ISO 8601 datetimes to UTC (dropping
713+
fractional seconds, converting offsets), joins a pair into an interval,
714+
passes durations / intervals through unchanged, renders a None endpoint as
715+
``..``, and returns None for a non-date word (e.g. ``"Apr"``)."""
716+
assert _format_api_dates(value, date=date) == expected
732717

733718

734719
def test_format_api_dates_rejects_mapping():

0 commit comments

Comments
 (0)