◐ Off-By-One · answer catalog

test-property-based-shrinking

2 answer(s)pythonpython3pythonpython3

listgen = Gen.listof(Gen.integer(-5, 5), 0, 6)

📦 Source in repository (JSON)

Answer 1

The file ~/property_testing.py implements a full property-based testing library in ~550 lines of pure Python 3.11. It has three core abstractions:

1. Gen[T] — composable random generators

from property_testing import Gen

# Integer in range
int_gen = Gen.integer(-10, 10)

# List of integers (length 0–6)
list_gen = Gen.list_of(Gen.integer(-5, 5), 0, 6)

# Tuples, booleans, strings, etc.
pair_gen = Gen.tuple_of(Gen.boolean(), Gen.integer(1, 100))

# Combinators: map, flat_map, mapN, one_of, frequency, constant
even_gen = Gen.integer(0, 100).map(lambda n: n * 2)

2. Shrink[T] — greedy shrinking to minimal counterexamples

from property_testing import Shrink

si = Shrink.integer()
# Find smallest value >= 0 that satisfies predicate
smallest = si(100, failed=lambda x: x >= 0)  # → 0

sl = Shrink.list_of(Shrink.integer())
# Find shortest list with odd sum
smallest = sl([5, 3, 7], failed=lambda lst: sum(lst) % 2 == 1)

3. @for_all / Property — property runner with automatic shrinking

from property_testing import for_all, Gen

# The classic property: reverse(reverse(xs)) == xs
@for_all(gen=Gen.list_of(Gen.integer(-20, 20), 0, 10), trials=500)
def test_reverse_twice(xs: list) -> bool:
    return list(reversed(list(reversed(xs)))) == xs

result = test_reverse_twice()   # run it
# result.passed == True, result.trials == 500

Shrinking algorithm (greedy, bounded): 1. Start with the failing value found during random testing 2. Generate all "one-step-smaller" candidates via Shrink.candidates() 3. Take the first candidate that still fails the property and is strictly smaller 4. Repeat until no smaller failing candidate exists


Evidence & signatures

All tests pass via `~/test_property_testing.py`:

| Category | Tests | Result |
|---|---|---|
| **Gen edge cases** | empty lists, constant gen, booleans, one_of, frequency, mapN, tuples, strings | ✅ |
| **Shrinking** | integers (positive/negative/zero), booleans, lists (elements & length), nothing shrinker, empty lists | ✅ |
| **Property edge cases** | always-true, always-false (shrunk to minimal), empty list, exception raised = failure, multi-arg via tuples | ✅ |
| **Classic property** | `reverse(reverse(xs)) == xs` over 500 random lists, including manual `[]`, `[1]`, `[1,2,3]` | ✅ |
| **Shrink stability** | Wrong property `reverse(reverse(xs)) != xs` (deliberately buggy) always shrinks to minimal `[]` across 5 runs | ✅ |

Key edge cases verified:
- **`Gen.integer` with `lo == hi`**: produces constant values
- **Negative integer shrinking**: `-50` shrinks to `0` (no infinite loops)
- **Empty list shrinking**: stays `[]`
- **Exception-as-failure**: a property raising `ValueError` is treated as a failing test
- **`Shrink.nothing()`**: returns value unchanged (for unshrinkable types)
- **`Gen.one_of` / `Gen.frequency`**: correctly samples from weighted alternatives

---
{"model": "claude-3.5-sonnet", "problem_class": "test-property-based-shrinking", "result": "passed", "tests": 25}

Answer 2

The file ~/property_testing.py implements a full property-based testing library in ~550 lines of pure Python 3.11. It has three core abstractions:

1. Gen[T] — composable random generators

from property_testing import Gen

# Integer in range
int_gen = Gen.integer(-10, 10)

# List of integers (length 0–6)
list_gen = Gen.list_of(Gen.integer(-5, 5), 0, 6)

# Tuples, booleans, strings, etc.
pair_gen = Gen.tuple_of(Gen.boolean(), Gen.integer(1, 100))

# Combinators: map, flat_map, mapN, one_of, frequency, constant
even_gen = Gen.integer(0, 100).map(lambda n: n * 2)

2. Shrink[T] — greedy shrinking to minimal counterexamples

from property_testing import Shrink

si = Shrink.integer()
# Find smallest value >= 0 that satisfies predicate
smallest = si(100, failed=lambda x: x >= 0)  # → 0

sl = Shrink.list_of(Shrink.integer())
# Find shortest list with odd sum
smallest = sl([5, 3, 7], failed=lambda lst: sum(lst) % 2 == 1)

3. @for_all / Property — property runner with automatic shrinking

from property_testing import for_all, Gen

# The classic property: reverse(reverse(xs)) == xs
@for_all(gen=Gen.list_of(Gen.integer(-20, 20), 0, 10), trials=500)
def test_reverse_twice(xs: list) -> bool:
    return list(reversed(list(reversed(xs)))) == xs

result = test_reverse_twice()   # run it
# result.passed == True, result.trials == 500

Shrinking algorithm (greedy, bounded): 1. Start with the failing value found during random testing 2. Generate all "one-step-smaller" candidates via Shrink.candidates() 3. Take the first candidate that still fails the property and is strictly smaller 4. Repeat until no smaller failing candidate exists


Evidence & signatures

All tests pass via `~/test_property_testing.py`:

| Category | Tests | Result |
|---|---|---|
| **Gen edge cases** | empty lists, constant gen, booleans, one_of, frequency, mapN, tuples, strings | ✅ |
| **Shrinking** | integers (positive/negative/zero), booleans, lists (elements & length), nothing shrinker, empty lists | ✅ |
| **Property edge cases** | always-true, always-false (shrunk to minimal), empty list, exception raised = failure, multi-arg via tuples | ✅ |
| **Classic property** | `reverse(reverse(xs)) == xs` over 500 random lists, including manual `[]`, `[1]`, `[1,2,3]` | ✅ |
| **Shrink stability** | Wrong property `reverse(reverse(xs)) != xs` (deliberately buggy) always shrinks to minimal `[]` across 5 runs | ✅ |

Key edge cases verified:
- **`Gen.integer` with `lo == hi`**: produces constant values
- **Negative integer shrinking**: `-50` shrinks to `0` (no infinite loops)
- **Empty list shrinking**: stays `[]`
- **Exception-as-failure**: a property raising `ValueError` is treated as a failing test
- **`Shrink.nothing()`**: returns value unchanged (for unshrinkable types)
- **`Gen.one_of` / `Gen.frequency`**: correctly samples from weighted alternatives

---
{"model": "claude-3.5-sonnet", "problem_class": "test-property-based-shrinking", "result": "passed", "tests": 25}
Generated from the verified corpus · MIT licensedBack to the catalog