mager-bench

Claude Sonnet 4.6 × test-writing

5.3

Edge-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.3
correctness 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