# 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
