# CLAUDE.md - DeepDrftTests

Guidance for working in the DeepDrftTests project (the test suite).

See the root `CLAUDE.md` for full architecture overview. This file covers what is specific to this project.

## One-line purpose

NUnit test project. Covers the FileDatabase subsystem end-to-end (the only piece of the codebase with non-trivial test coverage). References `DeepDrftContent.Services`.

## Layout

```
DeepDrftTests/
├── FileDatabaseTests.cs                # Main FileDatabase integration tests
├── MediaVaultTests.cs                  # MediaVault component tests
├── MediaVaultFactoryTests.cs           # Factory pattern tests
├── IndexSystemTests.cs                 # Index management tests
├── SimpleMediaTypeRegistryTests.cs     # Media type registry tests
├── UtilityTests.cs                     # Utility class tests (StructuralMap, FileUtils, etc.)
├── ModelTests.cs                       # Model validation tests
├── TestData.cs                         # Shared test fixtures and helpers
├── environment/
│   └── filedatabase.json               # Test-config FileDatabase settings
└── DeepDrftTests.csproj
```

## Test isolation strategy

Each test creates a unique directory under `Path.GetTempPath() + "DeepDrftTests/{Guid}"` in `[SetUp]` and best-effort deletes it in `[TearDown]`.

```csharp
[SetUp]
public void SetUp()
{
    _testDatabasePath = Path.Combine(
        Path.GetTempPath(),
        "DeepDrftTests",
        Guid.NewGuid().ToString());
    Directory.CreateDirectory(_testDatabasePath);
}

[TearDown]
public void TearDown()
{
    try { Directory.Delete(_testDatabasePath, recursive: true); }
    catch { /* Best-effort cleanup — ignore failures */ }
}
```

**New tests touching the filesystem must follow this pattern.** Do not write into the real `Database/Vaults` path. Do not use `[SetUp]` in base classes without allowing derived classes to override — some tests need custom setup.

## Core test classes

### FileDatabaseTests

Integration tests for the main FileDatabase functionality:
- Database creation and initialization at a specified path.
- Vault management (create, retrieve, check existence).
- Resource operations (register, load, type safety, edge cases).
- Multi-vault scenarios.
- Error handling (e.g., load from non-existent vault returns null).

These are the load-bearing tests. When FileDatabase semantics change, **these tests anchor the intent**. Update them in the same commit as the code change.

### MediaVaultTests

Component tests for individual vault implementations:
- Entry storage and retrieval.
- Media type handling (Audio, Image).
- File path sanitization (regex: `[^a-zA-Z0-9]` → `-`).
- Index maintenance (entries added/removed from vault index).

### IndexSystemTests

Index management validation:
- DirectoryIndex creation and persistence (JSON round-trip).
- VaultIndex type management (MediaVaultType recorded and rehydrated).
- IndexFactoryService operations.

### MediaVaultFactoryTests

Factory pattern validation:
- Vault creation for different `MediaVaultType` values.
- Path handling and directory creation.
- Type-specific vault instantiation.

### SimpleMediaTypeRegistryTests

Media type registry tests:
- Extension → MIME type mapping.
- Supported formats (wav, mp3, jpg, png, gif, etc.).

### UtilityTests

Utility class tests:
- `StructuralMap<TKey, TValue>` (JSON-based equality).
- `StructuralSet<T>` (set semantics with structural equality).
- `FileUtils` (async file I/O, chunked reading/writing).

### ModelTests

Model validation:
- Binary models can be created and serialized.
- DTOs round-trip correctly (serialize → deserialize).
- Metadata hierarchy is correct.

## TestData (shared fixtures)

Centralised test data and helper methods:

```csharp
public static class TestData
{
    // Real PNG byte buffer (16x16) — reused for mock audio testing
    public static readonly byte[] TestPngBytes = [/* 144 bytes */];

    // Factory methods
    public static ImageBinary CreateTestImageBinary(double aspectRatio = 1.0);
    public static AudioBinary CreateTestAudioBinary(double duration = 120.0, int bitrate = 320);

    // Named constants
    public static class TestKeys
    {
        public const string TestImageEntry = "test";
        public const string ImageVaultKey = "img";
        public const MediaVaultType ImageVaultType = MediaVaultType.Image;
    }
}
```

**Important**: `TestData.CreateTestAudioBinary` deliberately reuses PNG bytes as a mock audio buffer. The FileDatabase does not parse audio content — it stores any bytes with the metadata. Real WAV parsing is exercised by the CLI and content host, not the FileDatabase tests.

## Run commands

```bash
# Run all tests
dotnet test DeepDrftTests/

# Run with detailed output
dotnet test DeepDrftTests/ --verbosity normal

# Run specific test class
dotnet test DeepDrftTests/ --filter "ClassName=FileDatabaseTests"

# Run specific test method
dotnet test DeepDrftTests/ --filter "Name=FileDatabase_CanBeCreatedAtSpecifiedLocation"

# Run with code coverage (if tooling is installed)
dotnet test DeepDrftTests/ --collect:"XPlat Code Coverage"
```

## Testing patterns

### Async test methods

All database operations tested with async/await:

```csharp
[Test]
public async Task FileDatabase_CanRegisterAndRetrieveAudio()
{
    var fileDatabase = await FileDatabase.FromAsync(_testDatabasePath);
    var audio = new AudioBinary(/* params */);
    var registered = await fileDatabase.RegisterResourceAsync("tracks", "test-entry", audio);
    Assert.That(registered, Is.True);
    var loaded = await fileDatabase.LoadResourceAsync<AudioBinary>("tracks", "test-entry");
    Assert.That(loaded, Is.Not.Null);
}
```

### Type-safe media testing

Generic type parameters ensure type safety:

```csharp
var audio = await fileDatabase.LoadResourceAsync<AudioBinary>("tracks", trackId);
Assert.That(audio, Is.Not.Null);
Assert.That(audio.Duration, Is.EqualTo(120.0));
Assert.That(audio.Bitrate, Is.EqualTo(320));
```

### Error scenario coverage

Tests validate the error-swallowing contract:

```csharp
// Load from non-existent vault returns null
var result = await fileDatabase.LoadResourceAsync<AudioBinary>("non-existent", "entry");
Assert.That(result, Is.Null);

// Register to non-existent vault returns false (after creating it? depends on semantics — check code)
```

## Important testing principles

### The tests are the load-bearing documentation

When FileDatabase semantics change, especially:
- The swallow-and-return-null contract
- Entry-key sanitisation regex
- Vault-type round-trip on index
- Index-watcher reload

...the tests are where intent is anchored. Update them in the same commit as the code change.

### Authentic test data

Uses real PNG bytes instead of mock data for realistic testing scenarios. The FileDatabase doesn't care about actual audio/image content — it stores opaque buffers. But using real bytes makes the tests less misleading.

### Comprehensive coverage

Tests cover:
- Happy path scenarios (create, register, load, list).
- Edge cases (empty vault, non-existent entry, sanitisation edge cases).
- Type safety and generics.
- Async operation patterns.
- File system interactions (directory creation, file I/O, index JSON round-trip).

### Performance

Tests are designed for speed:
- Minimal test data sizes.
- Parallel test execution support (via temp directory isolation).
- Efficient cleanup.

## What is NOT tested

Be honest about coverage gaps:

- `TrackService` (Web or Content).
- `TrackController` (Web or Content).
- `TrackClient` / `TrackMediaClient` (HTTP clients).
- The audio player services (streaming, seek, interop).
- Dark-mode round-trip (cookie → settings → persistent state).
- `AudioProcessor` (WAV parsing, metadata extraction).

Any planned work in those areas should consider whether tests need to land alongside. **Testing the FileDatabase thoroughly does not mean testing everything** — it means testing the part that is most likely to break.

## Development commands

```bash
# Build
dotnet build DeepDrftTests/

# Run all tests
dotnet test DeepDrftTests/

# Run with live output
dotnet test DeepDrftTests/ -v normal

# Run a single test class
dotnet test DeepDrftTests/ --filter "ClassName=FileDatabaseTests"

# Clean test artifacts
dotnet clean DeepDrftTests/
```

## Configuration

- `environment/filedatabase.json`: Test-config FileDatabase settings (copied to output at build).
- `TestData.cs`: Centralised fixtures and helpers. Use these rather than duplicating test data.

When working with this project, treat the tests as the load-bearing specification of FileDatabase behaviour. When in doubt, read the tests first — they are clearer than the code.
