Persist file categories on the index and classify archives and unknown types during idle maintenance.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-28 11:37:29 +02:00
parent b33a78dbbe
commit 222b5d9969
42 changed files with 1719 additions and 80 deletions

View File

@@ -114,6 +114,135 @@ public class EntryAndSearchTests
Assert.Contains(byDate, e => e.Name == "Movie.mkv");
}
[Fact]
public async Task Upsert_assigns_and_preserves_categories()
{
await using var store = await Stores.Open();
var source = await store.AddSourceAsync(@"C:\media");
var root = new IndexEntry
{
SourceId = source.Id,
Name = "media",
NameNorm = "media",
IsDirectory = true,
PathRel = "",
LastSeenUtc = DateTimeOffset.UtcNow
};
root.Id = await store.Entries.UpsertAsync(root);
var photo = new IndexEntry
{
SourceId = source.Id,
ParentId = root.Id,
Name = "shot.jpg",
NameNorm = "shot.jpg",
Extension = "jpg",
PathRel = "shot.jpg",
LastSeenUtc = DateTimeOffset.UtcNow
};
photo.Id = await store.Entries.UpsertAsync(photo);
var loaded = await store.Entries.GetAsync(photo.Id);
Assert.Equal(FileCategory.Photos, loaded!.Category);
Assert.Equal(CategorySources.Extension, loaded.CategorySource);
await store.Entries.SetUserCategoryAsync(photo.Id, FileCategory.Documents, "Manual");
photo.SizeBytes = 100;
await store.Entries.UpsertAsync(photo);
loaded = await store.Entries.GetAsync(photo.Id);
Assert.Equal(FileCategory.Documents, loaded!.Category);
Assert.Equal(CategorySources.User, loaded.CategorySource);
var other = new IndexEntry
{
SourceId = source.Id,
ParentId = root.Id,
Name = "clip.mkv",
NameNorm = "clip.mkv",
Extension = "mkv",
PathRel = "clip.mkv",
LastSeenUtc = DateTimeOffset.UtcNow
};
other.Id = await store.Entries.UpsertAsync(other);
await store.Entries.RefreshCategoryFromChildrenAsync(root.Id);
var folder = await store.Entries.GetAsync(root.Id);
Assert.Equal(FileCategory.Unknown, folder!.Category);
}
[Fact]
public async Task Archive_contents_and_signature_queues()
{
await using var store = await Stores.Open();
var source = await store.AddSourceAsync(@"C:\media");
var zip = new IndexEntry
{
SourceId = source.Id,
Name = "photos.zip",
NameNorm = "photos.zip",
Extension = "zip",
PathRel = "photos.zip",
LastSeenUtc = DateTimeOffset.UtcNow
};
zip.Id = await store.Entries.UpsertAsync(zip);
Assert.Equal(FileCategory.Archive, (await store.Entries.GetAsync(zip.Id))!.Category);
for (var i = 0; i < 3; i++)
{
await store.Entries.UpsertAsync(new IndexEntry
{
SourceId = source.Id,
ParentId = zip.Id,
Name = $"shot{i}.jpg",
NameNorm = $"shot{i}.jpg",
Extension = "jpg",
PathRel = $"photos.zip/shot{i}.jpg",
LastSeenUtc = DateTimeOffset.UtcNow
});
}
var needing = await store.Entries.GetArchiveIdsNeedingContentClassifyAsync(10);
Assert.Contains(zip.Id, needing);
await store.Entries.RefreshCategoryFromChildrenAsync(zip.Id);
var loaded = await store.Entries.GetAsync(zip.Id);
Assert.Equal(FileCategory.Photos, loaded!.Category);
Assert.Equal(CategorySources.ArchiveContents, loaded.CategorySource);
Assert.Empty(await store.Entries.GetArchiveIdsNeedingContentClassifyAsync(10));
var mystery = new IndexEntry
{
SourceId = source.Id,
Name = "mystery.bin",
NameNorm = "mystery.bin",
Extension = "bin",
PathRel = "mystery.bin",
LastSeenUtc = DateTimeOffset.UtcNow
};
mystery.Id = await store.Entries.UpsertAsync(mystery);
var unknowns = await store.Entries.GetUnknownFilesForSignatureAsync(10);
Assert.Contains(unknowns, e => e.Id == mystery.Id);
Assert.Equal(0, await store.Entries.BackfillCheapCategoriesAsync(50));
}
[Fact]
public async Task User_category_by_path_is_preserved()
{
await using var store = await Stores.Open();
var source = await store.AddSourceAsync(@"C:\media");
var photo = new IndexEntry
{
SourceId = source.Id,
Name = "shot.jpg",
NameNorm = "shot.jpg",
Extension = "jpg",
PathRel = "shot.jpg",
LastSeenUtc = DateTimeOffset.UtcNow
};
photo.Id = await store.Entries.UpsertAsync(photo);
var mutations = new Explorer.Application.LocalIndexMutations(store);
await mutations.SetUserCategoryByPathAsync(@"C:\media\shot.jpg", FileCategory.Installer, "Manual");
var loaded = await store.Entries.GetAsync(photo.Id);
Assert.Equal(FileCategory.Installer, loaded!.Category);
Assert.Equal(CategorySources.User, loaded.CategorySource);
}
[Fact]
public async Task Folder_aggregates_and_tombstones()
{