171 lines
5.9 KiB
C#
171 lines
5.9 KiB
C#
using Explorer.Application;
|
|
|
|
namespace Explorer.Application.Tests;
|
|
|
|
public class ThumbnailSchedulerTests
|
|
{
|
|
[Fact]
|
|
public void Only_window_items_are_queued_not_the_whole_directory()
|
|
{
|
|
var scheduler = new ThumbnailScheduler();
|
|
scheduler.Reset(1);
|
|
scheduler.SetEnabled(true);
|
|
var window = Enumerable.Range(0, 40)
|
|
.Select(i => Job($@"C:\v{i}.jpg", rank: 0))
|
|
.Concat(Enumerable.Range(0, 24).Select(i => Job($@"C:\p{i}.jpg", rank: 1)))
|
|
.ToList();
|
|
scheduler.SetWindow(1, window);
|
|
|
|
var taken = Drain(scheduler);
|
|
Assert.Equal(64, taken.Count);
|
|
Assert.DoesNotContain(taken, j => j.Key.Path.Contains(@"\rest", StringComparison.Ordinal));
|
|
Assert.True(taken.Take(40).All(j => j.Rank == 0));
|
|
Assert.Equal(0, scheduler.InFlight);
|
|
}
|
|
|
|
[Fact]
|
|
public void Visible_jobs_are_taken_before_prefetch()
|
|
{
|
|
var scheduler = new ThumbnailScheduler();
|
|
scheduler.Reset(1);
|
|
scheduler.SetEnabled(true);
|
|
scheduler.SetWindow(1,
|
|
[
|
|
Job(@"C:\far.jpg", rank: 1),
|
|
Job(@"C:\near.jpg", rank: 0)
|
|
]);
|
|
|
|
Assert.True(scheduler.TryTake(out var first));
|
|
Assert.Equal(@"C:\near.jpg", first.Key.Path);
|
|
Assert.True(scheduler.TryTake(out var second));
|
|
Assert.Equal(@"C:\far.jpg", second.Key.Path);
|
|
scheduler.Complete(first, generated: true, failed: false);
|
|
scheduler.Complete(second, generated: true, failed: false);
|
|
}
|
|
|
|
[Fact]
|
|
public void Scrolling_away_drops_obsolete_pending_work()
|
|
{
|
|
var scheduler = new ThumbnailScheduler();
|
|
scheduler.Reset(1);
|
|
scheduler.SetEnabled(true);
|
|
scheduler.SetWindow(1, [Job(@"C:\old.jpg")]);
|
|
scheduler.SetWindow(1, [Job(@"C:\new.jpg")]);
|
|
|
|
Assert.True(scheduler.TryTake(out var job));
|
|
Assert.Equal(@"C:\new.jpg", job.Key.Path);
|
|
Assert.False(scheduler.TryTake(out _));
|
|
Assert.True(scheduler.Snapshot().Cancelled > 0);
|
|
scheduler.Complete(job, generated: true, failed: false);
|
|
}
|
|
|
|
[Fact]
|
|
public void Navigation_generation_invalidates_previous_jobs()
|
|
{
|
|
var scheduler = new ThumbnailScheduler();
|
|
scheduler.Reset(1);
|
|
scheduler.SetEnabled(true);
|
|
scheduler.SetWindow(1, [Job(@"C:\a.jpg")]);
|
|
Assert.True(scheduler.TryTake(out var stale));
|
|
scheduler.Reset(2);
|
|
Assert.False(scheduler.IsCurrent(stale));
|
|
Assert.False(scheduler.TryTake(out _));
|
|
scheduler.SetWindow(2, [Job(@"C:\b.jpg", generation: 2)]);
|
|
Assert.True(scheduler.TryTake(out var next));
|
|
Assert.Equal(@"C:\b.jpg", next.Key.Path);
|
|
scheduler.Complete(next, generated: true, failed: false);
|
|
}
|
|
|
|
[Fact]
|
|
public void Cache_hit_skips_regeneration()
|
|
{
|
|
var scheduler = new ThumbnailScheduler();
|
|
scheduler.Reset(1);
|
|
scheduler.SetEnabled(true);
|
|
var key = ThumbnailKey.From(@"C:\hit.jpg", DateTimeOffset.UnixEpoch, 128);
|
|
scheduler.MarkCached(key);
|
|
scheduler.SetWindow(1, [new ThumbnailJob(key, 0, 1)]);
|
|
Assert.False(scheduler.TryTake(out _));
|
|
scheduler.RecordCacheHit();
|
|
Assert.Equal(1, scheduler.Snapshot().CacheHits);
|
|
}
|
|
|
|
[Fact]
|
|
public void Window_is_capped_so_the_queue_cannot_hold_the_whole_directory()
|
|
{
|
|
var scheduler = new ThumbnailScheduler();
|
|
scheduler.Reset(1);
|
|
scheduler.SetEnabled(true);
|
|
var huge = Enumerable.Range(0, 500).Select(i => Job($@"C:\{i}.jpg")).ToList();
|
|
scheduler.SetWindow(1, huge);
|
|
Assert.True(scheduler.Snapshot().Window <= ThumbnailScheduler.MaxPending);
|
|
var taken = Drain(scheduler);
|
|
Assert.Equal(ThumbnailScheduler.MaxPending, taken.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void In_flight_work_is_tracked_until_complete()
|
|
{
|
|
var scheduler = new ThumbnailScheduler();
|
|
scheduler.Reset(1);
|
|
scheduler.SetEnabled(true);
|
|
scheduler.SetWindow(1, Enumerable.Range(0, 8).Select(i => Job($@"C:\{i}.jpg")).ToList());
|
|
Assert.True(scheduler.TryTake(out var a));
|
|
Assert.True(scheduler.TryTake(out var b));
|
|
Assert.Equal(2, scheduler.InFlight);
|
|
scheduler.Complete(a, generated: true, failed: false);
|
|
Assert.Equal(1, scheduler.InFlight);
|
|
scheduler.Complete(b, generated: true, failed: false);
|
|
Assert.Equal(0, scheduler.InFlight);
|
|
}
|
|
|
|
[Fact]
|
|
public void Preview_disabled_cancels_window()
|
|
{
|
|
var scheduler = new ThumbnailScheduler();
|
|
scheduler.Reset(1);
|
|
scheduler.SetEnabled(true);
|
|
scheduler.SetWindow(1, [Job(@"C:\x.jpg")]);
|
|
scheduler.SetEnabled(false);
|
|
Assert.False(scheduler.TryTake(out _));
|
|
}
|
|
|
|
[Fact]
|
|
public void Cache_key_changes_when_file_is_modified()
|
|
{
|
|
var first = ThumbnailKey.From(@"C:\a.jpg", DateTimeOffset.UnixEpoch, 128);
|
|
var second = ThumbnailKey.From(@"C:\a.jpg", DateTimeOffset.UnixEpoch.AddHours(1), 128);
|
|
Assert.NotEqual(first, second);
|
|
}
|
|
|
|
[Fact]
|
|
public void Lru_cache_evicts_oldest_when_full()
|
|
{
|
|
var cache = new LruCache<string, int>(2);
|
|
cache.Set("a", 1);
|
|
cache.Set("b", 2);
|
|
cache.Set("c", 3);
|
|
Assert.False(cache.TryGet("a", out _));
|
|
Assert.True(cache.TryGet("b", out var b));
|
|
Assert.Equal(2, b);
|
|
cache.Set("d", 4);
|
|
Assert.False(cache.TryGet("c", out _));
|
|
Assert.True(cache.TryGet("b", out _));
|
|
}
|
|
|
|
private static ThumbnailJob Job(string path, int rank = 0, int generation = 1)
|
|
=> new(ThumbnailKey.From(path, DateTimeOffset.UnixEpoch, 128), rank, generation);
|
|
|
|
private static List<ThumbnailJob> Drain(ThumbnailScheduler scheduler)
|
|
{
|
|
var taken = new List<ThumbnailJob>();
|
|
while (scheduler.TryTake(out var job))
|
|
{
|
|
taken.Add(job);
|
|
scheduler.Complete(job, generated: true, failed: false);
|
|
}
|
|
|
|
return taken;
|
|
}
|
|
}
|