Files
Wiki/test/Wiki.Contracts/NoteStoreContract.cs
T
claude-botandClaude Fable 5.1 c94afb004c
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
feat(facts): pictures as part of a statement, kept next to the raw source
A statement may carry images (a type label, for instance). The drafter
sees them as image blocks and transcribes what is printed; the deposit
stores each picture beside the note as raw/<stem>-<n>.<ext>, lists it in
the frontmatter and embeds it in the body. INoteStore gains a binary
create and a browse URL, so the raw page can link to the pictures. The
page takes pictures from a file picker (camera on phones) or from paste,
resized in the browser to 1600px.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-25 09:52:16 +02:00

100 lines
4.4 KiB
C#

using Wiki.Core.Model;
using Wiki.Core.Ports;
namespace Wiki.Contracts;
/// <summary>Every <see cref="INoteStore"/> adapter derives a test class from this and supplies a store over <see cref="VaultFixture"/>.</summary>
public abstract class NoteStoreContract
{
/// <summary>A store whose current head exposes exactly <see cref="VaultFixture.Files"/>.</summary>
protected abstract Task<INoteStore> CreateStoreAsync();
[Fact]
public async Task HeadHasACommit()
{
var store = await CreateStoreAsync();
var head = await store.GetHeadAsync(CancellationToken.None);
Assert.False(string.IsNullOrWhiteSpace(head.Commit));
}
[Fact]
public async Task ListsOnlyVaultDocumentsOfRequestedKinds()
{
var store = await CreateStoreAsync();
var head = await store.GetHeadAsync(CancellationToken.None);
var all = await store.ListAsync(head.Commit, VaultFixture.AllKinds, CancellationToken.None);
Assert.Equal(
VaultFixture.Expected.OrderBy(e => e.Path),
all.Select(r => (r.Kind, r.Slug, r.Path)).OrderBy(e => e.Path));
var wiki = await store.ListAsync(head.Commit, new HashSet<DocumentKind> { DocumentKind.Wiki }, CancellationToken.None);
Assert.All(wiki, r => Assert.Equal(DocumentKind.Wiki, r.Kind));
Assert.Equal(2, wiki.Count);
}
[Fact]
public async Task ContentHashIsStableAndDistinct()
{
var store = await CreateStoreAsync();
var head = await store.GetHeadAsync(CancellationToken.None);
var a = await store.ListAsync(head.Commit, VaultFixture.AllKinds, CancellationToken.None);
var b = await store.ListAsync(head.Commit, VaultFixture.AllKinds, CancellationToken.None);
Assert.Equal(a.OrderBy(r => r.Path).Select(r => r.ContentHash), b.OrderBy(r => r.Path).Select(r => r.ContentHash));
Assert.All(a, r => Assert.False(string.IsNullOrWhiteSpace(r.ContentHash)));
Assert.Equal(a.Count, a.Select(r => r.ContentHash).Distinct().Count());
}
[Fact]
public async Task ReadsExactText()
{
var store = await CreateStoreAsync();
var head = await store.GetHeadAsync(CancellationToken.None);
var refs = await store.ListAsync(head.Commit, VaultFixture.AllKinds, CancellationToken.None);
foreach (var r in refs)
{
var text = await store.ReadAsync(r, head.Commit, CancellationToken.None);
Assert.Equal(VaultFixture.Files[r.Path], text);
}
}
[Fact]
public async Task CreatesANewDocumentAndRefusesAnExistingPath()
{
var store = await CreateStoreAsync();
var written = await store.CreateAsync("raw/2026-09-24-new.md", "---\ntitle: New\n---\n\nText.\n", "raw: New", CancellationToken.None);
Assert.Equal("raw/2026-09-24-new.md", written.Path);
Assert.False(string.IsNullOrWhiteSpace(written.Commit));
var head = await store.GetHeadAsync(CancellationToken.None);
var refs = await store.ListAsync(head.Commit, VaultFixture.AllKinds, CancellationToken.None);
var created = Assert.Single(refs, r => r.Path == "raw/2026-09-24-new.md");
Assert.Equal("---\ntitle: New\n---\n\nText.\n", await store.ReadAsync(created, head.Commit, CancellationToken.None));
await Assert.ThrowsAsync<DocumentExistsException>(() =>
store.CreateAsync("raw/2026-09-24-new.md", "other", "raw: New", CancellationToken.None));
await Assert.ThrowsAsync<DocumentExistsException>(() =>
store.CreateAsync("wiki/udm-dns.md", "other", "x", CancellationToken.None));
}
[Fact]
public async Task CreatesABinaryAndRefusesAnExistingPath()
{
var store = await CreateStoreAsync();
var bytes = new byte[] { 0xFF, 0xD8, 0xFF, 0xE0, 1, 2, 3 };
var written = await store.CreateAsync("raw/2026-09-24-new-1.jpg", bytes, "raw: New (attachment 1)", CancellationToken.None);
Assert.Equal("raw/2026-09-24-new-1.jpg", written.Path);
Assert.False(string.IsNullOrWhiteSpace(written.Commit));
await Assert.ThrowsAsync<DocumentExistsException>(() =>
store.CreateAsync("raw/2026-09-24-new-1.jpg", bytes, "x", CancellationToken.None));
}
[Fact]
public async Task HealthReportsOk()
{
var store = await CreateStoreAsync();
var health = await store.CheckAsync(CancellationToken.None);
Assert.True(health.Ok, health.Detail);
Assert.Equal(store.Name, health.Adapter);
}
}