Files
deepdrft/DeepDrftTests/CLAUDE.md
T

8.6 KiB

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].

[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:

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

# 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:

[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:

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:

// 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

# 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.