From a0f29395f3b45288e115b98155ab7185ee3d2fd4 Mon Sep 17 00:00:00 2001 From: "Jeffrey C. Ollie" Date: Sat, 29 Aug 2026 21:09:52 -0500 Subject: [PATCH] test findMessageByFilename and explain its error causes Covers lookup by absolute and database-relative filename, null for unknown filenames, and XapianException on a closed database. The FindMessageError docs now explain that UpgradeRequired means the on-disk format predates filename lookup and what triggers a Xapian exception. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_017i7R7ReKJAHGQpitxGXqrb --- src/Database.zig | 9 ++++++--- src/tests.zig | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/Database.zig b/src/Database.zig index f86f218..7b5ea12 100644 --- a/src/Database.zig +++ b/src/Database.zig @@ -744,10 +744,13 @@ pub fn removeMessage(self: *const Database, filename: [:0]const u8) RemoveMessag pub const FindMessageError = error{ /// Out of memory creating message object. OutOfMemory, - /// The caller must upgrade the database to use this function - /// (`findMessageByFilename` only). + /// The database is in an older on-disk format that cannot look messages + /// up by filename; call `Database.upgrade` first. Returned by + /// `findMessageByFilename` only. UpgradeRequired, - /// A Xapian exception occurred. + /// The underlying Xapian database reported an error — for example, the + /// database has been closed, or an I/O failure occurred while reading + /// it. XapianException, /// libnotmuch returned an undocumented status code. Unexpected, diff --git a/src/tests.zig b/src/tests.zig index d3390f9..f83023f 100644 --- a/src/tests.zig +++ b/src/tests.zig @@ -255,6 +255,34 @@ test "Database.removeMessage with a message stored under multiple filenames" { try std.testing.expect(try ghost.getFlag(.ghost)); } +test "Database.findMessageByFilename" { + const alloc = std.testing.allocator; + var test_db = try fixture.corpusDatabase(); + defer test_db.deinit(); + const db = test_db.database; + + const root = db.getPath() orelse return error.TestUnexpectedResult; + + // Lookup by absolute filename. + const abs = try std.fs.path.joinZ(alloc, &.{ root, "cur", "two.eml" }); + defer alloc.free(abs); + const by_abs = try db.findMessageByFilename(abs) orelse return error.TestUnexpectedResult; + defer by_abs.deinit(); + try std.testing.expectEqualStrings("two@example.org", by_abs.getMessageID() orelse ""); + + // Lookup by filename relative to the database path. + const by_rel = try db.findMessageByFilename("cur/two.eml") orelse return error.TestUnexpectedResult; + defer by_rel.deinit(); + try std.testing.expectEqualStrings("two@example.org", by_rel.getMessageID() orelse ""); + + // Unknown filenames return null. + try std.testing.expectEqual(@as(?notmuch.Message, null), try db.findMessageByFilename("cur/missing.eml")); + + // A closed database reports a Xapian exception. + try db.close(); + try std.testing.expectError(error.XapianException, db.findMessageByFilename(abs)); +} + test "Database configuration access" { var test_db = try fixture.corpusDatabase(); defer test_db.deinit(); -- 2.54.0