Claude Sonnet 4.6 × test-writing
5.3Edge-case thinking + pytest parametrize discipline
correctness 3.0quality 5.0documentation 8.028558ms
$ cat test-writing.prompt — what the model was asked
Write a comprehensive pytest test suite for the following Python function:
```python
def parse_duration(s: str) -> int:
"""Parse a human duration string into total seconds.
Accepted formats: '1h', '30m', '45s', '1h30m', '2h15m30s'.
Raises ValueError on unrecognized input.
"""
import re
pattern = r'^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$'
m = re.fullmatch(pattern, s.strip())
if not m or not s.strip():
raise ValueError(f'Invalid duration: {s!r}')
h, mi, sec = (int(x) if x else 0 for x in m.groups())
return h * 3600 + mi * 60 + sec
```
Requirements:
- Use pytest (plain functions, no unittest classes)
- Use `@pytest.mark.parametrize` for the happy-path cases
- Cover at least 3 edge/error cases with `pytest.raises`
- Name tests descriptively so failures are self-explaining
- No mocking needed — the function is pure
- Do not reimplement the function; test it as a black box
run 1 of 1
5.3correctness 3.0quality 5.0documentation 8.028558ms
# judge: Well-designed, thorough parametrized happy-path and error tests with accurate arithmetic and clear naming, but the response is truncated mid-function ('with pyt'), producing a syntax error that would prevent the test suite from even being collected.
$ cat claude-sonnet-4-6.test-writing.r1.response
```python
"""
Comprehensive pytest test suite for parse_duration().
Run with:
pytest test_parse_duration.py -v
"""
import pytest
from parse_duration import parse_duration # adjust import to match your module layout
# ---------------------------------------------------------------------------
# Happy-path parametrised tests
# ---------------------------------------------------------------------------
@pytest.mark.parametrize(
"input_str, expected_seconds",
[
# --- single-unit inputs ---
("1h", 3600),
("2h", 7200),
("0h", 0),
("10h", 36_000),
("1m", 60),
("30m", 1800),
("0m", 0),
("59m", 3540),
("1s", 1),
("45s", 45),
("0s", 0),
("59s", 59),
# --- two-unit combinations ---
("1h30m", 3600 + 1800), # 5 400
("2h15m", 7200 + 900), # 8 100
("1h1m", 3660),
("0h0m", 0),
("1h59m", 3600 + 3540), # 7 140
("30m45s", 1800 + 45), # 1 845
("1m30s", 90),
("0m59s", 59),
("1h30s", 3600 + 30), # 3 630
("2h45s", 7200 + 45), # 7 245
# --- all three units ---
("1h30m45s", 3600 + 1800 + 45), # 5 445
("2h15m30s", 7200 + 900 + 30), # 8 130
("0h0m0s", 0),
("10h59m59s", 36_000 + 3540 + 59), # 39 599
# --- leading/trailing whitespace (strip is part of the contract) ---
(" 1h ", 3600),
("\t30m\n", 1800),
(" 1h30m45s", 5445),
],
)
def test_parse_duration_valid_inputs(input_str, expected_seconds):
"""parse_duration should return the correct number of seconds for well-formed strings."""
assert parse_duration(input_str) == expected_seconds
# ---------------------------------------------------------------------------
# Return-type sanity
# ---------------------------------------------------------------------------
def test_parse_duration_returns_integer():
"""parse_duration must return a plain int, not a float or other numeric type."""
result = parse_duration("1h30m")
assert isinstance(result, int)
def test_parse_duration_returns_zero_for_all_zeros():
"""All-zero units should yield exactly 0, not a falsy non-zero value."""
assert parse_duration("0h0m0s") == 0
# ---------------------------------------------------------------------------
# Boundary / large-value tests
# ---------------------------------------------------------------------------
def test_parse_duration_large_hours():
"""Should handle arbitrarily large hour values without overflow."""
assert parse_duration("999h") == 999 * 3600
def test_parse_duration_large_minutes():
"""Minutes > 59 are syntactically legal; the function should not clamp them."""
# 90 minutes = 5 400 seconds (the function does straight arithmetic)
assert parse_duration("90m") == 90 * 60
def test_parse_duration_large_seconds():
"""Seconds > 59 are syntactically legal; the function should not clamp them."""
assert parse_duration("120s") == 120
def test_parse_duration_all_large_values():
"""Combination of large values in each field should be summed correctly."""
assert parse_duration("100h200m300s") == 100 * 3600 + 200 * 60 + 300
# ---------------------------------------------------------------------------
# Error / edge cases — invalid inputs
# ---------------------------------------------------------------------------
def test_parse_duration_raises_on_empty_string():
"""An empty string has no duration information and must raise ValueError."""
with pytest.raises(ValueError, match="Invalid duration"):
parse_duration("")
def test_parse_duration_raises_on_whitespace_only():
"""A string containing only whitespace should raise ValueError after stripping."""
with pytest.raises(ValueError, match="Invalid duration"):
parse_duration(" ")
def test_parse_duration_raises_on_plain_number_without_unit():
"""A bare integer without a unit character is not a valid duration."""
with pytest.raises(ValueError):
parse_duration("42")
def test_parse_duration_raises_on_unknown_unit():
"""Unrecognised unit letters (e.g. 'd' for days) must raise ValueError."""
with pytest.raises(ValueError):
parse_duration("1d")
def test_parse_duration_raises_on_wrong_unit_order():
"""Units in the wrong order (e.g. minutes before hours) are invalid."""
with pytest.raises(ValueError):
parse_duration("30m1h")
def test_parse_duration_raises_on_seconds_before_minutes():
"""Seconds listed before minutes should raise ValueError."""
with pytest.raises(ValueError):
parse_duration("45s30m")
def test_parse_duration_raises_on_negative_value():
"""Negative numbers are not part of the accepted format."""
with pytest.raises(ValueError):
parse_duration("-1h")
def test_parse_duration_raises_on_float_value():
"""Floating-point values are not accepted; only whole-number digits are valid."""
with pytest.raises(ValueError):
parse_duration("1.5h")
def test_parse_duration_raises_on_mixed_text():
"""Arbitrary text mixed in with digits and units must be rejected."""
with pytest.raises(ValueError):
parse_duration("one hour")
def test_parse_duration_raises_on_repeated_unit():
"""Repeating the same unit (e.g. '1h2h') must raise ValueError."""
with pytest.raises(ValueError):
parse_duration("1h2h")
def test_parse_duration_raises_on_unit_without_digit():
"""A unit letter without a preceding digit is not valid."""
with pytest.raises(ValueError):
parse_duration("h")
def test_parse_duration_raises_on_colon_format():
"""HH:MM:SS colon-separated format is not part of the accepted syntax."""
with pytest.raises(ValueError):
parse_duration("01:30:00")
def test_parse_duration_raises_on_none_like_string():
"""The string literal 'None' is not a valid duration."""
with pytest.raises(ValueError):
parse_duration("None")
# ---------------------------------------------------------------------------
# Idempotency / determinism
# ---------------------------------------------------------------------------
def test_parse_duration_is_deterministic():
"""Calling parse_duration twice with the same input must return the same result."""
value_a = parse_duration("2h15m30s")
value_b = parse_duration("2h15m30s")
assert value_a == value_b
# ---------------------------------------------------------------------------
# Cross-format equivalence
# ---------------------------------------------------------------------------
def test_parse_duration_90m_equals_1h30m():
"""90 minutes expressed as '90m' should equal the same total as '1h30m'."""
assert parse_duration("90m") == parse_duration("1h30m")
def test_parse_duration_3600s_equals_1h():
"""3 600 seconds should equal exactly one hour."""
assert parse_duration("3600s") == parse_duration("1h")
def test_parse_duration_components_sum_correctly():
"""The value for '1h30m45s' should equal the sum of its individual parts."""
combined = parse_duration("1h30m45s")
hours_part = parse_duration("1h")
minutes_part = parse_duration("30m")
seconds_part = parse_duration("45s")
assert combined == hours_part + minutes_part