# 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` (JSON-based equality). - `StructuralSet` (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("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("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("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.