summaryrefslogtreecommitdiffstats
path: root/pigeonhole/tests/extensions/include
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 17:36:47 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 17:36:47 +0000
commit0441d265f2bb9da249c7abf333f0f771fadb4ab5 (patch)
tree3f3789daa2f6db22da6e55e92bee0062a7d613fe /pigeonhole/tests/extensions/include
parentInitial commit. (diff)
downloaddovecot-0441d265f2bb9da249c7abf333f0f771fadb4ab5.tar.xz
dovecot-0441d265f2bb9da249c7abf333f0f771fadb4ab5.zip
Adding upstream version 1:2.3.21+dfsg1.upstream/1%2.3.21+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'pigeonhole/tests/extensions/include')
-rw-r--r--pigeonhole/tests/extensions/include/errors.svtest149
-rw-r--r--pigeonhole/tests/extensions/include/errors/action-conflicts.sieve4
-rw-r--r--pigeonhole/tests/extensions/include/errors/circular-1.sieve5
-rw-r--r--pigeonhole/tests/extensions/include/errors/circular-2.sieve5
-rw-r--r--pigeonhole/tests/extensions/include/errors/circular-3.sieve5
-rw-r--r--pigeonhole/tests/extensions/include/errors/depth-limit.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/errors/generic.sieve7
-rw-r--r--pigeonhole/tests/extensions/include/errors/global-namespace.sieve13
-rw-r--r--pigeonhole/tests/extensions/include/errors/include-limit.sieve6
-rw-r--r--pigeonhole/tests/extensions/include/errors/scriptname.sieve25
-rw-r--r--pigeonhole/tests/extensions/include/errors/variables-inactive.sieve7
-rw-r--r--pigeonhole/tests/extensions/include/errors/variables.sieve23
-rw-r--r--pigeonhole/tests/extensions/include/execute.svtest68
-rw-r--r--pigeonhole/tests/extensions/include/execute/actions-fileinto.sieve5
-rw-r--r--pigeonhole/tests/extensions/include/execute/namespace.sieve26
-rw-r--r--pigeonhole/tests/extensions/include/execute/optional.sieve5
-rw-r--r--pigeonhole/tests/extensions/include/included-global/namespace.dict4
-rw-r--r--pigeonhole/tests/extensions/include/included-global/namespace.sieve4
-rw-r--r--pigeonhole/tests/extensions/include/included-global/rfc-ex1-spam_tests.sieve7
-rw-r--r--pigeonhole/tests/extensions/include/included/action-fileinto.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/action-reject.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/actions-fileinto1.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/actions-fileinto2.sieve4
-rw-r--r--pigeonhole/tests/extensions/include/included/actions-fileinto3.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/circular-one.sieve5
-rw-r--r--pigeonhole/tests/extensions/include/included/circular-three-2.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/circular-three-3.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/circular-three.sieve7
-rw-r--r--pigeonhole/tests/extensions/include/included/circular-two-2.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/circular-two.sieve7
-rw-r--r--pigeonhole/tests/extensions/include/included/depth-limit-1.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/depth-limit-2.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/depth-limit-3.sieve1
-rw-r--r--pigeonhole/tests/extensions/include/included/namespace.dict4
-rw-r--r--pigeonhole/tests/extensions/include/included/namespace.sieve4
-rw-r--r--pigeonhole/tests/extensions/include/included/once-1.sieve9
-rw-r--r--pigeonhole/tests/extensions/include/included/once-2.sieve12
-rw-r--r--pigeonhole/tests/extensions/include/included/once-3.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/once-4.sieve3
-rw-r--r--pigeonhole/tests/extensions/include/included/optional-1.sieve9
-rw-r--r--pigeonhole/tests/extensions/include/included/optional-2.sieve9
-rw-r--r--pigeonhole/tests/extensions/include/included/rfc-ex1-always_allow.sieve8
-rw-r--r--pigeonhole/tests/extensions/include/included/rfc-ex1-mailing_lists.sieve10
-rw-r--r--pigeonhole/tests/extensions/include/included/rfc-ex1-spam_tests.sieve10
-rw-r--r--pigeonhole/tests/extensions/include/included/rfc-ex2-spam_filter_script.sieve8
-rw-r--r--pigeonhole/tests/extensions/include/included/twice-1.sieve7
-rw-r--r--pigeonhole/tests/extensions/include/included/twice-2.sieve8
-rw-r--r--pigeonhole/tests/extensions/include/included/variables-included1.sieve7
-rw-r--r--pigeonhole/tests/extensions/include/included/variables-included2.sieve6
-rw-r--r--pigeonhole/tests/extensions/include/included/variables-included3.sieve8
-rw-r--r--pigeonhole/tests/extensions/include/once.svtest24
-rw-r--r--pigeonhole/tests/extensions/include/optional.svtest40
-rw-r--r--pigeonhole/tests/extensions/include/rfc-ex1-default.sieve6
-rw-r--r--pigeonhole/tests/extensions/include/rfc-ex2-default.sieve21
-rw-r--r--pigeonhole/tests/extensions/include/rfc.svtest13
-rw-r--r--pigeonhole/tests/extensions/include/twice.svtest20
-rw-r--r--pigeonhole/tests/extensions/include/variables.svtest29
57 files changed, 700 insertions, 0 deletions
diff --git a/pigeonhole/tests/extensions/include/errors.svtest b/pigeonhole/tests/extensions/include/errors.svtest
new file mode 100644
index 0000000..6f8b1cc
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors.svtest
@@ -0,0 +1,149 @@
+require "vnd.dovecot.testsuite";
+
+require "relational";
+require "comparator-i;ascii-numeric";
+
+/*
+ * Generic include errors
+ */
+
+test "Generic" {
+ if test_script_compile "errors/generic.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+test "Circular - direct" {
+ if test_script_compile "errors/circular-1.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+test "Circular - one intermittent" {
+ if test_script_compile "errors/circular-2.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "4" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+test "Circular - two intermittent" {
+ if test_script_compile "errors/circular-3.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "5" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Using global without variables required
+ */
+
+test "Variables inactive" {
+ if test_script_compile "errors/variables-inactive.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Generic variables errors
+ */
+
+test "Variables" {
+ if test_script_compile "errors/variables.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "3" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Global variable namespace
+ */
+
+test "Global Namespace" {
+ if test_script_compile "errors/global-namespace.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "4" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/*
+ * Invalid script names
+ */
+
+test "Invalid Script Names" {
+ if test_script_compile "errors/scriptname.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "8" {
+ test_fail "wrong number of errors reported";
+ }
+}
+
+/* Include limit */
+
+test "Include limit" {
+ test_config_set "sieve_include_max_includes" "3";
+ test_config_reload :extension "include";
+
+ if test_script_compile "errors/include-limit.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "2" {
+ test_fail "wrong number of errors reported";
+ }
+
+ test_config_set "sieve_include_max_includes" "255";
+ test_config_reload :extension "include";
+
+ if not test_script_compile "errors/include-limit.sieve" {
+ test_fail "compile should have succeeded";
+ }
+}
+
+/* Depth limit */
+
+test "Depth limit" {
+ test_config_set "sieve_include_max_nesting_depth" "2";
+ test_config_reload :extension "include";
+
+ if test_script_compile "errors/depth-limit.sieve" {
+ test_fail "compile should have failed";
+ }
+
+ if not test_error :count "eq" :comparator "i;ascii-numeric" "4" {
+ test_fail "wrong number of errors reported";
+ }
+
+ test_config_set "sieve_include_max_nesting_depth" "10";
+ test_config_reload :extension "include";
+
+ if not test_script_compile "errors/depth-limit.sieve" {
+ test_fail "compile should have succeeded";
+ }
+}
+
diff --git a/pigeonhole/tests/extensions/include/errors/action-conflicts.sieve b/pigeonhole/tests/extensions/include/errors/action-conflicts.sieve
new file mode 100644
index 0000000..ddeb42c
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/action-conflicts.sieve
@@ -0,0 +1,4 @@
+require "include";
+
+include "action-fileinto";
+include "action-reject";
diff --git a/pigeonhole/tests/extensions/include/errors/circular-1.sieve b/pigeonhole/tests/extensions/include/errors/circular-1.sieve
new file mode 100644
index 0000000..22b6f87
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/circular-1.sieve
@@ -0,0 +1,5 @@
+require "include";
+
+discard;
+
+include "circular-one";
diff --git a/pigeonhole/tests/extensions/include/errors/circular-2.sieve b/pigeonhole/tests/extensions/include/errors/circular-2.sieve
new file mode 100644
index 0000000..0cfa375
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/circular-2.sieve
@@ -0,0 +1,5 @@
+require "include";
+
+discard;
+
+include "circular-two";
diff --git a/pigeonhole/tests/extensions/include/errors/circular-3.sieve b/pigeonhole/tests/extensions/include/errors/circular-3.sieve
new file mode 100644
index 0000000..1ad95b6
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/circular-3.sieve
@@ -0,0 +1,5 @@
+require "include";
+
+discard;
+
+include "circular-three";
diff --git a/pigeonhole/tests/extensions/include/errors/depth-limit.sieve b/pigeonhole/tests/extensions/include/errors/depth-limit.sieve
new file mode 100644
index 0000000..93291b6
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/depth-limit.sieve
@@ -0,0 +1,3 @@
+require "include";
+
+include :personal "depth-limit-1";
diff --git a/pigeonhole/tests/extensions/include/errors/generic.sieve b/pigeonhole/tests/extensions/include/errors/generic.sieve
new file mode 100644
index 0000000..66eba18
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/generic.sieve
@@ -0,0 +1,7 @@
+require "include";
+
+# Non-existent sieve script
+include "frop.sieve";
+
+# Use of / in script names
+include "../frop.sieve";
diff --git a/pigeonhole/tests/extensions/include/errors/global-namespace.sieve b/pigeonhole/tests/extensions/include/errors/global-namespace.sieve
new file mode 100644
index 0000000..3827b60
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/global-namespace.sieve
@@ -0,0 +1,13 @@
+require "variables";
+require "include";
+
+# Invalid namespace
+set "globl.var" "frop";
+
+# Sub-namespace
+set "global.env.0" "12";
+
+# Invalid variable name
+set "global.12" "porf";
+
+
diff --git a/pigeonhole/tests/extensions/include/errors/include-limit.sieve b/pigeonhole/tests/extensions/include/errors/include-limit.sieve
new file mode 100644
index 0000000..f6689dd
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/include-limit.sieve
@@ -0,0 +1,6 @@
+require "include";
+
+include "rfc-ex1-always_allow";
+include "rfc-ex2-spam_filter_script";
+include "rfc-ex1-mailing_lists";
+include "rfc-ex1-spam_tests";
diff --git a/pigeonhole/tests/extensions/include/errors/scriptname.sieve b/pigeonhole/tests/extensions/include/errors/scriptname.sieve
new file mode 100644
index 0000000..9a10c3d
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/scriptname.sieve
@@ -0,0 +1,25 @@
+require "variables";
+require "include";
+require "encoded-character";
+
+# Slash
+include "../frop";
+
+# More slashes
+include "../../james/sieve/vacation";
+
+# 0000-001F; [CONTROL CHARACTERS]
+include "idiotic${unicode: 001a}";
+
+# 007F; DELETE
+include "idiotic${unicode: 007f}";
+
+# 0080-009F; [CONTROL CHARACTERS]
+include "idiotic${unicode: 0085}";
+
+# 2028; LINE SEPARATOR
+include "idiotic${unicode: 2028}";
+
+# 2029; PARAGRAPH SEPARATOR
+include "idiotic${unicode: 2029}";
+
diff --git a/pigeonhole/tests/extensions/include/errors/variables-inactive.sieve b/pigeonhole/tests/extensions/include/errors/variables-inactive.sieve
new file mode 100644
index 0000000..06e0df1
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/variables-inactive.sieve
@@ -0,0 +1,7 @@
+require "include";
+require "fileinto";
+
+global "friep";
+global "frop";
+
+fileinto "Frop";
diff --git a/pigeonhole/tests/extensions/include/errors/variables.sieve b/pigeonhole/tests/extensions/include/errors/variables.sieve
new file mode 100644
index 0000000..eac99f8
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/errors/variables.sieve
@@ -0,0 +1,23 @@
+require "include";
+require "variables";
+
+# Duplicate global declaration (not an error)
+global "frml";
+global "frml";
+
+keep;
+
+# Global after command not being require or global (not an error)
+global "friep";
+
+# DEPRECATED: import/export after command not being require or import/export
+export "friep";
+import "friep";
+
+# Marking local variable as global
+set "frutsels" "frop";
+global "frutsels";
+set "frutsels" "frop";
+
+
+
diff --git a/pigeonhole/tests/extensions/include/execute.svtest b/pigeonhole/tests/extensions/include/execute.svtest
new file mode 100644
index 0000000..734ac66
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/execute.svtest
@@ -0,0 +1,68 @@
+require "vnd.dovecot.testsuite";
+require "include";
+require "variables";
+
+test_set "message" text:
+From: idiot@example.com
+To: idiot@example.org
+Subject: Frop!
+
+Frop.
+.
+;
+
+test "Actions Fileinto" {
+ test_mailbox_create "aaaa";
+ test_mailbox_create "bbbb";
+
+ if not test_script_compile "execute/actions-fileinto.sieve" {
+ test_fail "failed to compile sieve script";
+ }
+
+ test_binary_save "actions-fileinto";
+ test_binary_load "actions-fileinto";
+
+ if not test_script_run {
+ test_fail "failed to execute sieve script";
+ }
+
+ if not test_result_execute {
+ test_fail "failed to execute result";
+ }
+
+ test_message :folder "aaaa" 0;
+
+ if not header "subject" "Frop!" {
+ test_fail "fileinto \"aaaa\" not executed.";
+ }
+
+ test_message :folder "bbbb" 0;
+
+ if not header "subject" "Frop!" {
+ test_fail "fileinto \"bbbb\" not executed.";
+ }
+}
+
+test "Namespace - file" {
+ if not test_script_compile "execute/namespace.sieve" {
+ test_fail "failed to compile sub-test";
+ }
+
+ if not test_script_run {
+ test_fail "failed to execute sub-test";
+ }
+}
+
+test "Namespace - dict" {
+ test_config_set "sieve" "dict:file:${tst.path}/included/namespace.dict";
+ test_config_set "sieve_global" "dict:file:${tst.path}/included-global/namespace.dict";
+ test_config_reload :extension "include";
+
+ if not test_script_compile "execute/namespace.sieve" {
+ test_fail "failed to compile sub-test";
+ }
+
+ if not test_script_run {
+ test_fail "failed to execute sub-test";
+ }
+}
diff --git a/pigeonhole/tests/extensions/include/execute/actions-fileinto.sieve b/pigeonhole/tests/extensions/include/execute/actions-fileinto.sieve
new file mode 100644
index 0000000..b0b8157
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/execute/actions-fileinto.sieve
@@ -0,0 +1,5 @@
+require "include";
+
+include "actions-fileinto1";
+include "actions-fileinto2";
+include "actions-fileinto3";
diff --git a/pigeonhole/tests/extensions/include/execute/namespace.sieve b/pigeonhole/tests/extensions/include/execute/namespace.sieve
new file mode 100644
index 0000000..cbe41a2
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/execute/namespace.sieve
@@ -0,0 +1,26 @@
+require "vnd.dovecot.testsuite";
+require "include";
+require "variables";
+
+set "global.a" "none";
+include :personal "namespace";
+
+if string "${global.a}" "none" {
+ test_fail "personal script not executed";
+}
+
+if not string "${global.a}" "personal" {
+ test_fail "executed global instead of personal script: ${global.a}";
+}
+
+set "global.a" "none";
+include :global "namespace";
+
+if string "{global.a}" "none" {
+ test_fail "global script not executed";
+}
+
+if not string "${global.a}" "global" {
+ test_fail "executed personal instead of global script: ${global.a}";
+}
+
diff --git a/pigeonhole/tests/extensions/include/execute/optional.sieve b/pigeonhole/tests/extensions/include/execute/optional.sieve
new file mode 100644
index 0000000..a6ad479
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/execute/optional.sieve
@@ -0,0 +1,5 @@
+require "include";
+
+include :optional "optional-1";
+include :optional "optional-2";
+include :optional "optional-3";
diff --git a/pigeonhole/tests/extensions/include/included-global/namespace.dict b/pigeonhole/tests/extensions/include/included-global/namespace.dict
new file mode 100644
index 0000000..8f52fd3
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included-global/namespace.dict
@@ -0,0 +1,4 @@
+priv/sieve/name/namespace
+1
+priv/sieve/data/1
+require ["variables", "include"]; set "global.a" "global";
diff --git a/pigeonhole/tests/extensions/include/included-global/namespace.sieve b/pigeonhole/tests/extensions/include/included-global/namespace.sieve
new file mode 100644
index 0000000..d11c2f1
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included-global/namespace.sieve
@@ -0,0 +1,4 @@
+require "include";
+require "variables";
+
+set "global.a" "global";
diff --git a/pigeonhole/tests/extensions/include/included-global/rfc-ex1-spam_tests.sieve b/pigeonhole/tests/extensions/include/included-global/rfc-ex1-spam_tests.sieve
new file mode 100644
index 0000000..340ceaf
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included-global/rfc-ex1-spam_tests.sieve
@@ -0,0 +1,7 @@
+require ["reject"];
+
+if anyof (header :contains "Subject" "$$",
+ header :contains "Subject" "Make money")
+{
+ reject "Not wanted";
+}
diff --git a/pigeonhole/tests/extensions/include/included/action-fileinto.sieve b/pigeonhole/tests/extensions/include/included/action-fileinto.sieve
new file mode 100644
index 0000000..9aafb95
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/action-fileinto.sieve
@@ -0,0 +1,3 @@
+require "fileinto";
+
+fileinto "frop";
diff --git a/pigeonhole/tests/extensions/include/included/action-reject.sieve b/pigeonhole/tests/extensions/include/included/action-reject.sieve
new file mode 100644
index 0000000..6e7b0b0
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/action-reject.sieve
@@ -0,0 +1,3 @@
+require "reject";
+
+reject "Ik heb geen zin in die rommel.";
diff --git a/pigeonhole/tests/extensions/include/included/actions-fileinto1.sieve b/pigeonhole/tests/extensions/include/included/actions-fileinto1.sieve
new file mode 100644
index 0000000..d4c5031
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/actions-fileinto1.sieve
@@ -0,0 +1,3 @@
+require "fileinto";
+
+fileinto "aaaa";
diff --git a/pigeonhole/tests/extensions/include/included/actions-fileinto2.sieve b/pigeonhole/tests/extensions/include/included/actions-fileinto2.sieve
new file mode 100644
index 0000000..f73da0d
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/actions-fileinto2.sieve
@@ -0,0 +1,4 @@
+require "fileinto";
+
+fileinto "bbbb";
+
diff --git a/pigeonhole/tests/extensions/include/included/actions-fileinto3.sieve b/pigeonhole/tests/extensions/include/included/actions-fileinto3.sieve
new file mode 100644
index 0000000..d4c5031
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/actions-fileinto3.sieve
@@ -0,0 +1,3 @@
+require "fileinto";
+
+fileinto "aaaa";
diff --git a/pigeonhole/tests/extensions/include/included/circular-one.sieve b/pigeonhole/tests/extensions/include/included/circular-one.sieve
new file mode 100644
index 0000000..2d60606
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/circular-one.sieve
@@ -0,0 +1,5 @@
+require "include";
+
+keep;
+
+include "circular-one";
diff --git a/pigeonhole/tests/extensions/include/included/circular-three-2.sieve b/pigeonhole/tests/extensions/include/included/circular-three-2.sieve
new file mode 100644
index 0000000..5199f21
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/circular-three-2.sieve
@@ -0,0 +1,3 @@
+require "include";
+
+include "circular-three-3";
diff --git a/pigeonhole/tests/extensions/include/included/circular-three-3.sieve b/pigeonhole/tests/extensions/include/included/circular-three-3.sieve
new file mode 100644
index 0000000..4c062cd
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/circular-three-3.sieve
@@ -0,0 +1,3 @@
+require "include";
+
+include "circular-three.sieve";
diff --git a/pigeonhole/tests/extensions/include/included/circular-three.sieve b/pigeonhole/tests/extensions/include/included/circular-three.sieve
new file mode 100644
index 0000000..13be546
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/circular-three.sieve
@@ -0,0 +1,7 @@
+require "include";
+
+keep;
+
+include "circular-three-2";
+
+
diff --git a/pigeonhole/tests/extensions/include/included/circular-two-2.sieve b/pigeonhole/tests/extensions/include/included/circular-two-2.sieve
new file mode 100644
index 0000000..d529214
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/circular-two-2.sieve
@@ -0,0 +1,3 @@
+require "include";
+
+include "circular-two.sieve";
diff --git a/pigeonhole/tests/extensions/include/included/circular-two.sieve b/pigeonhole/tests/extensions/include/included/circular-two.sieve
new file mode 100644
index 0000000..8a879cb
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/circular-two.sieve
@@ -0,0 +1,7 @@
+require "include";
+
+keep;
+
+include "circular-two-2";
+
+
diff --git a/pigeonhole/tests/extensions/include/included/depth-limit-1.sieve b/pigeonhole/tests/extensions/include/included/depth-limit-1.sieve
new file mode 100644
index 0000000..ce5571f
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/depth-limit-1.sieve
@@ -0,0 +1,3 @@
+require "include";
+
+include :personal "depth-limit-2";
diff --git a/pigeonhole/tests/extensions/include/included/depth-limit-2.sieve b/pigeonhole/tests/extensions/include/included/depth-limit-2.sieve
new file mode 100644
index 0000000..79c55e0
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/depth-limit-2.sieve
@@ -0,0 +1,3 @@
+require "include";
+
+include :personal "depth-limit-3";
diff --git a/pigeonhole/tests/extensions/include/included/depth-limit-3.sieve b/pigeonhole/tests/extensions/include/included/depth-limit-3.sieve
new file mode 100644
index 0000000..6203a21
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/depth-limit-3.sieve
@@ -0,0 +1 @@
+keep;
diff --git a/pigeonhole/tests/extensions/include/included/namespace.dict b/pigeonhole/tests/extensions/include/included/namespace.dict
new file mode 100644
index 0000000..35d7aaa
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/namespace.dict
@@ -0,0 +1,4 @@
+priv/sieve/name/namespace
+1
+priv/sieve/data/1
+require ["variables", "include"]; set "global.a" "personal";
diff --git a/pigeonhole/tests/extensions/include/included/namespace.sieve b/pigeonhole/tests/extensions/include/included/namespace.sieve
new file mode 100644
index 0000000..3f5738f
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/namespace.sieve
@@ -0,0 +1,4 @@
+require "include";
+require "variables";
+
+set "global.a" "personal";
diff --git a/pigeonhole/tests/extensions/include/included/once-1.sieve b/pigeonhole/tests/extensions/include/included/once-1.sieve
new file mode 100644
index 0000000..288d141
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/once-1.sieve
@@ -0,0 +1,9 @@
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "${result} ONE";
+
+return;
+
diff --git a/pigeonhole/tests/extensions/include/included/once-2.sieve b/pigeonhole/tests/extensions/include/included/once-2.sieve
new file mode 100644
index 0000000..abf29e5
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/once-2.sieve
@@ -0,0 +1,12 @@
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "${result} TWO";
+
+keep;
+
+include :once "once-1";
+
+return;
diff --git a/pigeonhole/tests/extensions/include/included/once-3.sieve b/pigeonhole/tests/extensions/include/included/once-3.sieve
new file mode 100644
index 0000000..739651e
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/once-3.sieve
@@ -0,0 +1,3 @@
+require "include";
+
+include "once-4";
diff --git a/pigeonhole/tests/extensions/include/included/once-4.sieve b/pigeonhole/tests/extensions/include/included/once-4.sieve
new file mode 100644
index 0000000..9cc1a47
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/once-4.sieve
@@ -0,0 +1,3 @@
+require "include";
+
+include :once "once-3";
diff --git a/pigeonhole/tests/extensions/include/included/optional-1.sieve b/pigeonhole/tests/extensions/include/included/optional-1.sieve
new file mode 100644
index 0000000..288d141
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/optional-1.sieve
@@ -0,0 +1,9 @@
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "${result} ONE";
+
+return;
+
diff --git a/pigeonhole/tests/extensions/include/included/optional-2.sieve b/pigeonhole/tests/extensions/include/included/optional-2.sieve
new file mode 100644
index 0000000..11920f5
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/optional-2.sieve
@@ -0,0 +1,9 @@
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "${result} TWO";
+
+keep;
+
diff --git a/pigeonhole/tests/extensions/include/included/rfc-ex1-always_allow.sieve b/pigeonhole/tests/extensions/include/included/rfc-ex1-always_allow.sieve
new file mode 100644
index 0000000..6dc8ddc
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/rfc-ex1-always_allow.sieve
@@ -0,0 +1,8 @@
+if header :is "From" "boss@example.com"
+{
+ keep;
+}
+elsif header :is "From" "ceo@example.com"
+{
+ keep;
+}
diff --git a/pigeonhole/tests/extensions/include/included/rfc-ex1-mailing_lists.sieve b/pigeonhole/tests/extensions/include/included/rfc-ex1-mailing_lists.sieve
new file mode 100644
index 0000000..d020972
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/rfc-ex1-mailing_lists.sieve
@@ -0,0 +1,10 @@
+require ["fileinto"];
+
+if header :is "Sender" "owner-ietf-mta-filters@imc.example.com"
+{
+ fileinto "lists.sieve";
+}
+elsif header :is "Sender" "owner-ietf-imapext@imc.example.com"
+{
+ fileinto "lists.imapext";
+}
diff --git a/pigeonhole/tests/extensions/include/included/rfc-ex1-spam_tests.sieve b/pigeonhole/tests/extensions/include/included/rfc-ex1-spam_tests.sieve
new file mode 100644
index 0000000..7916064
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/rfc-ex1-spam_tests.sieve
@@ -0,0 +1,10 @@
+require ["reject"];
+
+if header :contains "Subject" "XXXX"
+{
+ reject "Not wanted";
+}
+elsif header :is "From" "money@example.com"
+{
+ reject "Not wanted";
+}
diff --git a/pigeonhole/tests/extensions/include/included/rfc-ex2-spam_filter_script.sieve b/pigeonhole/tests/extensions/include/included/rfc-ex2-spam_filter_script.sieve
new file mode 100644
index 0000000..01ab984
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/rfc-ex2-spam_filter_script.sieve
@@ -0,0 +1,8 @@
+require ["variables", "include"];
+global ["test", "test_mailbox"];
+
+if header :contains "Subject" "${test}"
+{
+ set "test_mailbox" "spam-${test}";
+}
+
diff --git a/pigeonhole/tests/extensions/include/included/twice-1.sieve b/pigeonhole/tests/extensions/include/included/twice-1.sieve
new file mode 100644
index 0000000..a770a3b
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/twice-1.sieve
@@ -0,0 +1,7 @@
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "${result} TWO";
+
diff --git a/pigeonhole/tests/extensions/include/included/twice-2.sieve b/pigeonhole/tests/extensions/include/included/twice-2.sieve
new file mode 100644
index 0000000..eff9429
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/twice-2.sieve
@@ -0,0 +1,8 @@
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "${result} THREE";
+
+include "twice-1";
diff --git a/pigeonhole/tests/extensions/include/included/variables-included1.sieve b/pigeonhole/tests/extensions/include/included/variables-included1.sieve
new file mode 100644
index 0000000..5f6cb2f
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/variables-included1.sieve
@@ -0,0 +1,7 @@
+require "include";
+require "variables";
+
+global ["value1"];
+global ["result1"];
+
+set "result1" "${value1} ${global.value2}";
diff --git a/pigeonhole/tests/extensions/include/included/variables-included2.sieve b/pigeonhole/tests/extensions/include/included/variables-included2.sieve
new file mode 100644
index 0000000..135e03b
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/variables-included2.sieve
@@ -0,0 +1,6 @@
+require "include";
+require "variables";
+
+global ["value3", "value4"];
+
+set "global.result2" "${value3} ${value4}";
diff --git a/pigeonhole/tests/extensions/include/included/variables-included3.sieve b/pigeonhole/tests/extensions/include/included/variables-included3.sieve
new file mode 100644
index 0000000..51bb786
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/included/variables-included3.sieve
@@ -0,0 +1,8 @@
+require "include";
+require "variables";
+
+global "result1";
+global "result2";
+global "result";
+
+set "result" "${result1} ${result2}";
diff --git a/pigeonhole/tests/extensions/include/once.svtest b/pigeonhole/tests/extensions/include/once.svtest
new file mode 100644
index 0000000..3395c6b
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/once.svtest
@@ -0,0 +1,24 @@
+require "vnd.dovecot.testsuite";
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "";
+
+test "Included Once" {
+ include "once-1";
+ include "once-2";
+
+ if string "${result}" " ONE TWO ONE" {
+ test_fail "duplicate included :once script";
+ }
+
+ if not string "${result}" " ONE TWO" {
+ test_fail "unexpected result value: ${result}";
+ }
+}
+
+test "Included Once recursive" {
+ include "once-3";
+}
diff --git a/pigeonhole/tests/extensions/include/optional.svtest b/pigeonhole/tests/extensions/include/optional.svtest
new file mode 100644
index 0000000..345f830
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/optional.svtest
@@ -0,0 +1,40 @@
+require "vnd.dovecot.testsuite";
+require "include";
+require "variables";
+
+global "result";
+set "result" "";
+
+test "Included Optional" {
+ include :optional "optional-1";
+ include :optional "optional-2";
+
+ if not string "${result}" " ONE TWO" {
+ test_fail "unexpected result value: ${result}";
+ }
+
+ # missing
+ include :optional "optional-3";
+
+ if not string "${result}" " ONE TWO" {
+ test_fail "unexpected result value after missing script: ${result}";
+ }
+}
+
+
+test "Included Optional - Binary" {
+ if not test_script_compile "execute/optional.sieve" {
+ test_fail "failed to compile sieve script";
+ }
+
+ test_binary_save "optional";
+ test_binary_load "optional";
+
+ if not test_script_run {
+ test_fail "failed to execute sieve script";
+ }
+
+ if not string "${result}" " ONE TWO" {
+ test_fail "unexpected result value: ${result}";
+ }
+}
diff --git a/pigeonhole/tests/extensions/include/rfc-ex1-default.sieve b/pigeonhole/tests/extensions/include/rfc-ex1-default.sieve
new file mode 100644
index 0000000..5a8cb52
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/rfc-ex1-default.sieve
@@ -0,0 +1,6 @@
+require ["include"];
+
+include :personal "rfc-ex1-always_allow";
+include :global "rfc-ex1-spam_tests";
+include :personal "rfc-ex1-spam_tests";
+include :personal "rfc-ex1-mailing_lists";
diff --git a/pigeonhole/tests/extensions/include/rfc-ex2-default.sieve b/pigeonhole/tests/extensions/include/rfc-ex2-default.sieve
new file mode 100644
index 0000000..8b1bf4d
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/rfc-ex2-default.sieve
@@ -0,0 +1,21 @@
+require ["variables", "include", "relational", "fileinto"];
+global "test";
+global "test_mailbox";
+
+# The included script may contain repetitive code that is
+# effectively a subroutine that can be factored out.
+set "test" "$$";
+include "rfc-ex2-spam_filter_script";
+
+set "test" "Make money";
+include "rfc-ex2-spam_filter_script";
+
+# Message will be filed according to the test that matched last.
+if string :count "eq" "${test_mailbox}" "1"
+{
+ fileinto "INBOX${test_mailbox}";
+ stop;
+}
+
+# If nothing matched, the message is implicitly kept.
+
diff --git a/pigeonhole/tests/extensions/include/rfc.svtest b/pigeonhole/tests/extensions/include/rfc.svtest
new file mode 100644
index 0000000..00908ac
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/rfc.svtest
@@ -0,0 +1,13 @@
+require "vnd.dovecot.testsuite";
+
+test "RFC example 1" {
+ if not test_script_compile "rfc-ex1-default.sieve" {
+ test_fail "failed to compile sieve script";
+ }
+}
+
+test "RFC example 2" {
+ if not test_script_compile "rfc-ex2-default.sieve" {
+ test_fail "failed to compile sieve script";
+ }
+}
diff --git a/pigeonhole/tests/extensions/include/twice.svtest b/pigeonhole/tests/extensions/include/twice.svtest
new file mode 100644
index 0000000..5cd5da2
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/twice.svtest
@@ -0,0 +1,20 @@
+require "vnd.dovecot.testsuite";
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "ONE";
+
+test "Twice included" {
+ include "twice-1";
+ include "twice-2";
+
+ if string "${result}" "ONE TWO THREE" {
+ test_fail "duplicate include failed";
+ }
+
+ if not string "${result}" "ONE TWO THREE TWO" {
+ test_fail "unexpected result: ${result}";
+ }
+}
diff --git a/pigeonhole/tests/extensions/include/variables.svtest b/pigeonhole/tests/extensions/include/variables.svtest
new file mode 100644
index 0000000..5c4f8d8
--- /dev/null
+++ b/pigeonhole/tests/extensions/include/variables.svtest
@@ -0,0 +1,29 @@
+require "vnd.dovecot.testsuite";
+
+require "include";
+require "variables";
+
+global ["value1", "value2"];
+set "value1" "Works";
+set "value2" "fine.";
+
+global ["value3", "value4"];
+set "value3" "Yeah";
+set "value4" "it does.";
+
+include "variables-included1";
+include "variables-included2";
+include "variables-included3";
+
+global "result";
+
+test "Basic" {
+ if not string :is "${result}" "Works fine. Yeah it does." {
+ test_fail "invalid result: ${result}";
+ }
+
+ if string :is "${result}" "nonsense" {
+ test_fail "string test succeeds inappropriately";
+ }
+}
+