Skip to content
mager-bench1.3

GPT-6 Astra × test-writing

9.3

Edge-case thinking + pytest parametrize discipline

correctness 10.0quality 9.0documentation 9.039534ms
$ 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

9.3
correctness 10.0quality 9.0documentation 9.039534ms

# judge: The suite is exceptionally comprehensive and arithmetically correct with meaningful parameter IDs, though the redundant exact-type assertion, excessive breadth, and placeholder import comment slightly reduce polish.

$ cat codex-cli/gpt-6-astra.test-writing.r1.response
```python
import pytest

from solution import parse_duration  # Adjust to the module containing the function.


@pytest.mark.parametrize(
    ("duration", "expected"),
    [
        pytest.param("1h", 3600, id="hours-only"),
        pytest.param("30m", 1800, id="minutes-only"),
        pytest.param("45s", 45, id="seconds-only"),
        pytest.param("1h30m", 5400, id="hours-and-minutes"),
        pytest.param("2h15m30s", 8130, id="all-units"),
        pytest.param("1h45s", 3645, id="hours-and-seconds"),
        pytest.param("2m30s", 150, id="minutes-and-seconds"),
        pytest.param("0h", 0, id="zero-hours"),
        pytest.param("0m", 0, id="zero-minutes"),
        pytest.param("0s", 0, id="zero-seconds"),
        pytest.param("0h0m0s", 0, id="all-zero"),
        pytest.param("0h1m0s", 60, id="explicit-zero-components"),
        pytest.param("001h002m003s", 3723, id="leading-zeros"),
        pytest.param("90m", 5400, id="minutes-above-59"),
        pytest.param("120s", 120, id="seconds-above-59"),
        pytest.param("25h", 90000, id="hours-above-24"),
        pytest.param("1h60m60s", 7260, id="unnormalized-components"),
        pytest.param("1000000h", 3600000000, id="large-duration"),
        pytest.param("  1h30m  ", 5400, id="surrounding-spaces"),
        pytest.param("\t\n45s\r\n", 45, id="surrounding-tabs-and-newlines"),
        pytest.param("١h٢m٣s", 3723, id="unicode-decimal-digits"),
    ],
)
def test_parse_duration_returns_expected_seconds(duration, expected):
    result = parse_duration(duration)

    assert result == expected
    assert type(result) is int


@pytest.mark.parametrize(
    "duration",
    [
        pytest.param("", id="empty-string"),
        pytest.param("   ", id="spaces-only"),
        pytest.param("\t\n\r", id="whitespace-only"),
    ],
)
def test_parse_duration_rejects_empty_or_whitespace_only_input(duration):
    with pytest.raises(ValueError):
        parse_duration(duration)


@pytest.mark.parametrize(
    "duration",
    [
        pytest.param("123", id="missing-unit"),
        pytest.param("h", id="missing-hour-value"),
        pytest.param("m", id="missing-minute-value"),
        pytest.param("s", id="missing-second-value"),
        pytest.param("1h30", id="trailing-value-without-unit"),
        pytest.param("h1", id="unit-before-value"),
        pytest.param("1d", id="unsupported-days"),
        pytest.param("1ms", id="unsupported-milliseconds"),
        pytest.param("1H", id="uppercase-hours"),
        pytest.param("30M", id="uppercase-minutes"),
        pytest.param("45S", id="uppercase-seconds"),
        pytest.param("1hour", id="spelled-out-unit"),
        pytest.param("1:30:00", id="clock-format"),
        pytest.param("-1h", id="negative-value"),
        pytest.param("+1h", id="explicit-positive-sign"),
        pytest.param("1.5h", id="fractional-value"),
        pytest.param("1e3s", id="scientific-notation"),
        pytest.param("1,000s", id="comma-separated-number"),
        pytest.param("1_000s", id="underscore-separated-number"),
    ],
)
def test_parse_duration_rejects_invalid_values_and_units(duration):
    with pytest.raises(ValueError):
        parse_duration(duration)


@pytest.mark.parametrize(
    "duration",
    [
        pytest.param("30m1h", id="minutes-before-hours"),
        pytest.param("45s1m", id="seconds-before-minutes"),
        pytest.param("1s1h", id="seconds-before-hours"),
        pytest.param("1h2h", id="repeated-hours"),
        pytest.param("1m2m", id="repeated-minutes"),
        pytest.param("1s2s", id="repeated-seconds"),
        pytest.param("1h2m3h", id="hours-repeated-after-minutes"),
    ],
)
def test_parse_duration_rejects_reordered_or_repeated_units(duration):
    with pytest.raises(ValueError):
        parse_duration(duration)


@pytest.mark.parametrize(
    "duration",
    [
        pytest.param("1 h", id="space-before-unit"),
        pytest.param("1h 30m", id="space-between-components"),
        pytest.param("1h\t30m", id="internal-tab"),
        pytest.param("1h\n30m", id="internal-newline"),
        pytest.param("1h,30m", id="comma-between-components"),
        pytest.param("1h+30m", id="plus-between-components"),
        pytest.param("about1h", id="leading-text"),
        pytest.param("1h30mextra", id="trailing-text"),
        pytest.param("1h!", id="trailing-punctuation"),
        pytest.param("1h\x00", id="trailing-null"),
    ],
)
def test_parse_duration_rejects_internal_separators_and_extra_characters(duration):
    with pytest.raises(ValueError):
        parse_duration(duration)
```