Add Git overlay, operation tools, and virtualized preview so large folders stay responsive.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
170
tests/Explorer.Application.Tests/ThumbnailSchedulerTests.cs
Normal file
170
tests/Explorer.Application.Tests/ThumbnailSchedulerTests.cs
Normal file
@@ -0,0 +1,170 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user