using System; using Paca.Mobile.Core; using Xunit; namespace Paca.Tests.Core; public class ThumbnailScrubberPreviewGateTests { [Fact] public void Gate241_ThumbnailScrubberPreview_CalculatesTimestamp_AndFormatsProperly() { Assert.Equal("00:45", ThumbnailScrubberPreview.FormatTimestamp(45.2)); Assert.Equal("01:01:05", ThumbnailScrubberPreview.FormatTimestamp(3665.0)); Assert.Equal("00:00", ThumbnailScrubberPreview.FormatTimestamp(0)); } [Fact] public void Gate242_ThumbnailScrubberPreview_CalculatesThumbnailUrl_WithSeekQuery() { var preview = new ThumbnailScrubberPreview("media-123", totalDurationSec: 200.0); var url = preview.GetPreviewUrlForRatio(0.5); // 100s Assert.Contains("/api/library/media-123/thumb", url); Assert.Contains("t=100", url); } [Fact] public void Gate243_ThumbnailScrubberPreview_ClampsSeekPositionWithinBounds() { var preview = new ThumbnailScrubberPreview("media-999", totalDurationSec: 100.0); // Underflow clamp var underflowTime = preview.GetClampedSeekTime(-0.1); Assert.Equal(0.0, underflowTime); // Overflow clamp var overflowTime = preview.GetClampedSeekTime(1.5); Assert.Equal(100.0, overflowTime); } [Fact] public void Gate244_ThumbnailScrubberPreview_LruCache_EvictsOldestWhenLimitReached() { var cache = new ScrubberPreviewCache(capacity: 3); cache.Put("t=10", new byte[] { 1 }); cache.Put("t=20", new byte[] { 2 }); cache.Put("t=30", new byte[] { 3 }); Assert.True(cache.TryGet("t=10", out _)); Assert.True(cache.TryGet("t=20", out _)); Assert.True(cache.TryGet("t=30", out _)); // Add 4th item, oldest accessed was t=10 before t=20/t=30, now add t=40 cache.Put("t=40", new byte[] { 4 }); Assert.Equal(3, cache.Count); // t=40 is in cache Assert.True(cache.TryGet("t=40", out _)); } }