# Table-Driven Test Generator

Generate complete Vitest/Jest/pytest table-driven tests for any function. Covers happy path, boundary values, null/undefined, async rejection, and type edge cases. Ready to run, zero placeholder text.

## Quick Reference

# Table-Driven Test Generator

> **Purpose:** Generate a complete, runnable test file for any function using table-driven tests (`it.each` / `test.each` in Vitest/Jest, parametrize in pytest). Covers: happy path, boundary values, null/undefined inputs, empty collections, async rejection, and type coercion edge cases. Output can be pasted directly into a `.test.ts` or `_test.py` file and run immediately.

---

## Invocation

```
/test <function-signature-and-implementation>
```

**Examples:**
- `/test function add(a: number, b: number): number { return a + b }`
- `/test async function fetchUser(id: string): Promise<User | null>`
- `/test def calculate_discount(price: float, pct: float) -> float:`

---

## Process

### Step 1: Analyze the Function

Identify:
- **Inputs**: types, constraints, optional vs required
- **Output**: return type, possible return values
- **Side effects**: async operations, mutations, I/O
- **Failure modes**: throws, returns null, rejects, etc.

---

### Step 2: Design Test Cases

For every function, generate tests covering:

| Category | Examples |
|----------|---------|
| Happy path | Typical inputs, expected output |
| Boundary — low | 0, -1, empty string, empty array |
| Boundary — high | MAX_SAFE_INTEGER, very long string, large array |
| Null / undefined | null, undefined, missing optional param |
| Type edge cases | NaN, Infinity, 0.1 + 0.2 floating point |
| Async rejection | Network error, timeout, invalid response |
| Error path | Invalid input → throws specific error |
| Idempotency | Same input twice → same output |

---

### Step 3: Write the Test File

**Vitest / Jest output:**

```typescript
import { describe, it, expect, vi } from 'vitest'
import { functionName } from './module'

describe('functionName', () => {
  it.each([
    // [description, input1, input2, ..., expected]
    ['happy path: typical inputs', arg1, arg2, expectedOutput],
    ['boundary: zero value', 0, arg2, expectedForZero],
    ['boundary: negative', -1, arg2, expectedForNegative],
    ['null input: first arg null', null, arg2, expectedForNull],
  ])('%s', (description, input1, input2, expected) => {
    // Arrange
    const input = buildInput(input1, input2)

    // Act
    const result = functionName(input1, input2)

    // Assert
    expect(result).toEqual(expected)
  })

  it('throws on invalid input', () => {
    // Arrange + Act + Assert
    expect(() => functionName(invalidInput)).toThrow('Expected error message')
  })

  it('handles async rejection gracefully', async () => {
    // Arrange
    vi.mocked(dependency).mockRejectedValue(new Error('Network error'))

    // Act + Assert
    await expect(functionName(input)).rejects.toThrow('Network error')
  })
})
```

**pytest output:**

```python
import pytest
from module import function_name

@pytest.mark.parametrize("description,input_val,expected", [
    ("happy path: typical input", typical_input, expected_output),
    ("boundary: zero", 0, expected_for_zero),
    ("boundary: negative", -1, expected_for_neg),
    ("None input", None, expected_for_none),
])
def test_function_name(description, input_val, expected):
    # Arrange + Act
    result = function_name(input_val)

    # Assert
    assert result == expected, f"Failed: {description}"

def test_function_name_raises_on_invalid():
    with pytest.raises(ValueError, match="Expected message"):
        function_name(invalid_input)
```

---

## Rules

- Every test must follow AAA (Arrange / Act / Assert) with comment labels
- The table must have at least 5 rows: 1 happy path + 4 edge cases
- Async functions must include at least one rejection test
- No placeholder text in the output — all test values must be concrete
- If the function has side effects (DB write, HTTP call): add a mock setup block
- Output must be runnable as-is — the only acceptable TODO is "fill in real mock return value"
- Detect framework from function syntax: TypeScript → Vitest, Python → pytest, Go → `testing.T` table tests

## Playground

<!DOCTYPE html><html><head><meta charset='utf-8'><style>*{box-sizing:border-box;margin:0;padding:0}body{background:#0d1117;color:#e6edf3;font-family:monospace;font-size:12px;height:100vh;display:flex;flex-direction:column;overflow:hidden}.header{background:#161b22;border-bottom:1px solid #30363d;padding:8px 14px;font-size:11px;color:#8b949e;display:flex;justify-content:space-between;align-items:center;flex-shrink:0}.title{color:#58a6ff;font-weight:bold;font-size:13px}.panels{display:flex;flex:1;overflow:hidden}.panel{flex:1;overflow:auto;padding:12px;border-right:1px solid #30363d}.panel:last-child{border-right:none}.label{font-size:10px;color:#8b949e;text-transform:uppercase;letter-spacing:.08em;margin-bottom:6px}pre{white-space:pre-wrap;word-break:break-word;line-height:1.5}</style></head><body><div class='header'><span class='title'>Table-Driven Test Generator</span><span>Example · SkillSlap</span></div><div class='panels'><div class='panel'><div class='label'>Input: Go function</div><pre><span style='color:#8b949e'>func Clamp(v, min, max int) int {</span>
<span style='color:#8b949e'>    if v &lt; min { return min }</span>
<span style='color:#8b949e'>    if v &gt; max { return max }</span>
<span style='color:#8b949e'>    return v</span>
<span style='color:#8b949e'>}</span></pre></div><div class='panel'><div class='label'>Output: Table-driven tests</div><pre><span style='color:#58a6ff'>func TestClamp(t *testing.T) {</span>
<span style='color:#8b949e'>  tests := []struct{</span>
<span style='color:#8b949e'>    name     string</span>
<span style='color:#8b949e'>    v,mn,mx  int</span>
<span style='color:#8b949e'>    want     int</span>
<span style='color:#8b949e'>  }{</span>
<span style='color:#8b949e'>    {"below min", -5, 0, 10, 0},</span>
<span style='color:#8b949e'>    {"above max", 15, 0, 10, 10},</span>
<span style='color:#8b949e'>    {"in range",   5, 0, 10,  5},</span>
<span style='color:#8b949e'>    {"at min",     0, 0, 10,  0},</span>
<span style='color:#8b949e'>    {"at max",    10, 0, 10, 10},</span>
<span style='color:#8b949e'>  }</span>

<span style='color:#8b949e'>  for _, tc := range tests {</span>
<span style='color:#8b949e'>    t.Run(tc.name, func(t *testing.T) {</span>
<span style='color:#8b949e'>      got := Clamp(tc.v, tc.mn, tc.mx)</span>
<span style='color:#8b949e'>      if got != tc.want {</span>
<span style='color:#8b949e'>        t.Errorf("got %d want %d",</span>
<span style='color:#8b949e'>          got, tc.want)</span>
<span style='color:#8b949e'>      }</span>
<span style='color:#8b949e'>    })</span>
<span style='color:#8b949e'>  }</span>
<span style='color:#8b949e'>}</span></pre></div></div></body></html>
