using GitConverter.Lib.Factories; using GitConverter.Lib.Models; using GitConverter.TestsApp.TestSupport; namespace GitConverter.TestsApp.Converters { /// /// Integration-style tests for Shapefile conversion flows. /// /// /// Purpose /// - Exercise end-to-end Shapefile conversion using the real ConversionService and ShapefileConverter /// against small sample archives placed under TestData\Shapefile. /// /// Behavior & expectations /// - Tests are defensive: they skip when no TestData is present so CI remains non-fatal. /// - For each sample the tests create isolated output and temp folders under a unique temp root. /// - When ShapefileConverter returns Success the test asserts that at least one file /// was created inside the output folder. When the result is Failure the test asserts a non-empty /// diagnostic message is present. /// /// Test data /// - Place representative, small shapefile archives (.7z or .zip) under TestData\Shapefile in the test project /// and mark them with CopyToOutputDirectory=PreserveNewest so they are available at runtime via AppContext.BaseDirectory. /// /// Notes /// - Integration tests avoid asserting exact filenames; they verify that outputs exist. When asserting suffixes /// prefer FileExtensionHelpers.FromOption(...) + ToDotExtension() to compute expectations. /// - Tests intentionally pass the detected source format to Convert so converters that vary behavior by source /// format can use that information. /// [Collection("Integration")] public class ShapefileConverterIntegrationTests : IDisposable { private readonly string _root; public ShapefileConverterIntegrationTests() { _root = Path.Combine(Path.GetTempPath(), "GitConverter.ShapefileTests", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(_root); } public void Dispose() { try { if (Directory.Exists(_root)) Directory.Delete(_root, true); } catch { } } private static string TestDataShapefileFolder => IntegrationTestConstants.TestDataShapefileFolder; /// /// Execute Shapefile conversion against the first available shapefile archive found under the configured test data folder. /// /// /// Preconditions: /// - Small shapefile archives (.7z or .zip) must be present under and copied to test output. /// /// Test steps: /// 1. Locate the first *.7z or *.zip archive under the test data folder. If none exists the test is skipped (no failure). /// 2. Use to resolve a converter for the input archive. A failed detection is treated /// as a test failure (indicates misconfiguration or regression in detection logic). /// 3. For each supported targetFormatOption from : /// a. Create isolated output and temp directories under the per-test temp root. /// b. Invoke the converter's Convert method with the input, detected source format, target, output and temp paths. /// c. On success (ConversionResult.IsSuccess == true) assert that one or more files were written to the output directory. /// d. On failure assert that the returned ConversionResult.Message is non-empty and fail the test with that message. /// /// Cleanup: /// - Output and temp folders created for a target are deleted in a finally block to avoid leaving artifacts. /// /// Logging & diagnostics: /// - Converters emit diagnostics via the configured logging adapter; this test surface captures filesystem outputs /// and conversion results to determine pass/fail. /// /// Determinism: /// - Tests deliberately do not assert on exact output filenames to remain resilient to implementation changes. /// - Sample artifacts should be small to keep tests fast and reliable in CI. /// [Fact(DisplayName = "ShapefileConverter.Convert direct call against first archive (if present)")] public void Convert_SingleShapefileArchive_ToAllTargetOptions() { if (!Directory.Exists(TestDataShapefileFolder)) return; var sample = Directory.EnumerateFiles(TestDataShapefileFolder, "*", SearchOption.TopDirectoryOnly) .FirstOrDefault(f => f.EndsWith(".7z", StringComparison.OrdinalIgnoreCase) || f.EndsWith(".zip", StringComparison.OrdinalIgnoreCase)); if (sample == null) return; var factory = new ConverterFactory(); foreach (var targetFormatOption in IntegrationTestConstants.TargetOptions) { var outDir = Path.Combine(_root, $"{Path.GetFileNameWithoutExtension(sample)}_{targetFormatOption}_out"); var tempDir = Path.Combine(_root, $"{Path.GetFileNameWithoutExtension(sample)}_{targetFormatOption}_tmp"); Directory.CreateDirectory(outDir); Directory.CreateDirectory(tempDir); try { // Resolve a converter for the input archive; treat detection failure as a test failure. if (!factory.TryCreateForInput(sample, out var converter, out var detectedSourceFormat, out var detectReason) || converter == null) { throw new Xunit.Sdk.XunitException($"Failed to detect converter for '{sample}': {detectReason ?? ""}"); } // Execute conversion. Pass detectedSourceFormat so converters with source-specific behavior can use it. ConversionResult result = converter.Convert(sample, detectedSourceFormat, "Csv", outDir, tempDir); Assert.NotNull(result); if (result.IsSuccess) { var files = Directory.EnumerateFiles(outDir, "*", SearchOption.AllDirectories).ToList(); Assert.True(files.Count > 0, $"No output files for target format option '{targetFormatOption}' when converting '{sample}'."); } else { // On failure ensure a diagnostic message is present and fail clearly. Assert.False(string.IsNullOrWhiteSpace(result.Message), $"Conversion to '{targetFormatOption}' failed with empty message ({sample})."); throw new Xunit.Sdk.XunitException($"Conversion to '{targetFormatOption}' failed: {result.Message ?? ""} ({sample})."); } } finally { try { if (Directory.Exists(outDir)) Directory.Delete(outDir, true); } catch { } try { if (Directory.Exists(tempDir)) Directory.Delete(tempDir, true); } catch { } } } } } }