summaryrefslogtreecommitdiffstats
path: root/pigeonhole/tests/extensions/body
diff options
context:
space:
mode:
Diffstat (limited to 'pigeonhole/tests/extensions/body')
-rw-r--r--pigeonhole/tests/extensions/body/basic.svtest97
-rw-r--r--pigeonhole/tests/extensions/body/content.svtest332
-rw-r--r--pigeonhole/tests/extensions/body/errors.svtest19
-rw-r--r--pigeonhole/tests/extensions/body/errors/syntax.sieve38
-rw-r--r--pigeonhole/tests/extensions/body/match-values.svtest55
-rw-r--r--pigeonhole/tests/extensions/body/raw.svtest85
-rw-r--r--pigeonhole/tests/extensions/body/text.svtest225
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";
+ }
+}
+