using FrameProcessor.Configuration; using FrameProcessor.Domain; using FrameProcessor.Storage; using Microsoft.Extensions.Options; namespace FrameProcessor.Tests; public class ImageStoreTests : IDisposable { private readonly string _directory; public ImageStoreTests() { _directory = Path.Combine(Path.GetTempPath(), "frame-processor-tests", Guid.NewGuid().ToString("N")); } public void Dispose() { if (Directory.Exists(_directory)) { Directory.Delete(_directory, recursive: true); } } [Fact] public void Constructor_CreatesImageDirectoryIfMissing() { Assert.False(Directory.Exists(_directory)); _ = CreateStore(); Assert.True(Directory.Exists(_directory)); } [Fact] public async Task WriteAsync_PersistsBytesAtMacKeyedPath() { var store = CreateStore(); var mac = MacAddress.Parse("AA:BB:CC:DD:EE:FF"); var payload = new byte[] { 0xDE, 0xAD, 0xBE, 0xEF }; await store.WriteAsync(mac, payload, CancellationToken.None); var expectedPath = Path.Combine(_directory, "aabbccddeeff.png"); Assert.True(File.Exists(expectedPath)); Assert.Equal(payload, await File.ReadAllBytesAsync(expectedPath)); } [Fact] public async Task WriteAsync_RemovesTempFileAfterRename() { var store = CreateStore(); var mac = MacAddress.Parse("aabbccddeeff"); await store.WriteAsync(mac, new byte[] { 0x01 }, CancellationToken.None); Assert.False(File.Exists(Path.Combine(_directory, "aabbccddeeff.png.tmp"))); } [Fact] public async Task WriteAsync_OverwritesPreviousImage() { var store = CreateStore(); var mac = MacAddress.Parse("aabbccddeeff"); await store.WriteAsync(mac, new byte[] { 0x01, 0x02 }, CancellationToken.None); await store.WriteAsync(mac, new byte[] { 0x09, 0x08, 0x07 }, CancellationToken.None); var path = Path.Combine(_directory, "aabbccddeeff.png"); Assert.Equal(new byte[] { 0x09, 0x08, 0x07 }, await File.ReadAllBytesAsync(path)); } [Fact] public async Task WriteAsync_OverwritesStaleTempFileFromPriorCrash() { Directory.CreateDirectory(_directory); var stalePath = Path.Combine(_directory, "aabbccddeeff.png.tmp"); await File.WriteAllBytesAsync(stalePath, new byte[] { 0xFF, 0xFF }); var store = CreateStore(); await store.WriteAsync(MacAddress.Parse("aabbccddeeff"), new byte[] { 0x01 }, CancellationToken.None); Assert.False(File.Exists(stalePath)); Assert.Equal(new byte[] { 0x01 }, await File.ReadAllBytesAsync(Path.Combine(_directory, "aabbccddeeff.png"))); } [Fact] public void TryGetPath_ReturnsFalseWhenAbsent() { var store = CreateStore(); var found = store.TryGetPath(MacAddress.Parse("aabbccddeeff"), out var path); Assert.False(found); Assert.Null(path); } [Fact] public async Task TryGetPath_ReturnsPathAfterWrite() { var store = CreateStore(); var mac = MacAddress.Parse("aabbccddeeff"); await store.WriteAsync(mac, new byte[] { 0x01 }, CancellationToken.None); var found = store.TryGetPath(mac, out var path); Assert.True(found); Assert.Equal(Path.Combine(_directory, "aabbccddeeff.png"), path); } private ImageStore CreateStore() => new(Options.Create(new StorageOptions { ImageDirectory = _directory })); }