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.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.Instance); await sources.InitializeAsync(); var browse = new BrowseService( new BrowseEnumerator(), volumes, store, sources, new StorageProviderRegistry([], NullLogger.Instance), new CloudPlaceStore(env), new UiPreferencesStore(env)); return (browse, store); } } file sealed class BrowseEnumerator : IFileSystemEnumerator { public IEnumerable EnumerateChildren(string directoryPath) => EnumerateChildrenSafe(directoryPath, out _); public FileSystemItem? GetItem(string path) => null; public IReadOnlyList 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 Online { get; set; } = []; public IReadOnlyList 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; } }