From a181d7bba8efddff6a4c4e44c70e79d39f815c6d Mon Sep 17 00:00:00 2001 From: Sean Silvius Date: Sun, 12 Apr 2026 15:06:12 -0700 Subject: [PATCH] =?UTF-8?q?test(imap):=20add=20RFC=203501=20=C2=A76.4.4=20?= =?UTF-8?q?coverage=20for=20remaining=20flag=20SEARCH=20criteria?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DRAFT/UNDRAFT, FLAGGED/UNFLAGGED, RECENT/OLD, UNANSWERED were handled by the FLAG_CRITERIA lookup table in parseSearchCriteria but had no tests. Parser was correct; issue #82 was filed by reading only the switch statement and missing the pre-dispatch lookup. Resolves #82 Co-Authored-By: Claude Sonnet 4.6 --- packages/imap/tests/protocol/parser.test.ts | 35 +++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/packages/imap/tests/protocol/parser.test.ts b/packages/imap/tests/protocol/parser.test.ts index 33f4a81..e68f714 100644 --- a/packages/imap/tests/protocol/parser.test.ts +++ b/packages/imap/tests/protocol/parser.test.ts @@ -338,6 +338,41 @@ describe("parseSearchCriteria", () => { ]); }); + // RFC 3501 Section 6.4.4 -- remaining flag-keyword criteria + it("parses DRAFT and UNDRAFT (RFC 3501 \u00a76.4.4)", () => { + expect(parseSearchCriteria("DRAFT")).toEqual([ + { type: "flag", flag: "\\Draft", negated: false }, + ]); + expect(parseSearchCriteria("UNDRAFT")).toEqual([ + { type: "flag", flag: "\\Draft", negated: true }, + ]); + }); + + it("parses FLAGGED and UNFLAGGED (RFC 3501 \u00a76.4.4)", () => { + expect(parseSearchCriteria("FLAGGED")).toEqual([ + { type: "flag", flag: "\\Flagged", negated: false }, + ]); + expect(parseSearchCriteria("UNFLAGGED")).toEqual([ + { type: "flag", flag: "\\Flagged", negated: true }, + ]); + }); + + it("parses RECENT and OLD (RFC 3501 \u00a76.4.4)", () => { + expect(parseSearchCriteria("RECENT")).toEqual([ + { type: "flag", flag: "\\Recent", negated: false }, + ]); + // OLD = messages that do not have the \Recent flag + expect(parseSearchCriteria("OLD")).toEqual([ + { type: "flag", flag: "\\Recent", negated: true }, + ]); + }); + + it("parses UNANSWERED (RFC 3501 \u00a76.4.4)", () => { + expect(parseSearchCriteria("UNANSWERED")).toEqual([ + { type: "flag", flag: "\\Answered", negated: true }, + ]); + }); + it("throws on unknown criterion", () => { expect(() => parseSearchCriteria("FOOBAR")).toThrow(ImapParseError); });