Files
Explorer-Workbench/tests/Explorer.Application.Tests/BrowseServiceTests.cs
netquick 9bf451932f Improve file operations, layout memory, and drive status.
Add a sequential file-operations queue with pause, reorder, and optional auto-clear; persist window size and tree width; show free space; and clear leftover indexing status.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-24 01:52:30 +02:00

158 lines
5.6 KiB
C#

using Explorer.Application;
using Explorer.Domain;
using Explorer.Domain.Abstractions;
using Explorer.Storage.Sqlite;
using Microsoft.Extensions.Logging.Abstractions;
namespace Explorer.Application.Tests;
public class BrowseServiceTests
{
[Fact]
public async Task This_pc_shows_indexed_root_aggregate_size()
{
var (browse, store) = await CreateAsync(@"C:\", "C: (930.6 GB)");
var source = (await store.Sources.GetAllAsync()).Single();
source.LastIndexedUtc = DateTimeOffset.UtcNow;
await store.Sources.UpsertAsync(source);
var root = new IndexEntry
{
SourceId = source.Id,
Name = "C:",
NameNorm = "c:",
IsDirectory = true,
PathRel = "",
LastSeenUtc = DateTimeOffset.UtcNow,
AggregateSize = 1_073_741_824
};
await store.Entries.UpsertAsync(root);
var listing = await browse.ListThisPcAsync();
var item = Assert.Single(listing.Items);
Assert.Equal(1_073_741_824, item.SizeBytes);
Assert.Equal(250_000_000, item.FreeSpaceBytes);
Assert.Equal(1_000_000_000, item.CapacityBytes);
Assert.True(item.IsDirectory);
}
[Fact]
public async Task Live_listing_overlays_folder_aggregate_from_index()
{
var (browse, store) = await CreateAsync(@"C:\", "C:");
var source = (await store.Sources.GetAllAsync()).Single();
source.LastIndexedUtc = DateTimeOffset.UtcNow;
await store.Sources.UpsertAsync(source);
var root = new IndexEntry
{
SourceId = source.Id,
Name = "C:",
NameNorm = "c:",
IsDirectory = true,
PathRel = "",
LastSeenUtc = DateTimeOffset.UtcNow
};
root.Id = await store.Entries.UpsertAsync(root);
await store.Entries.UpsertAsync(new IndexEntry
{
SourceId = source.Id,
ParentId = root.Id,
Name = "Movies",
NameNorm = "movies",
IsDirectory = true,
PathRel = "Movies",
LastSeenUtc = DateTimeOffset.UtcNow,
AggregateSize = 200
});
var listing = await browse.ListAsync(@"C:\");
var movies = Assert.Single(listing.Items, i => i.Name == "Movies");
Assert.Equal(200, movies.SizeBytes);
Assert.Equal(250_000_000, movies.FreeSpaceBytes);
var loose = Assert.Single(listing.Items, i => i.Name == "loose.txt");
Assert.Equal(10, loose.SizeBytes);
}
private static async Task<(BrowseService Browse, SqliteIndexStore Store)> CreateAsync(string root, string display)
{
var db = Path.Combine(Path.GetTempPath(), "ew-browse", Guid.NewGuid().ToString("N"), "index.db");
var store = new SqliteIndexStore(db, NullLogger<SqliteIndexStore>.Instance);
await store.OpenAsync();
var volumes = new BrowseVolumes
{
Online =
[
new VolumeFingerprint
{
Kind = SourceKind.NtfsLocal,
RootPath = root,
DisplayName = display,
VolumeSerial = 1,
CapacityBytes = 1_000_000_000,
FreeBytes = 250_000_000
}
]
};
var env = new BrowseEnv(Path.GetDirectoryName(db)!);
var sources = new SourceManager(store, volumes, env, new SystemClock(), NullLogger<SourceManager>.Instance);
await sources.InitializeAsync();
var browse = new BrowseService(
new BrowseEnumerator(),
volumes,
store,
sources,
new StorageProviderRegistry([], NullLogger<StorageProviderRegistry>.Instance),
new CloudPlaceStore(env),
new UiPreferencesStore(env));
return (browse, store);
}
}
file sealed class BrowseEnumerator : IFileSystemEnumerator
{
public IEnumerable<FileSystemItem> EnumerateChildren(string directoryPath)
=> EnumerateChildrenSafe(directoryPath, out _);
public FileSystemItem? GetItem(string path) => null;
public IReadOnlyList<FileSystemItem> EnumerateChildrenSafe(string directoryPath, out string? error)
{
error = null;
return
[
new FileSystemItem { FullPath = Path.Combine(directoryPath, "Movies"), Name = "Movies", IsDirectory = true },
new FileSystemItem { FullPath = Path.Combine(directoryPath, "loose.txt"), Name = "loose.txt", SizeBytes = 10 }
];
}
}
file sealed class BrowseVolumes : IVolumeService
{
public List<VolumeFingerprint> Online { get; set; } = [];
public IReadOnlyList<VolumeFingerprint> EnumerateOnlineVolumes() => Online;
public VolumeFingerprint? Probe(string path)
=> Online.FirstOrDefault(v => path.StartsWith(v.RootPath.TrimEnd('\\'), StringComparison.OrdinalIgnoreCase));
public bool IsPathReachable(string path)
=> Online.Any(v => path.StartsWith(v.RootPath.TrimEnd('\\'), StringComparison.OrdinalIgnoreCase));
public VolumeSpace GetSpace(string path)
{
var fp = Probe(path);
return new VolumeSpace(fp?.CapacityBytes, fp?.FreeBytes);
}
}
file sealed class BrowseEnv : IAppEnvironment
{
public BrowseEnv(string dir)
{
DataDirectory = dir;
Directory.CreateDirectory(dir);
DatabasePath = Path.Combine(dir, "index.db");
LogDirectory = Path.Combine(dir, "logs");
Directory.CreateDirectory(LogDirectory);
}
public string DataDirectory { get; }
public string DatabasePath { get; }
public string LogDirectory { get; }
}