diff options
Diffstat (limited to 'pigeonhole/tests/extensions/body')
-rw-r--r-- | pigeonhole/tests/extensions/body/basic.svtest | 97 | ||||
-rw-r--r-- | pigeonhole/tests/extensions/body/content.svtest | 332 | ||||
-rw-r--r-- | pigeonhole/tests/extensions/body/errors.svtest | 19 | ||||
-rw-r--r-- | pigeonhole/tests/extensions/body/errors/syntax.sieve | 38 | ||||
-rw-r--r-- | pigeonhole/tests/extensions/body/match-values.svtest | 55 | ||||
-rw-r--r-- | pigeonhole/tests/extensions/body/raw.svtest | 85 | ||||
-rw-r--r-- | pigeonhole/tests/extensions/body/text.svtest | 225 |
7 files changed, 851 insertions, 0 deletions
diff --git a/pigeonhole/tests/extensions/body/basic.svtest b/pigeonhole/tests/extensions/body/basic.svtest new file mode 100644 index 0000000..0b2bffc --- /dev/null +++ b/pigeonhole/tests/extensions/body/basic.svtest @@ -0,0 +1,97 @@ +require "vnd.dovecot.testsuite"; +require "relational"; +require "comparator-i;ascii-numeric"; + +require "body"; + +test_set "message" text: +From: stephan@example.org +To: tss@example.net +Subject: Test message. + +Test! + +. +; + +/* Empty line + * + * RFC 5173: + * 'The body test matches content in the body of an email message, that + * is, anything following the first empty line after the header. (The + * empty line itself, if present, is not considered to be part of the + * body.)' + */ +test "The empty line" { + + if not body :raw :is text: +Test! + +. + { + test_fail "invalid message body extracted (1)"; + } + + if body :raw :is text: + +Test! + +. + { + test_fail "invalid message body extracted (2)"; + } + + if body :raw :is "Test" + { + test_fail "body test matches nonsense (3)"; + } +} + +/* Default comparator and match type + * + * RFC 5173: + * 'The COMPARATOR and MATCH-TYPE keyword parameters are defined in + * [SIEVE]. As specified in Sections 2.7.1 and 2.7.3 of [SIEVE], the + * default COMPARATOR is "i;ascii-casemap" and the default MATCH-TYPE is + * ":is".' + */ + +test "Defaults" { + if anyof ( body :raw "Test", body :raw "*Test*" ) { + test_fail "default match type is not :is as is required"; + } + + if allof( not body :raw :contains "tesT", body :raw :contains "Test" ) { + test_fail "default comparator is not i;ascii-casemap as is required"; + } +} + +/* No body + * + * RFC 5173: + * 'If a message consists of a header only, not followed by an empty line, + * then that set is empty and all "body" tests return false, including + * those that test for an empty string. (This is similar to how the + * "header" test always fails when the named header fields aren't present.)' + */ + +test_set "message" text: +From: stephan@example.org +To: tss@example.net +Subject: No body is here! +. +; + +test "No body" { + if body :raw :contains "" { + test_fail "matched against non-existent body (:contains \"\")"; + } + + if body :raw :is "" { + test_fail "matched against non-existent body (:is \"\")"; + } + + if body :raw :matches "*" { + test_fail "matched against non-existent body (:matches \"*\")"; + } +} diff --git a/pigeonhole/tests/extensions/body/content.svtest b/pigeonhole/tests/extensions/body/content.svtest new file mode 100644 index 0000000..2eb3837 --- /dev/null +++ b/pigeonhole/tests/extensions/body/content.svtest @@ -0,0 +1,332 @@ +require "vnd.dovecot.testsuite"; +require "relational"; +require "comparator-i;ascii-numeric"; + +require "body"; + +/* + * + */ + +test_set "message" text: +From: justin@example.com +To: carl@example.nl +Subject: Frop +Content-Type: multipart/mixed; boundary=donkey + +This is a multi-part message in MIME format. + +--donkey +Content-Type: text/plain + +Plain Text + +--donkey +Content-Type: text/stupid + +Stupid Text + +--donkey +Content-Type: text/plain/stupid + +Plain Stupid Text + +--donkey-- +. +; + +/* + * RFC5173, Section 5.2: + * If an individual content type begins or ends with a '/' (slash) or + * contains multiple slashes, then it matches no content types. + * ... + */ + +test "Basic Match" { + if not body :content "text/plain" :matches "Plain Text*" { + test_fail "failed to match (1)"; + } + + if not body :content "text/plain" :contains "" { + test_fail "failed to match (2)"; + } + + if not body :content "text/stupid" :contains "" { + test_fail "failed to match (3)"; + } +} + +test "Begin Slash" { + if body :content "/plain" :contains "" { + test_fail "matched :content \"/plain\""; + } +} + +test "End Slash" { + if body :content "text/" :contains "" { + test_fail "matched :content \"text/\""; + } +} + +test "Double Slash" { + if body :content "text/plain/stupid" :contains "" { + test_fail "matched :content \"text/plain/stupid\""; + } +} + +/* + * + */ + +test_set "message" text: +From: justin@example.com +To: carl@example.nl +Subject: Frop +Content-Type: multipart/mixed; boundary=limit + +This is a multi-part message in MIME format. + +--limit +Content-Type: text/plain + +This is a text message. + +--limit +Content-Type: text/html + +<html><body>This is HTML</body></html> + +--limit +Content-Type: application/sieve + +keep; + +--limit-- +. +; + +/* RFC5173, Section 5.2: + * ... + * Otherwise, if it contains a slash, then it specifies a full + * <type>/<subtype> pair, and matches only that specific content type. + * If it is the empty string, all MIME content types are matched. + * Otherwise, it specifies a <type> only, and any subtype of that type + * matches it. + */ + +test "Full Content Type" { + if not body :content "text/plain" :matches "This is a text message.*" { + test_fail "failed to match text/plain content"; + } + + if body :content "text/plain" :matches "<html><body>This is HTML</body></html>*" { + test_fail "erroneously matched text/html content"; + } + + if not body :content "text/html" :matches "<html><body>This is HTML</body></html>*" { + test_fail "failed to match text/html content"; + } + + if body :content "text/html" :matches "This is a text message.*" { + test_fail "erroneously matched text/plain content"; + } + + if body :content "text/html" :matches "This is HTML*" { + test_fail "body :content test matched plain text"; + } +} + +test "Empty Content Type" { + if not body :content "" :matches "This is a text message.*" { + test_fail "failed to match text/plain content"; + } + + if not body :content "" :matches "<html><body>This is HTML</body></html>*" { + test_fail "failed to match text/html content"; + } + + if not body :content "" :matches "keep;*" { + test_fail "failed to match application/sieve content"; + } + + if body :content "" :matches "*blurdybloop*" { + test_fail "body :content \"\" test matches nonsense"; + } +} + +test "Main Content Type" { + if not body :content "text" :matches "This is a text message.*" { + test_fail "failed to match text/plain content"; + } + + if not body :content "text" :matches "<html><body>This is HTML</body></html>*" { + test_fail "failed to match text/html content"; + } + + if body :content "text" :matches "keep;*" { + test_fail "erroneously matched application/sieve content"; + } +} + +/* + * + */ + +test_set "message" text: +From: Whomever <whoever@example.com> +To: Someone <someone@example.com> +Date: Sat, 10 Oct 2009 00:30:04 +0200 +Subject: whatever +Content-Type: multipart/mixed; boundary=outer + +This is a multi-part message in MIME format. + +--outer +Content-Type: multipart/alternative; boundary=inner + +This is a nested multi-part message in MIME format. + +--inner +Content-Type: text/plain; charset="us-ascii" + +Hello + +--inner +Content-Type: text/html; charset="us-ascii" + +<html><body>Hello</body></html> + +--inner-- + +This is the end of the inner MIME multipart. + +--outer +Content-Type: message/rfc822 + +From: Someone Else +Subject: Hello, this is an elaborate request for you to finally say hello + already! + +Please say Hello + +--outer-- + +This is the end of the outer MIME multipart. +. +; + +/* RFC5173, Section 5.2: + * + * The search for MIME parts matching the :content specification is + * recursive and automatically descends into multipart and + * message/rfc822 MIME parts. All MIME parts with matching types are + * searched for the key strings. The test returns true if any + * combination of a searched MIME part and key-list argument match. + */ + +test "Nested Search" { + if not body :content "text/plain" :matches "Hello*" { + test_fail "failed to match text/plain content"; + } + + if body :content "text/plain" :matches "<html><body>Hello</body></html>*" { + test_fail "erroneously matched text/html content"; + } + + if not body :content "text/html" :matches "<html><body>Hello</body></html>*" { + test_fail "failed to match text/html content"; + } + + if body :content "text/html" :matches "Hello*" { + test_fail "erroneously matched text/plain content"; + } + + if not body :content "text" :contains "html" { + test_fail "failed match text content (1)"; + } + + if not body :content "text" :contains "hello" { + test_fail "failed match text content (2)"; + } + + if not body :content "text/plain" :contains "please say hello" { + test_fail "failed match nested message content as text/plain"; + } + + if not body :content "text" :contains "please say hello" { + test_fail "failed match nested message content as text/*"; + } + + if not body :content "text" :count "eq" :comparator "i;ascii-numeric" "3" { + test_fail "matched wrong number of \"text/*\" body parts"; + } +} + +/* RFC5173, Section 5.2: + * + * If the :content specification matches a multipart MIME part, only the + * prologue and epilogue sections of the part will be searched for the + * key strings, treating the entire prologue and the entire epilogue as + * separate strings; the contents of nested parts are only searched if + * their respective types match the :content specification. + * + */ + +test "Multipart Content" { + if not body :content "multipart" :contains + "This is a multi-part message in MIME format" { + test_fail "missed first multipart body part"; + } + + if not body :content "multipart" :contains + "This is a nested multi-part message in MIME format" { + test_fail "missed second multipart body part"; + } + + if not body :content "multipart" :contains + "This is the end of the inner MIME multipart" { + test_fail "missed third multipart body part"; + } + + if not body :content "multipart" :contains + "This is the end of the outer MIME multipart." { + test_fail "missed fourth multipart body part"; + } + + if body :content "multipart" :contains "--inner" { + test_fail "inner boundary is part of match"; + } + + if body :content "multipart" :contains "--outer" { + test_fail "outer boundary is part of match"; + } +} + +/* RFC5173, Section 5.2: + * + * If the :content specification matches a message/rfc822 MIME part, + * only the header of the nested message will be searched for the key + * strings, treating the header as a single string; the contents of the + * nested message body parts are only searched if their content type + * matches the :content specification. + */ + +test "Content-Type: message/rfc822" { + if not body :content "message/rfc822" :contains + "From: Someone Else" { + test_fail "missed raw message/rfc822 from header"; + } + + if not body :content "message/rfc822" :is text: +From: Someone Else +Subject: Hello, this is an elaborate request for you to finally say hello + already! +. + { + test_fail "header content does not match exactly"; + } +} + + + + diff --git a/pigeonhole/tests/extensions/body/errors.svtest b/pigeonhole/tests/extensions/body/errors.svtest new file mode 100644 index 0000000..8db5657 --- /dev/null +++ b/pigeonhole/tests/extensions/body/errors.svtest @@ -0,0 +1,19 @@ +require "vnd.dovecot.testsuite"; + +require "relational"; +require "comparator-i;ascii-numeric"; + +/* + * Invalid syntax + */ + +test "Invalid Syntax" { + if test_script_compile "errors/syntax.sieve" { + test_fail "compile should have failed"; + } + + if not test_error :count "eq" :comparator "i;ascii-numeric" "12" { + test_fail "wrong number of errors reported"; + } +} + diff --git a/pigeonhole/tests/extensions/body/errors/syntax.sieve b/pigeonhole/tests/extensions/body/errors/syntax.sieve new file mode 100644 index 0000000..8adf0ef --- /dev/null +++ b/pigeonhole/tests/extensions/body/errors/syntax.sieve @@ -0,0 +1,38 @@ +require "body"; + +# 1: No key list +if body { } + +# 2: Number +if body 3 { } + +# OK: String +if body "frop" { } + +# 3: To many arguments +if body "frop" "friep" { } + +# 4: Unknown tag +if body :frop { } + +# 5: Unknown tag with valid key +if body :friep "frop" { } + +# 6: Content without argument +if body :content { } + +# 7: Content without key argument +if body :content "frop" { } + +# 8: Content with number argument +if body :content 3 "frop" { } + +# 9: Content with unknown tag +if body :content :frml "frop" { } + +# 10: Content with known tag +if body :content :contains "frop" { } + +# 11: Duplicate transform +if body :content "frop" :raw "frop" { } + diff --git a/pigeonhole/tests/extensions/body/match-values.svtest b/pigeonhole/tests/extensions/body/match-values.svtest new file mode 100644 index 0000000..55d5535 --- /dev/null +++ b/pigeonhole/tests/extensions/body/match-values.svtest @@ -0,0 +1,55 @@ +require "vnd.dovecot.testsuite"; + +require "body"; +require "variables"; + +test_set "message" text: +From: stephan@example.org +To: s.bosch@twente.example.net +Subject: Body test + +The big bad body test. +. +; + +# Test whether body test ignores match values +test "Match values disabled" { + if not body :raw :matches "The * bad * test*" { + test_fail "should have matched"; + } + + if anyof ( + string :is "${1}" "big", + string :is "${2}" "body", + not string :is "${0}" "", + not string :is "${1}" "", + not string :is "${2}" "") { + test_fail "match values not disabled"; + } +} + +test "Match values re-enabled" { + if not header :matches "from" "*@*" { + test_fail "should have matched"; + } + + if anyof ( + not string :is "${0}" "stephan@example.org", + not string :is "${1}" "stephan", + not string :is "${2}" "example.org" ) { + test_fail "match values not re-enabled properly."; + } +} + +test "Match values retained" { + if not body :raw :matches "The * bad * test*" { + test_fail "should have matched"; + } + + if anyof ( + not string :is "${0}" "stephan@example.org", + not string :is "${1}" "stephan", + not string :is "${2}" "example.org" ) { + test_fail "match values not retained after body test."; + } +} diff --git a/pigeonhole/tests/extensions/body/raw.svtest b/pigeonhole/tests/extensions/body/raw.svtest new file mode 100644 index 0000000..d3404b9 --- /dev/null +++ b/pigeonhole/tests/extensions/body/raw.svtest @@ -0,0 +1,85 @@ +require "vnd.dovecot.testsuite"; +require "body"; + +test_set "message" text: +From: Whomever <whoever@example.com> +To: Someone <someone@example.com> +Date: Sat, 10 Oct 2009 00:30:04 +0200 +Subject: whatever +Content-Type: multipart/mixed; boundary=outer + +This is a multi-part message in MIME format. + +--outer +Content-Type: multipart/alternative; boundary=inner + +This is a nested multi-part message in MIME format. + +--inner +Content-Type: text/plain; charset="us-ascii" + +Hello + +--inner +Content-Type: text/html; charset="us-ascii" + +<html><body>Hello</body></html> + +--inner-- + +This is the end of the inner MIME multipart. + +--outer +Content-Type: message/rfc822 + +From: Someone Else +Subject: hello request + +Please say Hello + +--outer-- + +This is the end of the outer MIME multipart. +. +; + +/* + * + * RFC 5173: + * The ":raw" transform matches against the entire undecoded body of a + * message as a single item. + * + * If the specified body-transform is ":raw", the [MIME] structure of + * the body is irrelevant. The implementation MUST NOT remove any + * transfer encoding from the message, MUST NOT refuse to filter + * messages with syntactic errors (unless the environment it is part of + * rejects them outright), and MUST treat multipart boundaries or the + * MIME headers of enclosed body parts as part of the content being + * matched against, instead of MIME structures to interpret. + */ + +test "Multipart Boundaries" { + if not body :raw :contains "--inner" { + test_fail "Raw body does not contain '--inner'"; + } + + if not body :raw :contains "--outer" { + test_fail "Raw body does not contain '--outer'"; + } +} + +test "Multipart Headers" { + if not body :raw :contains "boundary=inner" { + test_fail "Raw body does not contain 'boundary=inner'"; + } + + if not body :raw :contains "rfc822" { + test_fail "Raw body does not contain 'rfc822'"; + } +} + +test "Multipart Content" { + if not body :raw :contains "<html><body>Hello</body></html>" { + test_fail "Raw body does not contain '<html><body>Hello</body></html>'"; + } +} diff --git a/pigeonhole/tests/extensions/body/text.svtest b/pigeonhole/tests/extensions/body/text.svtest new file mode 100644 index 0000000..2dc6a03 --- /dev/null +++ b/pigeonhole/tests/extensions/body/text.svtest @@ -0,0 +1,225 @@ +require "vnd.dovecot.testsuite"; +require "relational"; +require "comparator-i;ascii-numeric"; + +require "body"; + +/* + * + */ + +test_set "message" text: +From: justin@example.com +To: carl@example.nl +Subject: Frop +Content-Type: multipart/mixed; boundary=donkey + +This is a multi-part message in MIME format. + +--donkey +Content-Type: text/plain + +Plain Text + +--donkey +Content-Type: text/stupid + +Stupid Text + +--donkey +Content-Type: text/plain/stupid + +Plain Stupid Text + +--donkey-- +. +; + +test "Basic Match" { + if not body :text :contains "Plain Text" { + test_fail "failed to match (1)"; + } + + if not body :text :contains "Stupid Text" { + test_fail "failed to match (2)"; + } +} + +test "Double Slash" { + if body :text :contains "Plain Stupid Text" { + test_fail "matched \"text/plain/stupid\""; + } +} + +/* + * + */ + +test_set "message" text: +From: justin@example.com +To: carl@example.nl +Subject: Frop +Content-Type: multipart/mixed; boundary=limit + +This is a multi-part message in MIME format. + +--limit +Content-Type: text/plain + +This is a text message. + +--limit +Content-Type: text/html + +<html><body>This is HTML</body></html> + +--limit +Content-Type: application/sieve + +keep; + +--limit-- +. +; + +test "Full Content Type" { + if not body :text :contains "This is a text message" { + test_fail "failed to match text/plain content"; + } + + if not body :text :contains "This is HTML" { + test_fail "failed to match text/html content"; + } + + if body :text :contains "<html>" { + test_fail "erroneously matched text/html markup"; + } + + if body :text :contains "keep;" { + test_fail "body :text test matched non-text content"; + } +} + +/* + * + */ + +test_set "message" text: +From: Whomever <whoever@example.com> +To: Someone <someone@example.com> +Date: Sat, 10 Oct 2009 00:30:04 +0200 +Subject: whatever +Content-Type: multipart/mixed; boundary=outer + +This is a multi-part message in MIME format. + +--outer +Content-Type: multipart/alternative; boundary=inner + +This is a nested multi-part message in MIME format. + +--inner +Content-Type: text/plain; charset="us-ascii" + +Hello + +--inner +Content-Type: text/html; charset="us-ascii" + +<html><body>HTML Hello</body></html> + +--inner +Content-Type: application/xhtml+xml; charset="us-ascii" + +<html><body>XHTML Hello</body></html> + +--inner-- + +This is the end of the inner MIME multipart. + +--outer +Content-Type: message/rfc822 + +From: Someone Else +Subject: Hello, this is an elaborate request for you to finally say hello + already! + +Please say Hello + +--outer-- + +This is the end of the outer MIME multipart. +. +; + +/* RFC5173, Section 5.2: + * + * The search for MIME parts matching the :content specification is + * recursive and automatically descends into multipart and + * message/rfc822 MIME parts. All MIME parts with matching types are + * searched for the key strings. The test returns true if any + * combination of a searched MIME part and key-list argument match. + */ + +test "Nested Search" { + if not body :text :contains "Hello" { + test_fail "failed to match text/plain content"; + } + if not body :text :contains "HTML Hello" { + test_fail "failed to match text/html content"; + } + if not body :text :contains "XHTML Hello" { + test_fail "failed to match application/xhtml+xml content"; + } + if body :text :contains ["<html>", "body"] { + test_fail "erroneously matched text/html markup"; + } + if not body :text :contains "Please say Hello" { + test_fail "failed to match message/rfc822 body"; + } + if body :text :contains "MIME" { + test_fail "erroneously matched multipart prologue/epilogue text"; + } +} + +/* + * Broken/Empty parts + */ + +test_set "message" text: +From: Whomever <whoever@example.com> +To: Someone <someone@example.com> +Date: Sat, 10 Oct 2009 00:30:04 +0200 +Subject: whatever +Content-Type: multipart/mixed; boundary=outer + +This is a multi-part message in MIME format. + +--outer +Content-Type: text/html + +--outer +Content-Type: text/html; charset=utf-8 +Content-Transfer-Encoding: multipart/related +Content-Disposition: inline + +<html><body>Please say Hello</body></html> + +--outer-- + +This is the end of the outer MIME multipart. +. +; + +test "Nested Search" { + if body :text :contains "Hello" { + test_fail "Cannot match empty/broken part"; + } + if body :text :contains ["<html>", "body"] { + test_fail "erroneously matched text/html markup"; + } + if body :text :contains "MIME" { + test_fail "erroneously matched multipart prologue/epilogue text"; + } +} + |