using Microsoft.Extensions.Logging.Abstractions; using Wiki.Application.Reading; using Wiki.Application.Retrieval; using Wiki.Application.Sync; using Wiki.Core.Model; namespace Wiki.Application.Tests; public class NoteQueriesTests { private readonly FakeStore _store = new(); private readonly FakeCatalog _catalog = new(); private readonly FakeIndex _index = new(); private readonly FakeEmbeddings _model = new("m1"); private NoteQueries Queries => new(_catalog, new RankUseCase(_index, _catalog)); private async Task SeedAsync() { _store.Files["wiki/udm-dns.md"] = "---\ntitle: UDM intercepts DNS\ntype: wiki\ntags: [dns, udm]\nsources: [raw/_processed/2026-09-01-dns.md, \"live check\"]\nrelated: [ceph-osd]\nupdated: 2026-09-16\n---\n\n# UDM intercepts DNS\n\nSee [[ceph-osd]] and [[missing-note]].\n"; _store.Files["wiki/ceph-osd.md"] = "---\ntitle: Ceph OSD\ntype: wiki\ntags: [ceph]\nupdated: 2026-09-10\n---\n\n# Ceph OSD\n\nOSD.\n"; _store.Files["raw/_processed/2026-09-01-dns.md"] = "---\ntitle: DNS capture\ntype: raw\nsource: dig session\ncaptured: 2026-09-01\n---\n\ncapture\n"; _store.Files["raw/2026-09-23-pending.md"] = "---\ntitle: Pending\ntype: raw\nsource: shell\ncaptured: 2026-09-23\n---\n\npending\n"; _store.Files["output/2026-09-20-answer.md"] = "---\ntitle: An answer\ntype: output\nquestion: Does the UDM intercept DNS?\ngenerated: 2026-09-20\n---\n\nYes.\n"; _store.Files["output/2026-09-21-wiki-audit.md"] = "---\ntitle: Wiki audit\ntype: audit\ngenerated: 2026-09-21\n---\n\nreport\n"; var sync = new SyncUseCase(_store, _catalog, _index, [_model], TimeProvider.System, NullLogger.Instance); await sync.RunAsync(false, CancellationToken.None); } [Fact] public async Task ListsByUpdatedAndFiltersByTag() { await SeedAsync(); var all = await Queries.ListAsync(null, 10, CancellationToken.None); Assert.Equal(["udm-dns", "ceph-osd"], all.Select(n => n.Slug)); var ceph = await Queries.ListAsync("CEPH", 10, CancellationToken.None); Assert.Equal(["ceph-osd"], ceph.Select(n => n.Slug)); } [Fact] public async Task NoteViewResolvesLinksBacklinksAndSources() { await SeedAsync(); var view = await Queries.GetAsync("udm-dns", CancellationToken.None); Assert.NotNull(view); Assert.Equal(["ceph-osd", "ceph-osd", "missing-note"], view.Outgoing.Select(l => l.ToSlug)); Assert.Equal(["missing-note"], view.UnresolvedLinks); Assert.Equal([(DocumentKind.RawProcessed, "2026-09-01-dns"), (null, null)], view.Sources.Select(s => (s.Kind, s.Slug))); var ceph = await Queries.GetAsync("ceph-osd", CancellationToken.None); Assert.Equal(2, ceph!.Backlinks.Count); Assert.Null(await Queries.GetAsync("nope", CancellationToken.None)); } [Fact] public async Task TagsRawQueueAndReports() { await SeedAsync(); var tags = await Queries.TagsAsync(CancellationToken.None); Assert.Equal(1, tags["dns"]); var raw = await Queries.RawQueueAsync(CancellationToken.None); var entry = Assert.Single(raw); Assert.Equal(("2026-09-23-pending", new DateOnly(2026, 9, 23), "shell"), (entry.Slug, entry.Captured, entry.Source)); var reports = await Queries.ReportsAsync(null, 10, CancellationToken.None); Assert.Equal(["2026-09-21-wiki-audit", "2026-09-20-answer"], reports.Select(r => r.Slug)); var outputs = await Queries.ReportsAsync("output", 10, CancellationToken.None); Assert.Equal("Does the UDM intercept DNS?", Assert.Single(outputs).Question); } [Fact] public async Task SearchCarriesScoresAndTags() { await SeedAsync(); var udm = (await _catalog.GetAsync(DocumentKind.Wiki, "udm-dns", CancellationToken.None))!; var hits = await Queries.SearchAsync(_model, Wiki.Core.Parsing.EmbeddingText.For(udm), 2, CancellationToken.None); Assert.Equal("udm-dns", hits[0].Slug); Assert.Equal(["dns", "udm"], hits[0].Tags); Assert.NotNull(hits[0].Score); } }