# Foundry Factories for MineSeeker

Factory classes for creating test data. For general Foundry usage, see [Zenstruck Foundry Docs](https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html).

---

## Available Factories

All factories are in `tests/Factory/`:

| Factory | Entity | Use For |
|---------|--------|---------|
| `UserFactory` | `User` | Registered users with auth |
| `GamerFactory` | `Gamer` | Anonymous/guest players |
| `PlayedGameFactory` | `PlayedGame` | Game records |
| `StepFactory` | `Step` | Individual game moves |
| `GridFactory` | `Grid` | 16×16 game grids |
| `GridRowFactory` | `GridRow` | Grid row data |
| `WebAuthnCredentialFactory` | `WebAuthnCredential` | Passkey credentials |
| `ContactMessageFactory` | `ContactMessage` | Contact form messages |

---

## Quick Examples

### UserFactory

```php
// Basic user
$user = UserFactory::createOne();

// Unverified user
$user = UserFactory::createOne(['isVerified' => false]);

// Admin user
$user = UserFactory::createOne(['roles' => ['ROLE_ADMIN']]);

// Multiple users
UserFactory::createMany(5);
```

### GamerFactory

```php
// Anonymous gamer
$gamer = GamerFactory::new()->anonymous()->create();
```

### PlayedGameFactory

```php
// Game with registered players
$game = PlayedGameFactory::new()
    ->withRegisteredPlayers()
    ->create();

// Game with anonymous players
$game = PlayedGameFactory::new()
    ->withAnonymousPlayers()
    ->create();

// Red wins
$game = PlayedGameFactory::new()
    ->withRegisteredPlayers()
    ->redWins()
    ->create();

// Blue wins
$game = PlayedGameFactory::new()
    ->withRegisteredPlayers()
    ->blueWins()
    ->create();

// Resigned game
$game = PlayedGameFactory::new()
    ->resigned('red')
    ->create();
```

### StepFactory

```php
// Mine hit
$step = StepFactory::new()
    ->forPlayer('red')
    ->mine()
    ->create(['playedGame' => $game]);

// Safe cell
$step = StepFactory::new()
    ->forPlayer('blue')
    ->safe()
    ->create(['playedGame' => $game]);

// With revealed cells
$step = StepFactory::new()
    ->withRevealedCells([
        ['row' => 5, 'col' => 5],
        ['row' => 5, 'col' => 6],
    ])
    ->create(['playedGame' => $game]);
```

### GridFactory

```php
// Full 16×16 grid
$grid = GridFactory::createOne(['playedGame' => $game]);

// Automatically creates 16 rows
self::assertCount(16, $grid->gridRow);
```

### WebAuthnCredentialFactory

```php
// Basic credential
$credential = WebAuthnCredentialFactory::createOne(['user' => $user]);

// Named credential, recently used
$credential = WebAuthnCredentialFactory::new()
    ->withName('YubiKey 5C')
    ->recentlyUsed()
    ->create(['user' => $user]);
```

### ContactMessageFactory

```php
// Basic message
$message = ContactMessageFactory::createOne();

// Without consent
$message = ContactMessageFactory::new()
    ->withoutConsent()
    ->create();
```

---

## Factory API Reference

### Common Methods (All Factories)

```php
// Create single entity
Factory::createOne([
    'property' => 'value',
]);

// Create multiple
Factory::createMany(5);

// Create with factory methods
Factory::new()
    ->customMethod()
    ->create(['property' => 'value']);

// Access repository
Factory::repository()->findAll();
Factory::repository()->count([]);
Factory::repository()->findBy(['field' => 'value']);
```

### PlayedGameFactory Methods

| Method | Description |
|--------|-------------|
| `withRegisteredPlayers()` | Creates game with 2 registered users |
| `withAnonymousPlayers()` | Creates game with 2 anonymous gamers |
| `withMixedPlayers()` | One registered, one anonymous |
| `redWins()` | Red has 26 points |
| `blueWins()` | Blue has 26 points |
| `resigned(string $player)` | Set resignation ('red' or 'blue') |

### StepFactory Methods

| Method | Description |
|--------|-------------|
| `forPlayer(string $player)` | Set player ('red' or 'blue') |
| `mine()` | Step hits a mine |
| `safe()` | Step reveals safe cell |
| `withRevealedCells(array $cells)` | Set revealed cells array |

### GamerFactory Methods

| Method | Description |
|--------|-------------|
| `anonymous()` | Set username as "Guest_12345" |

### WebAuthnCredentialFactory Methods

| Method | Description |
|--------|-------------|
| `withName(string $name)` | Set credential name |
| `recentlyUsed()` | Set lastUsedAt to now |

### ContactMessageFactory Methods

| Method | Description |
|--------|-------------|
| `withoutConsent()` | Set consent to false |
| `anonymous()` | Remove IP address |

---

## MineSeeker-Specific Patterns

### Complete Game Setup

```php
// Create full game with steps and grid
$game = PlayedGameFactory::new()
    ->withRegisteredPlayers()
    ->create();

// Add steps
StepFactory::createMany(10, [
    'playedGame' => $game,
    'player' => 'red',
]);

// Add grid
$grid = GridFactory::createOne(['playedGame' => $game]);
```

### Testing Battle History

```php
// Create multiple finished games for a user
$user = UserFactory::createOne();

PlayedGameFactory::new()
    ->redWins()
    ->create(['red' => $user]);

PlayedGameFactory::new()
    ->blueWins()
    ->create(['blue' => $user]);
```

---

## Database Isolation

Tests automatically run in isolated transactions:

```php
public function testDatabaseIsolation(): void
{
    UserFactory::createMany(5);
    self::assertCount(5, UserFactory::repository()->findAll());
    
    // Automatically rolled back after test
}
```

No manual cleanup needed. Each test starts with a clean database.

---

## External Resources

- **[Zenstruck Foundry Documentation](https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html)** - Complete Foundry guide
- **[DAMA Doctrine Test Bundle](https://github.com/dmaicher/doctrine-test-bundle)** - Transaction isolation details
