# Converter tests — GitConverter.TestsApp.Factories This document describes testing guidance and helpers for unit tests that exercise the factory subsystem (`ConverterFactory`, `FactoryHelpers`, and related test helpers) in a lightweight, deterministic manner. Goals - Validate tolerant lookup and suggestion logic for human-facing conversion option keys. - Provide small, injectable registration maps so unit tests avoid instantiating heavy converter implementations (Aspose drivers, file I/O etc.). - Assert logging behavior for diagnostic scenarios (lookup misses, suggestions, duplicate registrations and factory delegate failures). What belongs here - Unit tests for `ConverterFactory` (Create / TryCreate / GetSupportedOptions). - Unit tests for `FactoryHelpers` (NormalizeKey, SuggestClosest, LevenshteinDistance). - Tests that assert logging behavior using the `TestLogger` and `LogAssert` helpers. - Lightweight fake converters and factories used to isolate detection and routing logic from conversion work. Patterns and best practices - Use explicit registrations for unit tests - Construct `ConverterFactory` with a small `Dictionary>` and a `TestLogger` to avoid instantiating built-in converters: `new ConverterFactory(registrations, testLogger)`. - Keys in the registrations dictionary may contain comma-separated aliases (the production factory supports this), but tests typically register single keys for clarity. - Test both APIs - Prefer `TryCreate(format, out converter)` for CLI-like, non-throwing behavior assertions. - Use `Create(format)` in tests that assert exception messages and suggestion text when an option is unsupported. - Normalize and suggestion behavior - Write tests that exercise normalization tolerance: case, punctuation, surrounding quotes and spacing. - Test suggestion behavior (`SuggestClosest`) using near-miss inputs (1-3 edits) and ensure no suggestion is returned for distant strings. - Logging assertions - Use `TestLogger` to capture logs and `LogAssert.ContainsMessage(logger, level, token)` to assert on tokens. - Prefer asserting the presence of a token (case-insensitive) rather than the full message text to keep tests resilient. - Key scenarios to assert: - Debug-level lookup miss when `TryCreate` cannot find a key. - Warn-level suggestion when `Create` throws and a close match exists. - Error-level message on duplicate registration during construction. - Warn-level message when a factory delegate throws during `TryCreate`. - Debug-level instantiation message when `TryCreate` succeeds. Examples - Simple registration map for tests: ```csharp var registrations = new Dictionary> { { "FakeFmt", () => new FakeConverter() } }; var logger = new TestLogger(); var factory = new ConverterFactory(registrations, logger); ``` - Typical assertions in tests: ```csharp // Non-throwing lookup Assert.True(factory.TryCreate("FakeFmt", out var converter)); Assert.NotNull(converter); // Suggestion path var ex = Assert.Throws(() => factory.Create("faekfmt")); Assert.Contains("Did you mean", ex.Message, StringComparison.OrdinalIgnoreCase); // Logging LogAssert.ContainsMessage(logger, LogLevel.Warn, "suggest"); ``` Additional test types to add - Detection tests that ensure `FactoryHelpers.SuggestClosest` thresholds behave correctly for various lengths. - Logging tests that assert registration summary and per-registration debug messages are emitted on construction. - Tests for alias registration handling (comma-separated aliases) and collision detection. CI and performance notes - Keep unit tests fast and pure (no network, minimal file I/O). Use explicit registration injection to avoid heavy dependencies. - Integration tests that require sample artifacts belong under `GitConverter.TestsApp` `TestData` folders and are guarded to skip when samples are missing. Troubleshooting - `ArgumentException` during test setup when constructing the registrations dictionary typically means the same normalized key was added twice. To reproduce the factory's duplicate-key detection in tests, use a case-sensitive dictionary (e.g. `StringComparer.Ordinal`) when adding both `"Dup"` and `"dup"` so the factory's normalization logic reports the collision. - If a logging assertion fails, dump `TestLogger` messages to the test output to inspect the exact tokens emitted. Adding new tests 1. Prefer unit tests over integration tests for factory logic. Unit tests should inject registrations and a `TestLogger`. 2. For detection-related tests (e.g., JSON voting) create small temporary files/archives under a unique temp folder and clean them up in `Dispose`. 3. When adding tests that assert log messages choose robust tokens (e.g., "duplicate registration", "instantiated converter") rather than full messages. Contact - Open issues for flaky tests or changes in normalization/suggestion heuristics. Include failing test output and any relevant captured logs.