summary refs log tree commit diff
path: root/lib/tests/modules
diff options
context:
space:
mode:
Diffstat (limited to 'lib/tests/modules')
-rw-r--r--lib/tests/modules/adhoc-freeformType-survives-type-merge.nix14
-rw-r--r--lib/tests/modules/alias-with-priority-can-override.nix55
-rw-r--r--lib/tests/modules/alias-with-priority.nix55
-rw-r--r--lib/tests/modules/attrsOf-conditional-check.nix7
-rw-r--r--lib/tests/modules/attrsOf-lazy-check.nix7
-rw-r--r--lib/tests/modules/declare-attrsOf.nix13
-rw-r--r--lib/tests/modules/declare-attrsOfSub-any-enable.nix29
-rw-r--r--lib/tests/modules/declare-bare-submodule-deep-option-duplicate.nix10
-rw-r--r--lib/tests/modules/declare-bare-submodule-deep-option.nix10
-rw-r--r--lib/tests/modules/declare-bare-submodule-nested-option.nix19
-rw-r--r--lib/tests/modules/declare-bare-submodule.nix18
-rw-r--r--lib/tests/modules/declare-coerced-value-unsound.nix10
-rw-r--r--lib/tests/modules/declare-coerced-value.nix10
-rw-r--r--lib/tests/modules/declare-either.nix5
-rw-r--r--lib/tests/modules/declare-enable-nested.nix14
-rw-r--r--lib/tests/modules/declare-enable.nix14
-rw-r--r--lib/tests/modules/declare-int-between-value.nix9
-rw-r--r--lib/tests/modules/declare-int-positive-value-nested.nix9
-rw-r--r--lib/tests/modules/declare-int-positive-value.nix9
-rw-r--r--lib/tests/modules/declare-int-unsigned-value.nix9
-rw-r--r--lib/tests/modules/declare-lazyAttrsOf.nix6
-rw-r--r--lib/tests/modules/declare-oneOf.nix9
-rw-r--r--lib/tests/modules/declare-set.nix12
-rw-r--r--lib/tests/modules/declare-submodule-via-evalModules.nix28
-rw-r--r--lib/tests/modules/declare-submoduleWith-modules.nix28
-rw-r--r--lib/tests/modules/declare-submoduleWith-noshorthand.nix13
-rw-r--r--lib/tests/modules/declare-submoduleWith-path.nix12
-rw-r--r--lib/tests/modules/declare-submoduleWith-shorthand.nix14
-rw-r--r--lib/tests/modules/declare-submoduleWith-special.nix17
-rw-r--r--lib/tests/modules/declare-variants.nix9
-rw-r--r--lib/tests/modules/default.nix8
-rw-r--r--lib/tests/modules/define-_module-args-custom.nix7
-rw-r--r--lib/tests/modules/define-attrsOfSub-bar-enable.nix3
-rw-r--r--lib/tests/modules/define-attrsOfSub-bar.nix3
-rw-r--r--lib/tests/modules/define-attrsOfSub-foo-enable-force.nix5
-rw-r--r--lib/tests/modules/define-attrsOfSub-foo-enable-if.nix5
-rw-r--r--lib/tests/modules/define-attrsOfSub-foo-enable.nix3
-rw-r--r--lib/tests/modules/define-attrsOfSub-foo-force-enable.nix7
-rw-r--r--lib/tests/modules/define-attrsOfSub-foo-if-enable.nix7
-rw-r--r--lib/tests/modules/define-attrsOfSub-foo.nix3
-rw-r--r--lib/tests/modules/define-attrsOfSub-force-foo-enable.nix7
-rw-r--r--lib/tests/modules/define-attrsOfSub-if-foo-enable.nix7
-rw-r--r--lib/tests/modules/define-bare-submodule-values.nix4
-rw-r--r--lib/tests/modules/define-enable-force.nix5
-rw-r--r--lib/tests/modules/define-enable-with-custom-arg.nix7
-rw-r--r--lib/tests/modules/define-enable.nix3
-rw-r--r--lib/tests/modules/define-force-attrsOfSub-foo-enable.nix5
-rw-r--r--lib/tests/modules/define-force-enable.nix5
-rw-r--r--lib/tests/modules/define-if-attrsOfSub-foo-enable.nix5
-rw-r--r--lib/tests/modules/define-module-check.nix3
-rw-r--r--lib/tests/modules/define-option-dependently-nested.nix16
-rw-r--r--lib/tests/modules/define-option-dependently.nix16
-rw-r--r--lib/tests/modules/define-shorthandOnlyDefinesConfig-true.nix1
-rw-r--r--lib/tests/modules/define-submoduleWith-noshorthand.nix3
-rw-r--r--lib/tests/modules/define-submoduleWith-shorthand.nix3
-rw-r--r--lib/tests/modules/define-value-int-negative.nix3
-rw-r--r--lib/tests/modules/define-value-int-positive.nix3
-rw-r--r--lib/tests/modules/define-value-int-zero.nix3
-rw-r--r--lib/tests/modules/define-value-list.nix3
-rw-r--r--lib/tests/modules/define-value-string-arbitrary.nix3
-rw-r--r--lib/tests/modules/define-value-string-bigint.nix3
-rw-r--r--lib/tests/modules/define-value-string-properties.nix12
-rw-r--r--lib/tests/modules/define-value-string.nix3
-rw-r--r--lib/tests/modules/define-variant.nix22
-rw-r--r--lib/tests/modules/disable-declare-enable.nix5
-rw-r--r--lib/tests/modules/disable-define-enable.nix5
-rw-r--r--lib/tests/modules/disable-enable-modules.nix5
-rw-r--r--lib/tests/modules/disable-recursive/bar.nix5
-rw-r--r--lib/tests/modules/disable-recursive/disable-bar.nix7
-rw-r--r--lib/tests/modules/disable-recursive/disable-foo.nix7
-rw-r--r--lib/tests/modules/disable-recursive/foo.nix5
-rw-r--r--lib/tests/modules/disable-recursive/main.nix8
-rw-r--r--lib/tests/modules/emptyValues.nix36
-rw-r--r--lib/tests/modules/freeform-attrsOf.nix3
-rw-r--r--lib/tests/modules/freeform-lazyAttrsOf.nix3
-rw-r--r--lib/tests/modules/freeform-nested.nix14
-rw-r--r--lib/tests/modules/freeform-str-dep-unstr.nix8
-rw-r--r--lib/tests/modules/freeform-submodules.nix22
-rw-r--r--lib/tests/modules/freeform-unstr-dep-str.nix8
-rw-r--r--lib/tests/modules/functionTo/list-order.nix25
-rw-r--r--lib/tests/modules/functionTo/merging-attrs.nix27
-rw-r--r--lib/tests/modules/functionTo/merging-list.nix24
-rw-r--r--lib/tests/modules/functionTo/trivial.nix17
-rw-r--r--lib/tests/modules/functionTo/wrong-type.nix18
-rw-r--r--lib/tests/modules/import-custom-arg.nix6
-rw-r--r--lib/tests/modules/import-from-store.nix11
-rw-r--r--lib/tests/modules/optionTypeFile.nix28
-rw-r--r--lib/tests/modules/optionTypeMerging.nix27
-rw-r--r--lib/tests/modules/raw.nix30
-rw-r--r--lib/tests/modules/types-anything/attrs-coercible.nix12
-rw-r--r--lib/tests/modules/types-anything/equal-atoms.nix26
-rw-r--r--lib/tests/modules/types-anything/functions.nix23
-rw-r--r--lib/tests/modules/types-anything/lists.nix16
-rw-r--r--lib/tests/modules/types-anything/mk-mods.nix44
-rw-r--r--lib/tests/modules/types-anything/nested-attrs.nix22
95 files changed, 1167 insertions, 0 deletions
diff --git a/lib/tests/modules/adhoc-freeformType-survives-type-merge.nix b/lib/tests/modules/adhoc-freeformType-survives-type-merge.nix
new file mode 100644
index 00000000000..3cefb543c25
--- /dev/null
+++ b/lib/tests/modules/adhoc-freeformType-survives-type-merge.nix
@@ -0,0 +1,14 @@
+{ lib, ... }: {
+  options.dummy = lib.mkOption { type = lib.types.anything; default = {}; };
+  freeformType =
+    let
+      a = lib.types.attrsOf (lib.types.submodule { options.bar = lib.mkOption { }; });
+    in
+    # modifying types like this breaks type merging.
+    # This test makes sure that type merging is not performed when only a single declaration exists.
+    # Don't modify types in practice!
+    a // {
+      merge = loc: defs: { freeformItems = a.merge loc defs; };
+    };
+  config.foo.bar = "ok";
+}
diff --git a/lib/tests/modules/alias-with-priority-can-override.nix b/lib/tests/modules/alias-with-priority-can-override.nix
new file mode 100644
index 00000000000..9a18c9d9f61
--- /dev/null
+++ b/lib/tests/modules/alias-with-priority-can-override.nix
@@ -0,0 +1,55 @@
+# This is a test to show that mkAliasOptionModule sets the priority correctly
+# for aliased options.
+#
+# This test shows that an alias with a high priority is able to override
+# a non-aliased option.
+
+{ config, lib, ... }:
+
+with lib;
+
+{
+  options = {
+    # A simple boolean option that can be enabled or disabled.
+    enable = lib.mkOption {
+      type = types.nullOr types.bool;
+      default = null;
+      example = true;
+      description = ''
+        Some descriptive text
+      '';
+    };
+
+    # mkAliasOptionModule sets warnings, so this has to be defined.
+    warnings = mkOption {
+      internal = true;
+      default = [];
+      type = types.listOf types.str;
+      example = [ "The `foo' service is deprecated and will go away soon!" ];
+      description = ''
+        This option allows modules to show warnings to users during
+        the evaluation of the system configuration.
+      '';
+    };
+  };
+
+  imports = [
+    # Create an alias for the "enable" option.
+    (mkAliasOptionModule [ "enableAlias" ] [ "enable" ])
+
+    # Disable the aliased option with a high priority so it
+    # should override the next import.
+    ( { config, lib, ... }:
+      {
+        enableAlias = lib.mkForce false;
+      }
+    )
+
+    # Enable the normal (non-aliased) option.
+    ( { config, lib, ... }:
+      {
+        enable = true;
+      }
+    )
+  ];
+}
diff --git a/lib/tests/modules/alias-with-priority.nix b/lib/tests/modules/alias-with-priority.nix
new file mode 100644
index 00000000000..a35a06fc697
--- /dev/null
+++ b/lib/tests/modules/alias-with-priority.nix
@@ -0,0 +1,55 @@
+# This is a test to show that mkAliasOptionModule sets the priority correctly
+# for aliased options.
+#
+# This test shows that an alias with a low priority is able to be overridden
+# with a non-aliased option.
+
+{ config, lib, ... }:
+
+with lib;
+
+{
+  options = {
+    # A simple boolean option that can be enabled or disabled.
+    enable = lib.mkOption {
+      type = types.nullOr types.bool;
+      default = null;
+      example = true;
+      description = ''
+        Some descriptive text
+      '';
+    };
+
+    # mkAliasOptionModule sets warnings, so this has to be defined.
+    warnings = mkOption {
+      internal = true;
+      default = [];
+      type = types.listOf types.str;
+      example = [ "The `foo' service is deprecated and will go away soon!" ];
+      description = ''
+        This option allows modules to show warnings to users during
+        the evaluation of the system configuration.
+      '';
+    };
+  };
+
+  imports = [
+    # Create an alias for the "enable" option.
+    (mkAliasOptionModule [ "enableAlias" ] [ "enable" ])
+
+    # Disable the aliased option, but with a default (low) priority so it
+    # should be able to be overridden by the next import.
+    ( { config, lib, ... }:
+      {
+        enableAlias = lib.mkDefault false;
+      }
+    )
+
+    # Enable the normal (non-aliased) option.
+    ( { config, lib, ... }:
+      {
+        enable = true;
+      }
+    )
+  ];
+}
diff --git a/lib/tests/modules/attrsOf-conditional-check.nix b/lib/tests/modules/attrsOf-conditional-check.nix
new file mode 100644
index 00000000000..0f00ebca155
--- /dev/null
+++ b/lib/tests/modules/attrsOf-conditional-check.nix
@@ -0,0 +1,7 @@
+{ lib, config, ... }: {
+  options.conditionalWorks = lib.mkOption {
+    default = ! config.value ? foo;
+  };
+
+  config.value.foo = lib.mkIf false "should not be defined";
+}
diff --git a/lib/tests/modules/attrsOf-lazy-check.nix b/lib/tests/modules/attrsOf-lazy-check.nix
new file mode 100644
index 00000000000..ec5b418b15a
--- /dev/null
+++ b/lib/tests/modules/attrsOf-lazy-check.nix
@@ -0,0 +1,7 @@
+{ lib, config, ... }: {
+  options.isLazy = lib.mkOption {
+    default = ! config.value ? foo;
+  };
+
+  config.value.bar = throw "is not lazy";
+}
diff --git a/lib/tests/modules/declare-attrsOf.nix b/lib/tests/modules/declare-attrsOf.nix
new file mode 100644
index 00000000000..d19964064b2
--- /dev/null
+++ b/lib/tests/modules/declare-attrsOf.nix
@@ -0,0 +1,13 @@
+{ lib, ... }:
+let
+  deathtrapArgs = lib.mapAttrs
+    (k: _: throw "The module system is too strict, accessing an unused option's ${k} mkOption-attribute.")
+    (lib.functionArgs lib.mkOption);
+in
+{
+  options.value = lib.mkOption {
+    type = lib.types.attrsOf lib.types.str;
+    default = {};
+  };
+  options.testing-laziness-so-don't-read-me = lib.mkOption deathtrapArgs;
+}
diff --git a/lib/tests/modules/declare-attrsOfSub-any-enable.nix b/lib/tests/modules/declare-attrsOfSub-any-enable.nix
new file mode 100644
index 00000000000..986d07227e1
--- /dev/null
+++ b/lib/tests/modules/declare-attrsOfSub-any-enable.nix
@@ -0,0 +1,29 @@
+{ lib, ... }:
+
+let
+  submod = { ... }: {
+    options = {
+      enable = lib.mkOption {
+        default = false;
+        example = true;
+        type = lib.types.bool;
+        description = ''
+          Some descriptive text
+        '';
+      };
+    };
+  };
+in
+
+{
+  options = {
+    attrsOfSub = lib.mkOption {
+      default = {};
+      example = {};
+      type = lib.types.attrsOf (lib.types.submodule [ submod ]);
+      description = ''
+        Some descriptive text
+      '';
+    };
+  };
+}
diff --git a/lib/tests/modules/declare-bare-submodule-deep-option-duplicate.nix b/lib/tests/modules/declare-bare-submodule-deep-option-duplicate.nix
new file mode 100644
index 00000000000..06ad1f6e0a5
--- /dev/null
+++ b/lib/tests/modules/declare-bare-submodule-deep-option-duplicate.nix
@@ -0,0 +1,10 @@
+{ lib, ... }:
+let
+  inherit (lib) mkOption types;
+in
+{
+  options.bare-submodule.deep = mkOption {
+    type = types.int;
+    default = 2;
+  };
+}
diff --git a/lib/tests/modules/declare-bare-submodule-deep-option.nix b/lib/tests/modules/declare-bare-submodule-deep-option.nix
new file mode 100644
index 00000000000..06ad1f6e0a5
--- /dev/null
+++ b/lib/tests/modules/declare-bare-submodule-deep-option.nix
@@ -0,0 +1,10 @@
+{ lib, ... }:
+let
+  inherit (lib) mkOption types;
+in
+{
+  options.bare-submodule.deep = mkOption {
+    type = types.int;
+    default = 2;
+  };
+}
diff --git a/lib/tests/modules/declare-bare-submodule-nested-option.nix b/lib/tests/modules/declare-bare-submodule-nested-option.nix
new file mode 100644
index 00000000000..da125c84b25
--- /dev/null
+++ b/lib/tests/modules/declare-bare-submodule-nested-option.nix
@@ -0,0 +1,19 @@
+{ config, lib, ... }:
+let
+  inherit (lib) mkOption types;
+in
+{
+  options.bare-submodule = mkOption {
+    type = types.submoduleWith {
+      shorthandOnlyDefinesConfig = config.shorthandOnlyDefinesConfig;
+      modules = [
+        {
+          options.nested = mkOption {
+            type = types.int;
+            default = 1;
+          };
+        }
+      ];
+    };
+  };
+}
diff --git a/lib/tests/modules/declare-bare-submodule.nix b/lib/tests/modules/declare-bare-submodule.nix
new file mode 100644
index 00000000000..5402f4ff5a5
--- /dev/null
+++ b/lib/tests/modules/declare-bare-submodule.nix
@@ -0,0 +1,18 @@
+{ config, lib, ... }:
+let
+  inherit (lib) mkOption types;
+in
+{
+  options.bare-submodule = mkOption {
+    type = types.submoduleWith {
+      modules = [ ];
+      shorthandOnlyDefinesConfig = config.shorthandOnlyDefinesConfig;
+    };
+    default = {};
+  };
+
+  # config-dependent options: won't recommend, but useful for making this test parameterized
+  options.shorthandOnlyDefinesConfig = mkOption {
+    default = false;
+  };
+}
diff --git a/lib/tests/modules/declare-coerced-value-unsound.nix b/lib/tests/modules/declare-coerced-value-unsound.nix
new file mode 100644
index 00000000000..7a017f24e77
--- /dev/null
+++ b/lib/tests/modules/declare-coerced-value-unsound.nix
@@ -0,0 +1,10 @@
+{ lib, ... }:
+
+{
+  options = {
+    value = lib.mkOption {
+      default = "12";
+      type = lib.types.coercedTo lib.types.str lib.toInt lib.types.ints.s8;
+    };
+  };
+}
diff --git a/lib/tests/modules/declare-coerced-value.nix b/lib/tests/modules/declare-coerced-value.nix
new file mode 100644
index 00000000000..76b12ad53f0
--- /dev/null
+++ b/lib/tests/modules/declare-coerced-value.nix
@@ -0,0 +1,10 @@
+{ lib, ... }:
+
+{
+  options = {
+    value = lib.mkOption {
+      default = 42;
+      type = lib.types.coercedTo lib.types.int builtins.toString lib.types.str;
+    };
+  };
+}
diff --git a/lib/tests/modules/declare-either.nix b/lib/tests/modules/declare-either.nix
new file mode 100644
index 00000000000..5a0fa978a13
--- /dev/null
+++ b/lib/tests/modules/declare-either.nix
@@ -0,0 +1,5 @@
+{ lib, ... }: {
+  options.value = lib.mkOption {
+    type = lib.types.either lib.types.int lib.types.str;
+  };
+}
diff --git a/lib/tests/modules/declare-enable-nested.nix b/lib/tests/modules/declare-enable-nested.nix
new file mode 100644
index 00000000000..c8da8273cba
--- /dev/null
+++ b/lib/tests/modules/declare-enable-nested.nix
@@ -0,0 +1,14 @@
+{ lib, ... }:
+
+{
+  options.set = {
+    enable = lib.mkOption {
+      default = false;
+      example = true;
+      type = lib.types.bool;
+      description = ''
+        Some descriptive text
+      '';
+    };
+  };
+}
diff --git a/lib/tests/modules/declare-enable.nix b/lib/tests/modules/declare-enable.nix
new file mode 100644
index 00000000000..ebee243c756
--- /dev/null
+++ b/lib/tests/modules/declare-enable.nix
@@ -0,0 +1,14 @@
+{ lib, ... }:
+
+{
+  options = {
+    enable = lib.mkOption {
+      default = false;
+      example = true;
+      type = lib.types.bool;
+      description = ''
+        Some descriptive text
+      '';
+    };
+  };
+}
diff --git a/lib/tests/modules/declare-int-between-value.nix b/lib/tests/modules/declare-int-between-value.nix
new file mode 100644
index 00000000000..8b2624cc5d6
--- /dev/null
+++ b/lib/tests/modules/declare-int-between-value.nix
@@ -0,0 +1,9 @@
+{ lib, ... }:
+
+{
+  options = {
+    value = lib.mkOption {
+      type = lib.types.ints.between (-21) 43;
+    };
+  };
+}
diff --git a/lib/tests/modules/declare-int-positive-value-nested.nix b/lib/tests/modules/declare-int-positive-value-nested.nix
new file mode 100644
index 00000000000..72d2fb89fc3
--- /dev/null
+++ b/lib/tests/modules/declare-int-positive-value-nested.nix
@@ -0,0 +1,9 @@
+{ lib, ... }:
+
+{
+  options.set = {
+    value = lib.mkOption {
+      type = lib.types.ints.positive;
+    };
+  };
+}
diff --git a/lib/tests/modules/declare-int-positive-value.nix b/lib/tests/modules/declare-int-positive-value.nix
new file mode 100644
index 00000000000..6e48c6ac8fe
--- /dev/null
+++ b/lib/tests/modules/declare-int-positive-value.nix
@@ -0,0 +1,9 @@
+{ lib, ... }:
+
+{
+  options = {
+    value = lib.mkOption {
+      type = lib.types.ints.positive;
+    };
+  };
+}
diff --git a/lib/tests/modules/declare-int-unsigned-value.nix b/lib/tests/modules/declare-int-unsigned-value.nix
new file mode 100644
index 00000000000..05d0eff01c9
--- /dev/null
+++ b/lib/tests/modules/declare-int-unsigned-value.nix
@@ -0,0 +1,9 @@
+{ lib, ... }:
+
+{
+  options = {
+    value = lib.mkOption {
+      type = lib.types.ints.unsigned;
+    };
+  };
+}
diff --git a/lib/tests/modules/declare-lazyAttrsOf.nix b/lib/tests/modules/declare-lazyAttrsOf.nix
new file mode 100644
index 00000000000..1d9fec25f90
--- /dev/null
+++ b/lib/tests/modules/declare-lazyAttrsOf.nix
@@ -0,0 +1,6 @@
+{ lib, ... }: {
+  options.value = lib.mkOption {
+    type = lib.types.lazyAttrsOf (lib.types.str // { emptyValue.value = "empty"; });
+    default = {};
+  };
+}
diff --git a/lib/tests/modules/declare-oneOf.nix b/lib/tests/modules/declare-oneOf.nix
new file mode 100644
index 00000000000..df092a14f81
--- /dev/null
+++ b/lib/tests/modules/declare-oneOf.nix
@@ -0,0 +1,9 @@
+{ lib, ... }: {
+  options.value = lib.mkOption {
+    type = lib.types.oneOf [
+      lib.types.int
+      (lib.types.listOf lib.types.int)
+      lib.types.str
+    ];
+  };
+}
diff --git a/lib/tests/modules/declare-set.nix b/lib/tests/modules/declare-set.nix
new file mode 100644
index 00000000000..853418531a8
--- /dev/null
+++ b/lib/tests/modules/declare-set.nix
@@ -0,0 +1,12 @@
+{ lib, ... }:
+
+{
+  options.set = lib.mkOption {
+    default = { };
+    example = { a = 1; };
+    type = lib.types.attrsOf lib.types.int;
+    description = ''
+      Some descriptive text
+    '';
+  };
+}
diff --git a/lib/tests/modules/declare-submodule-via-evalModules.nix b/lib/tests/modules/declare-submodule-via-evalModules.nix
new file mode 100644
index 00000000000..2841c64a073
--- /dev/null
+++ b/lib/tests/modules/declare-submodule-via-evalModules.nix
@@ -0,0 +1,28 @@
+{ lib, ... }: {
+  options.submodule = lib.mkOption {
+    inherit (lib.evalModules {
+      modules = [
+        {
+          options.inner = lib.mkOption {
+            type = lib.types.bool;
+            default = false;
+          };
+        }
+      ];
+    }) type;
+    default = {};
+  };
+
+  config.submodule = lib.mkMerge [
+    ({ lib, ... }: {
+      options.outer = lib.mkOption {
+        type = lib.types.bool;
+        default = false;
+      };
+    })
+    {
+      inner = true;
+      outer = true;
+    }
+  ];
+}
diff --git a/lib/tests/modules/declare-submoduleWith-modules.nix b/lib/tests/modules/declare-submoduleWith-modules.nix
new file mode 100644
index 00000000000..a8b82d17688
--- /dev/null
+++ b/lib/tests/modules/declare-submoduleWith-modules.nix
@@ -0,0 +1,28 @@
+{ lib, ... }: {
+  options.submodule = lib.mkOption {
+    type = lib.types.submoduleWith {
+      modules = [
+        {
+          options.inner = lib.mkOption {
+            type = lib.types.bool;
+            default = false;
+          };
+        }
+      ];
+    };
+    default = {};
+  };
+
+  config.submodule = lib.mkMerge [
+    ({ lib, ... }: {
+      options.outer = lib.mkOption {
+        type = lib.types.bool;
+        default = false;
+      };
+    })
+    {
+      inner = true;
+      outer = true;
+    }
+  ];
+}
diff --git a/lib/tests/modules/declare-submoduleWith-noshorthand.nix b/lib/tests/modules/declare-submoduleWith-noshorthand.nix
new file mode 100644
index 00000000000..af3b4ba470f
--- /dev/null
+++ b/lib/tests/modules/declare-submoduleWith-noshorthand.nix
@@ -0,0 +1,13 @@
+{ lib, ... }: let
+  sub.options.config = lib.mkOption {
+    type = lib.types.bool;
+    default = false;
+  };
+in {
+  options.submodule = lib.mkOption {
+    type = lib.types.submoduleWith {
+      modules = [ sub ];
+    };
+    default = {};
+  };
+}
diff --git a/lib/tests/modules/declare-submoduleWith-path.nix b/lib/tests/modules/declare-submoduleWith-path.nix
new file mode 100644
index 00000000000..477647f3212
--- /dev/null
+++ b/lib/tests/modules/declare-submoduleWith-path.nix
@@ -0,0 +1,12 @@
+{ lib, ... }: {
+  options.submodule = lib.mkOption {
+    type = lib.types.submoduleWith {
+      modules = [
+        ./declare-enable.nix
+      ];
+    };
+    default = {};
+  };
+
+  config.submodule = ./define-enable.nix;
+}
diff --git a/lib/tests/modules/declare-submoduleWith-shorthand.nix b/lib/tests/modules/declare-submoduleWith-shorthand.nix
new file mode 100644
index 00000000000..63ac16293e2
--- /dev/null
+++ b/lib/tests/modules/declare-submoduleWith-shorthand.nix
@@ -0,0 +1,14 @@
+{ lib, ... }: let
+  sub.options.config = lib.mkOption {
+    type = lib.types.bool;
+    default = false;
+  };
+in {
+  options.submodule = lib.mkOption {
+    type = lib.types.submoduleWith {
+      modules = [ sub ];
+      shorthandOnlyDefinesConfig = true;
+    };
+    default = {};
+  };
+}
diff --git a/lib/tests/modules/declare-submoduleWith-special.nix b/lib/tests/modules/declare-submoduleWith-special.nix
new file mode 100644
index 00000000000..6b15c5bde20
--- /dev/null
+++ b/lib/tests/modules/declare-submoduleWith-special.nix
@@ -0,0 +1,17 @@
+{ lib, ... }: {
+  options.submodule = lib.mkOption {
+    type = lib.types.submoduleWith {
+      modules = [
+        ({ lib, ... }: {
+          options.foo = lib.mkOption {
+            default = lib.foo;
+          };
+        })
+      ];
+      specialArgs.lib = lib // {
+        foo = "foo";
+      };
+    };
+    default = {};
+  };
+}
diff --git a/lib/tests/modules/declare-variants.nix b/lib/tests/modules/declare-variants.nix
new file mode 100644
index 00000000000..3ed6fa689e2
--- /dev/null
+++ b/lib/tests/modules/declare-variants.nix
@@ -0,0 +1,9 @@
+{ lib, moduleType, ... }:
+let inherit (lib) mkOption types;
+in
+{
+  options.variants = mkOption {
+    type = types.lazyAttrsOf moduleType;
+    default = {};
+  };
+}
diff --git a/lib/tests/modules/default.nix b/lib/tests/modules/default.nix
new file mode 100644
index 00000000000..5b094710419
--- /dev/null
+++ b/lib/tests/modules/default.nix
@@ -0,0 +1,8 @@
+{ lib ? import ../.., modules ? [] }:
+
+{
+  inherit (lib.evalModules {
+    inherit modules;
+    specialArgs.modulesPath = ./.;
+  }) config options;
+}
diff --git a/lib/tests/modules/define-_module-args-custom.nix b/lib/tests/modules/define-_module-args-custom.nix
new file mode 100644
index 00000000000..e565fd215a5
--- /dev/null
+++ b/lib/tests/modules/define-_module-args-custom.nix
@@ -0,0 +1,7 @@
+{ lib, ... }:
+
+{
+  config = {
+    _module.args.custom = true;
+  };
+}
diff --git a/lib/tests/modules/define-attrsOfSub-bar-enable.nix b/lib/tests/modules/define-attrsOfSub-bar-enable.nix
new file mode 100644
index 00000000000..99c55d8b360
--- /dev/null
+++ b/lib/tests/modules/define-attrsOfSub-bar-enable.nix
@@ -0,0 +1,3 @@
+{
+  attrsOfSub.bar.enable = true;
+}
diff --git a/lib/tests/modules/define-attrsOfSub-bar.nix b/lib/tests/modules/define-attrsOfSub-bar.nix
new file mode 100644
index 00000000000..2a33068a568
--- /dev/null
+++ b/lib/tests/modules/define-attrsOfSub-bar.nix
@@ -0,0 +1,3 @@
+{
+  attrsOfSub.bar = {};
+}
diff --git a/lib/tests/modules/define-attrsOfSub-foo-enable-force.nix b/lib/tests/modules/define-attrsOfSub-foo-enable-force.nix
new file mode 100644
index 00000000000..c9ee36446f1
--- /dev/null
+++ b/lib/tests/modules/define-attrsOfSub-foo-enable-force.nix
@@ -0,0 +1,5 @@
+{ lib, ... }:
+
+{
+  attrsOfSub.foo.enable = lib.mkForce false;
+}
diff --git a/lib/tests/modules/define-attrsOfSub-foo-enable-if.nix b/lib/tests/modules/define-attrsOfSub-foo-enable-if.nix
new file mode 100644
index 00000000000..0b3baddb5ec
--- /dev/null
+++ b/lib/tests/modules/define-attrsOfSub-foo-enable-if.nix
@@ -0,0 +1,5 @@
+{ config, lib, ... }:
+
+{
+  attrsOfSub.foo.enable = lib.mkIf config.enable true;
+}
diff --git a/lib/tests/modules/define-attrsOfSub-foo-enable.nix b/lib/tests/modules/define-attrsOfSub-foo-enable.nix
new file mode 100644
index 00000000000..39cd63cef72
--- /dev/null
+++ b/lib/tests/modules/define-attrsOfSub-foo-enable.nix
@@ -0,0 +1,3 @@
+{
+  attrsOfSub.foo.enable = true;
+}
diff --git a/lib/tests/modules/define-attrsOfSub-foo-force-enable.nix b/lib/tests/modules/define-attrsOfSub-foo-force-enable.nix
new file mode 100644
index 00000000000..009da7c77cd
--- /dev/null
+++ b/lib/tests/modules/define-attrsOfSub-foo-force-enable.nix
@@ -0,0 +1,7 @@
+{ lib, ... }:
+
+{
+  attrsOfSub.foo = lib.mkForce {
+    enable = false;
+  };
+}
diff --git a/lib/tests/modules/define-attrsOfSub-foo-if-enable.nix b/lib/tests/modules/define-attrsOfSub-foo-if-enable.nix
new file mode 100644
index 00000000000..93702dfa86f
--- /dev/null
+++ b/lib/tests/modules/define-attrsOfSub-foo-if-enable.nix
@@ -0,0 +1,7 @@
+{ config, lib, ... }:
+
+{
+  attrsOfSub.foo = lib.mkIf config.enable {
+    enable = true;
+  };
+}
diff --git a/lib/tests/modules/define-attrsOfSub-foo.nix b/lib/tests/modules/define-attrsOfSub-foo.nix
new file mode 100644
index 00000000000..e6bb531dedd
--- /dev/null
+++ b/lib/tests/modules/define-attrsOfSub-foo.nix
@@ -0,0 +1,3 @@
+{
+  attrsOfSub.foo = {};
+}
diff --git a/lib/tests/modules/define-attrsOfSub-force-foo-enable.nix b/lib/tests/modules/define-attrsOfSub-force-foo-enable.nix
new file mode 100644
index 00000000000..5c02dd34314
--- /dev/null
+++ b/lib/tests/modules/define-attrsOfSub-force-foo-enable.nix
@@ -0,0 +1,7 @@
+{ lib, ... }:
+
+{
+  attrsOfSub = lib.mkForce {
+    foo.enable = false;
+  };
+}
diff --git a/lib/tests/modules/define-attrsOfSub-if-foo-enable.nix b/lib/tests/modules/define-attrsOfSub-if-foo-enable.nix
new file mode 100644
index 00000000000..a3fe6051d41
--- /dev/null
+++ b/lib/tests/modules/define-attrsOfSub-if-foo-enable.nix
@@ -0,0 +1,7 @@
+{ config, lib, ... }:
+
+{
+  attrsOfSub = lib.mkIf config.enable {
+    foo.enable = true;
+  };
+}
diff --git a/lib/tests/modules/define-bare-submodule-values.nix b/lib/tests/modules/define-bare-submodule-values.nix
new file mode 100644
index 00000000000..00ede929ee6
--- /dev/null
+++ b/lib/tests/modules/define-bare-submodule-values.nix
@@ -0,0 +1,4 @@
+{
+  bare-submodule.nested = 42;
+  bare-submodule.deep = 420;
+}
diff --git a/lib/tests/modules/define-enable-force.nix b/lib/tests/modules/define-enable-force.nix
new file mode 100644
index 00000000000..f4990a32863
--- /dev/null
+++ b/lib/tests/modules/define-enable-force.nix
@@ -0,0 +1,5 @@
+{ lib, ... }:
+
+{
+  enable = lib.mkForce false;
+}
diff --git a/lib/tests/modules/define-enable-with-custom-arg.nix b/lib/tests/modules/define-enable-with-custom-arg.nix
new file mode 100644
index 00000000000..7da74671d14
--- /dev/null
+++ b/lib/tests/modules/define-enable-with-custom-arg.nix
@@ -0,0 +1,7 @@
+{ lib, custom, ... }:
+
+{
+  config = {
+    enable = custom;
+  };
+}
diff --git a/lib/tests/modules/define-enable.nix b/lib/tests/modules/define-enable.nix
new file mode 100644
index 00000000000..7dc26010ae5
--- /dev/null
+++ b/lib/tests/modules/define-enable.nix
@@ -0,0 +1,3 @@
+{
+  enable = true;
+}
diff --git a/lib/tests/modules/define-force-attrsOfSub-foo-enable.nix b/lib/tests/modules/define-force-attrsOfSub-foo-enable.nix
new file mode 100644
index 00000000000..dafb2360e1f
--- /dev/null
+++ b/lib/tests/modules/define-force-attrsOfSub-foo-enable.nix
@@ -0,0 +1,5 @@
+{ lib, ... }:
+
+lib.mkForce {
+  attrsOfSub.foo.enable = false;
+}
diff --git a/lib/tests/modules/define-force-enable.nix b/lib/tests/modules/define-force-enable.nix
new file mode 100644
index 00000000000..978caa2a8c0
--- /dev/null
+++ b/lib/tests/modules/define-force-enable.nix
@@ -0,0 +1,5 @@
+{ lib, ... }:
+
+lib.mkForce {
+  enable = false;
+}
diff --git a/lib/tests/modules/define-if-attrsOfSub-foo-enable.nix b/lib/tests/modules/define-if-attrsOfSub-foo-enable.nix
new file mode 100644
index 00000000000..6a8e32e802a
--- /dev/null
+++ b/lib/tests/modules/define-if-attrsOfSub-foo-enable.nix
@@ -0,0 +1,5 @@
+{ config, lib, ... }:
+
+lib.mkIf config.enable {
+  attrsOfSub.foo.enable = true;
+}
diff --git a/lib/tests/modules/define-module-check.nix b/lib/tests/modules/define-module-check.nix
new file mode 100644
index 00000000000..5a0707c975f
--- /dev/null
+++ b/lib/tests/modules/define-module-check.nix
@@ -0,0 +1,3 @@
+{
+  _module.check = false;
+}
diff --git a/lib/tests/modules/define-option-dependently-nested.nix b/lib/tests/modules/define-option-dependently-nested.nix
new file mode 100644
index 00000000000..69ee4255534
--- /dev/null
+++ b/lib/tests/modules/define-option-dependently-nested.nix
@@ -0,0 +1,16 @@
+{ lib, options, ... }:
+
+# Some modules may be distributed separately and need to adapt to other modules
+# that are distributed and versioned separately.
+{
+
+  # Always defined, but the value depends on the presence of an option.
+  config.set = {
+    value = if options ? set.enable then 360 else 7;
+  }
+  # Only define if possible.
+  // lib.optionalAttrs (options ? set.enable) {
+    enable = true;
+  };
+
+}
diff --git a/lib/tests/modules/define-option-dependently.nix b/lib/tests/modules/define-option-dependently.nix
new file mode 100644
index 00000000000..ad85f99a919
--- /dev/null
+++ b/lib/tests/modules/define-option-dependently.nix
@@ -0,0 +1,16 @@
+{ lib, options, ... }:
+
+# Some modules may be distributed separately and need to adapt to other modules
+# that are distributed and versioned separately.
+{
+
+  # Always defined, but the value depends on the presence of an option.
+  config = {
+    value = if options ? enable then 360 else 7;
+  }
+  # Only define if possible.
+  // lib.optionalAttrs (options ? enable) {
+    enable = true;
+  };
+
+}
diff --git a/lib/tests/modules/define-shorthandOnlyDefinesConfig-true.nix b/lib/tests/modules/define-shorthandOnlyDefinesConfig-true.nix
new file mode 100644
index 00000000000..bd3a73dce34
--- /dev/null
+++ b/lib/tests/modules/define-shorthandOnlyDefinesConfig-true.nix
@@ -0,0 +1 @@
+{ shorthandOnlyDefinesConfig = true; }
diff --git a/lib/tests/modules/define-submoduleWith-noshorthand.nix b/lib/tests/modules/define-submoduleWith-noshorthand.nix
new file mode 100644
index 00000000000..35e1607b6f1
--- /dev/null
+++ b/lib/tests/modules/define-submoduleWith-noshorthand.nix
@@ -0,0 +1,3 @@
+{
+  submodule.config.config = true;
+}
diff --git a/lib/tests/modules/define-submoduleWith-shorthand.nix b/lib/tests/modules/define-submoduleWith-shorthand.nix
new file mode 100644
index 00000000000..17df248db8e
--- /dev/null
+++ b/lib/tests/modules/define-submoduleWith-shorthand.nix
@@ -0,0 +1,3 @@
+{
+  submodule.config = true;
+}
diff --git a/lib/tests/modules/define-value-int-negative.nix b/lib/tests/modules/define-value-int-negative.nix
new file mode 100644
index 00000000000..a041222987a
--- /dev/null
+++ b/lib/tests/modules/define-value-int-negative.nix
@@ -0,0 +1,3 @@
+{
+  value = -23;
+}
diff --git a/lib/tests/modules/define-value-int-positive.nix b/lib/tests/modules/define-value-int-positive.nix
new file mode 100644
index 00000000000..5803de17263
--- /dev/null
+++ b/lib/tests/modules/define-value-int-positive.nix
@@ -0,0 +1,3 @@
+{
+  value = 42;
+}
diff --git a/lib/tests/modules/define-value-int-zero.nix b/lib/tests/modules/define-value-int-zero.nix
new file mode 100644
index 00000000000..68bb9f415c3
--- /dev/null
+++ b/lib/tests/modules/define-value-int-zero.nix
@@ -0,0 +1,3 @@
+{
+  value = 0;
+}
diff --git a/lib/tests/modules/define-value-list.nix b/lib/tests/modules/define-value-list.nix
new file mode 100644
index 00000000000..4831c1cc09b
--- /dev/null
+++ b/lib/tests/modules/define-value-list.nix
@@ -0,0 +1,3 @@
+{
+  value = [];
+}
diff --git a/lib/tests/modules/define-value-string-arbitrary.nix b/lib/tests/modules/define-value-string-arbitrary.nix
new file mode 100644
index 00000000000..8e3abaf536a
--- /dev/null
+++ b/lib/tests/modules/define-value-string-arbitrary.nix
@@ -0,0 +1,3 @@
+{
+  value = "foobar";
+}
diff --git a/lib/tests/modules/define-value-string-bigint.nix b/lib/tests/modules/define-value-string-bigint.nix
new file mode 100644
index 00000000000..f27e31985c9
--- /dev/null
+++ b/lib/tests/modules/define-value-string-bigint.nix
@@ -0,0 +1,3 @@
+{
+  value = "1000";
+}
diff --git a/lib/tests/modules/define-value-string-properties.nix b/lib/tests/modules/define-value-string-properties.nix
new file mode 100644
index 00000000000..972304c0112
--- /dev/null
+++ b/lib/tests/modules/define-value-string-properties.nix
@@ -0,0 +1,12 @@
+{ lib, ... }: {
+
+  imports = [{
+    value = lib.mkDefault "def";
+  }];
+
+  value = lib.mkMerge [
+    (lib.mkIf false "nope")
+    "yes"
+  ];
+
+}
diff --git a/lib/tests/modules/define-value-string.nix b/lib/tests/modules/define-value-string.nix
new file mode 100644
index 00000000000..e7a166965a7
--- /dev/null
+++ b/lib/tests/modules/define-value-string.nix
@@ -0,0 +1,3 @@
+{
+  value = "24";
+}
diff --git a/lib/tests/modules/define-variant.nix b/lib/tests/modules/define-variant.nix
new file mode 100644
index 00000000000..423cb0e37cb
--- /dev/null
+++ b/lib/tests/modules/define-variant.nix
@@ -0,0 +1,22 @@
+{ config, lib, ... }:
+let inherit (lib) types mkOption attrNames;
+in
+{
+  options = {
+    attrs = mkOption { type = types.attrsOf lib.types.int; };
+    result = mkOption { };
+    resultFoo = mkOption { };
+    resultFooBar = mkOption { };
+    resultFooFoo = mkOption { };
+  };
+  config = {
+    attrs.a = 1;
+    variants.foo.attrs.b = 1;
+    variants.bar.attrs.y = 1;
+    variants.foo.variants.bar.attrs.z = 1;
+    variants.foo.variants.foo.attrs.c = 3;
+    resultFoo = lib.concatMapStringsSep " " toString (attrNames config.variants.foo.attrs);
+    resultFooBar = lib.concatMapStringsSep " " toString (attrNames config.variants.foo.variants.bar.attrs);
+    resultFooFoo = lib.concatMapStringsSep " " toString (attrNames config.variants.foo.variants.foo.attrs);
+  };
+}
diff --git a/lib/tests/modules/disable-declare-enable.nix b/lib/tests/modules/disable-declare-enable.nix
new file mode 100644
index 00000000000..a373ee7e550
--- /dev/null
+++ b/lib/tests/modules/disable-declare-enable.nix
@@ -0,0 +1,5 @@
+{ lib, ... }:
+
+{
+  disabledModules = [ ./declare-enable.nix ];
+}
diff --git a/lib/tests/modules/disable-define-enable.nix b/lib/tests/modules/disable-define-enable.nix
new file mode 100644
index 00000000000..0d84a7c3cb6
--- /dev/null
+++ b/lib/tests/modules/disable-define-enable.nix
@@ -0,0 +1,5 @@
+{ lib, ... }:
+
+{
+  disabledModules = [ ./define-enable.nix ];
+}
diff --git a/lib/tests/modules/disable-enable-modules.nix b/lib/tests/modules/disable-enable-modules.nix
new file mode 100644
index 00000000000..c325f4e0743
--- /dev/null
+++ b/lib/tests/modules/disable-enable-modules.nix
@@ -0,0 +1,5 @@
+{ lib, ... }:
+
+{
+  disabledModules = [ "define-enable.nix" "declare-enable.nix" ];
+}
diff --git a/lib/tests/modules/disable-recursive/bar.nix b/lib/tests/modules/disable-recursive/bar.nix
new file mode 100644
index 00000000000..4d9240a432d
--- /dev/null
+++ b/lib/tests/modules/disable-recursive/bar.nix
@@ -0,0 +1,5 @@
+{
+  imports = [
+    ../declare-enable.nix
+  ];
+}
diff --git a/lib/tests/modules/disable-recursive/disable-bar.nix b/lib/tests/modules/disable-recursive/disable-bar.nix
new file mode 100644
index 00000000000..987b2802ae8
--- /dev/null
+++ b/lib/tests/modules/disable-recursive/disable-bar.nix
@@ -0,0 +1,7 @@
+{
+
+  disabledModules = [
+    ./bar.nix
+  ];
+
+}
diff --git a/lib/tests/modules/disable-recursive/disable-foo.nix b/lib/tests/modules/disable-recursive/disable-foo.nix
new file mode 100644
index 00000000000..5b68a3c4610
--- /dev/null
+++ b/lib/tests/modules/disable-recursive/disable-foo.nix
@@ -0,0 +1,7 @@
+{
+
+  disabledModules = [
+    ./foo.nix
+  ];
+
+}
diff --git a/lib/tests/modules/disable-recursive/foo.nix b/lib/tests/modules/disable-recursive/foo.nix
new file mode 100644
index 00000000000..4d9240a432d
--- /dev/null
+++ b/lib/tests/modules/disable-recursive/foo.nix
@@ -0,0 +1,5 @@
+{
+  imports = [
+    ../declare-enable.nix
+  ];
+}
diff --git a/lib/tests/modules/disable-recursive/main.nix b/lib/tests/modules/disable-recursive/main.nix
new file mode 100644
index 00000000000..48a3c6218cf
--- /dev/null
+++ b/lib/tests/modules/disable-recursive/main.nix
@@ -0,0 +1,8 @@
+{
+  imports = [
+    ./foo.nix
+    ./bar.nix
+  ];
+
+  enable = true;
+}
diff --git a/lib/tests/modules/emptyValues.nix b/lib/tests/modules/emptyValues.nix
new file mode 100644
index 00000000000..77825de3281
--- /dev/null
+++ b/lib/tests/modules/emptyValues.nix
@@ -0,0 +1,36 @@
+{ lib, ... }:
+let
+  inherit (lib) types;
+in {
+
+  options = {
+    int = lib.mkOption {
+      type = types.lazyAttrsOf types.int;
+    };
+    list = lib.mkOption {
+      type = types.lazyAttrsOf (types.listOf types.int);
+    };
+    nonEmptyList = lib.mkOption {
+      type = types.lazyAttrsOf (types.nonEmptyListOf types.int);
+    };
+    attrs = lib.mkOption {
+      type = types.lazyAttrsOf (types.attrsOf types.int);
+    };
+    null = lib.mkOption {
+      type = types.lazyAttrsOf (types.nullOr types.int);
+    };
+    submodule = lib.mkOption {
+      type = types.lazyAttrsOf (types.submodule {});
+    };
+  };
+
+  config = {
+    int.a = lib.mkIf false null;
+    list.a = lib.mkIf false null;
+    nonEmptyList.a = lib.mkIf false null;
+    attrs.a = lib.mkIf false null;
+    null.a = lib.mkIf false null;
+    submodule.a = lib.mkIf false null;
+  };
+
+}
diff --git a/lib/tests/modules/freeform-attrsOf.nix b/lib/tests/modules/freeform-attrsOf.nix
new file mode 100644
index 00000000000..8cc577f38a6
--- /dev/null
+++ b/lib/tests/modules/freeform-attrsOf.nix
@@ -0,0 +1,3 @@
+{ lib, ... }: {
+  freeformType = with lib.types; attrsOf (either str (attrsOf str));
+}
diff --git a/lib/tests/modules/freeform-lazyAttrsOf.nix b/lib/tests/modules/freeform-lazyAttrsOf.nix
new file mode 100644
index 00000000000..36d6c0b13fc
--- /dev/null
+++ b/lib/tests/modules/freeform-lazyAttrsOf.nix
@@ -0,0 +1,3 @@
+{ lib, ... }: {
+  freeformType = with lib.types; lazyAttrsOf (either str (lazyAttrsOf str));
+}
diff --git a/lib/tests/modules/freeform-nested.nix b/lib/tests/modules/freeform-nested.nix
new file mode 100644
index 00000000000..b81fa7f0d22
--- /dev/null
+++ b/lib/tests/modules/freeform-nested.nix
@@ -0,0 +1,14 @@
+{ lib, ... }:
+let
+  deathtrapArgs = lib.mapAttrs
+    (k: _: throw "The module system is too strict, accessing an unused option's ${k} mkOption-attribute.")
+    (lib.functionArgs lib.mkOption);
+in
+{
+  options.nest.foo = lib.mkOption {
+    type = lib.types.bool;
+    default = false;
+  };
+  options.nest.unused = lib.mkOption deathtrapArgs;
+  config.nest.bar = "bar";
+}
diff --git a/lib/tests/modules/freeform-str-dep-unstr.nix b/lib/tests/modules/freeform-str-dep-unstr.nix
new file mode 100644
index 00000000000..a2dfbc80cfa
--- /dev/null
+++ b/lib/tests/modules/freeform-str-dep-unstr.nix
@@ -0,0 +1,8 @@
+{ lib, config, ... }: {
+  options.foo = lib.mkOption {
+    type = lib.types.nullOr lib.types.str;
+    default = null;
+  };
+
+  config.foo = lib.mkIf (config ? value) config.value;
+}
diff --git a/lib/tests/modules/freeform-submodules.nix b/lib/tests/modules/freeform-submodules.nix
new file mode 100644
index 00000000000..3910435a7b5
--- /dev/null
+++ b/lib/tests/modules/freeform-submodules.nix
@@ -0,0 +1,22 @@
+{ lib, options, ... }: with lib.types; {
+
+  options.fooDeclarations = lib.mkOption {
+    default = (options.free.type.getSubOptions [])._freeformOptions.foo.declarations;
+  };
+
+  options.free = lib.mkOption {
+    type = submodule {
+      config._module.freeformType = lib.mkMerge [
+        (attrsOf (submodule {
+          options.foo = lib.mkOption {};
+        }))
+        (attrsOf (submodule {
+          options.bar = lib.mkOption {};
+        }))
+      ];
+    };
+  };
+
+  config.free.xxx.foo = 10;
+  config.free.yyy.bar = 10;
+}
diff --git a/lib/tests/modules/freeform-unstr-dep-str.nix b/lib/tests/modules/freeform-unstr-dep-str.nix
new file mode 100644
index 00000000000..549d89afeca
--- /dev/null
+++ b/lib/tests/modules/freeform-unstr-dep-str.nix
@@ -0,0 +1,8 @@
+{ lib, config, ... }: {
+  options.value = lib.mkOption {
+    type = lib.types.nullOr lib.types.str;
+    default = null;
+  };
+
+  config.foo = lib.mkIf (config.value != null) config.value;
+}
diff --git a/lib/tests/modules/functionTo/list-order.nix b/lib/tests/modules/functionTo/list-order.nix
new file mode 100644
index 00000000000..77a1a43a84f
--- /dev/null
+++ b/lib/tests/modules/functionTo/list-order.nix
@@ -0,0 +1,25 @@
+
+{ lib, config, ... }:
+let
+  inherit (lib) types;
+in {
+  options = {
+    fun = lib.mkOption {
+      type = types.functionTo (types.listOf types.str);
+    };
+
+    result = lib.mkOption {
+      type = types.str;
+      default = toString (config.fun {
+        a = "a";
+        b = "b";
+        c = "c";
+      });
+    };
+  };
+
+  config.fun = lib.mkMerge [
+    (input: lib.mkAfter [ input.a ])
+    (input: [ input.b ])
+  ];
+}
diff --git a/lib/tests/modules/functionTo/merging-attrs.nix b/lib/tests/modules/functionTo/merging-attrs.nix
new file mode 100644
index 00000000000..97c015f928a
--- /dev/null
+++ b/lib/tests/modules/functionTo/merging-attrs.nix
@@ -0,0 +1,27 @@
+{ lib, config, ... }:
+let
+  inherit (lib) types;
+in {
+  options = {
+    fun = lib.mkOption {
+      type = types.functionTo (types.attrsOf types.str);
+    };
+
+    result = lib.mkOption {
+      type = types.str;
+      default = toString (lib.attrValues (config.fun {
+        a = "a";
+        b = "b";
+        c = "c";
+      }));
+    };
+  };
+
+  config.fun = lib.mkMerge [
+    (input: { inherit (input) a; })
+    (input: { inherit (input) b; })
+    (input: {
+      b = lib.mkForce input.c;
+    })
+  ];
+}
diff --git a/lib/tests/modules/functionTo/merging-list.nix b/lib/tests/modules/functionTo/merging-list.nix
new file mode 100644
index 00000000000..15fcd2bdcc4
--- /dev/null
+++ b/lib/tests/modules/functionTo/merging-list.nix
@@ -0,0 +1,24 @@
+{ lib, config, ... }:
+let
+  inherit (lib) types;
+in {
+  options = {
+    fun = lib.mkOption {
+      type = types.functionTo (types.listOf types.str);
+    };
+
+    result = lib.mkOption {
+      type = types.str;
+      default = toString (config.fun {
+        a = "a";
+        b = "b";
+        c = "c";
+      });
+    };
+  };
+
+  config.fun = lib.mkMerge [
+    (input: [ input.a ])
+    (input: [ input.b ])
+  ];
+}
diff --git a/lib/tests/modules/functionTo/trivial.nix b/lib/tests/modules/functionTo/trivial.nix
new file mode 100644
index 00000000000..0962a0cf893
--- /dev/null
+++ b/lib/tests/modules/functionTo/trivial.nix
@@ -0,0 +1,17 @@
+{ lib, config, ... }:
+let
+  inherit (lib) types;
+in {
+  options = {
+    fun = lib.mkOption {
+      type = types.functionTo types.str;
+    };
+
+    result = lib.mkOption {
+      type = types.str;
+      default = config.fun "input";
+    };
+  };
+
+  config.fun = input: "input is ${input}";
+}
diff --git a/lib/tests/modules/functionTo/wrong-type.nix b/lib/tests/modules/functionTo/wrong-type.nix
new file mode 100644
index 00000000000..fd65b75088d
--- /dev/null
+++ b/lib/tests/modules/functionTo/wrong-type.nix
@@ -0,0 +1,18 @@
+
+{ lib, config, ... }:
+let
+  inherit (lib) types;
+in {
+  options = {
+    fun = lib.mkOption {
+      type = types.functionTo types.str;
+    };
+
+    result = lib.mkOption {
+      type = types.str;
+      default = config.fun 0;
+    };
+  };
+
+  config.fun = input: input + 1;
+}
diff --git a/lib/tests/modules/import-custom-arg.nix b/lib/tests/modules/import-custom-arg.nix
new file mode 100644
index 00000000000..3e687b661c1
--- /dev/null
+++ b/lib/tests/modules/import-custom-arg.nix
@@ -0,0 +1,6 @@
+{ lib, custom, ... }:
+
+{
+  imports = []
+  ++ lib.optional custom ./define-enable-force.nix;
+}
diff --git a/lib/tests/modules/import-from-store.nix b/lib/tests/modules/import-from-store.nix
new file mode 100644
index 00000000000..f5af22432ce
--- /dev/null
+++ b/lib/tests/modules/import-from-store.nix
@@ -0,0 +1,11 @@
+{ lib, ... }:
+{
+
+  imports = [
+    "${builtins.toFile "drv" "{}"}"
+    ./declare-enable.nix
+    ./define-enable.nix
+  ];
+
+}
+
diff --git a/lib/tests/modules/optionTypeFile.nix b/lib/tests/modules/optionTypeFile.nix
new file mode 100644
index 00000000000..6015d59a72c
--- /dev/null
+++ b/lib/tests/modules/optionTypeFile.nix
@@ -0,0 +1,28 @@
+{ config, lib, ... }: {
+
+  _file = "optionTypeFile.nix";
+
+  options.theType = lib.mkOption {
+    type = lib.types.optionType;
+  };
+
+  options.theOption = lib.mkOption {
+    type = config.theType;
+    default = {};
+  };
+
+  config.theType = lib.mkMerge [
+    (lib.types.submodule {
+      options.nested = lib.mkOption {
+        type = lib.types.int;
+      };
+    })
+    (lib.types.submodule {
+      _file = "other.nix";
+      options.nested = lib.mkOption {
+        type = lib.types.str;
+      };
+    })
+  ];
+
+}
diff --git a/lib/tests/modules/optionTypeMerging.nix b/lib/tests/modules/optionTypeMerging.nix
new file mode 100644
index 00000000000..74a620c4620
--- /dev/null
+++ b/lib/tests/modules/optionTypeMerging.nix
@@ -0,0 +1,27 @@
+{ config, lib, ... }: {
+
+  options.theType = lib.mkOption {
+    type = lib.types.optionType;
+  };
+
+  options.theOption = lib.mkOption {
+    type = config.theType;
+  };
+
+  config.theType = lib.mkMerge [
+    (lib.types.submodule {
+      options.int = lib.mkOption {
+        type = lib.types.int;
+        default = 10;
+      };
+    })
+    (lib.types.submodule {
+      options.str = lib.mkOption {
+        type = lib.types.str;
+      };
+    })
+  ];
+
+  config.theOption.str = "hello";
+
+}
diff --git a/lib/tests/modules/raw.nix b/lib/tests/modules/raw.nix
new file mode 100644
index 00000000000..418e671ed07
--- /dev/null
+++ b/lib/tests/modules/raw.nix
@@ -0,0 +1,30 @@
+{ lib, ... }: {
+
+  options = {
+    processedToplevel = lib.mkOption {
+      type = lib.types.raw;
+    };
+    unprocessedNesting = lib.mkOption {
+      type = lib.types.raw;
+    };
+    multiple = lib.mkOption {
+      type = lib.types.raw;
+    };
+    priorities = lib.mkOption {
+      type = lib.types.raw;
+    };
+  };
+
+  config = {
+    processedToplevel = lib.mkIf true 10;
+    unprocessedNesting.foo = throw "foo";
+    multiple = lib.mkMerge [
+      "foo"
+      "foo"
+    ];
+    priorities = lib.mkMerge [
+      "foo"
+      (lib.mkForce "bar")
+    ];
+  };
+}
diff --git a/lib/tests/modules/types-anything/attrs-coercible.nix b/lib/tests/modules/types-anything/attrs-coercible.nix
new file mode 100644
index 00000000000..085cbd638f1
--- /dev/null
+++ b/lib/tests/modules/types-anything/attrs-coercible.nix
@@ -0,0 +1,12 @@
+{ lib, ... }: {
+
+  options.value = lib.mkOption {
+    type = lib.types.anything;
+  };
+
+  config.value = {
+    outPath = "foo";
+    err = throw "err";
+  };
+
+}
diff --git a/lib/tests/modules/types-anything/equal-atoms.nix b/lib/tests/modules/types-anything/equal-atoms.nix
new file mode 100644
index 00000000000..972711201a0
--- /dev/null
+++ b/lib/tests/modules/types-anything/equal-atoms.nix
@@ -0,0 +1,26 @@
+{ lib, ... }: {
+
+  options.value = lib.mkOption {
+    type = lib.types.anything;
+  };
+
+  config = lib.mkMerge [
+    {
+      value.int = 0;
+      value.bool = false;
+      value.string = "";
+      value.path = /.;
+      value.null = null;
+      value.float = 0.1;
+    }
+    {
+      value.int = 0;
+      value.bool = false;
+      value.string = "";
+      value.path = /.;
+      value.null = null;
+      value.float = 0.1;
+    }
+  ];
+
+}
diff --git a/lib/tests/modules/types-anything/functions.nix b/lib/tests/modules/types-anything/functions.nix
new file mode 100644
index 00000000000..21edd4aff9c
--- /dev/null
+++ b/lib/tests/modules/types-anything/functions.nix
@@ -0,0 +1,23 @@
+{ lib, config, ... }: {
+
+  options.value = lib.mkOption {
+    type = lib.types.anything;
+  };
+
+  options.applied = lib.mkOption {
+    default = lib.mapAttrs (name: fun: fun null) config.value;
+  };
+
+  config = lib.mkMerge [
+    {
+      value.single-lambda = x: x;
+      value.multiple-lambdas = x: { inherit x; };
+      value.merging-lambdas = x: { inherit x; };
+    }
+    {
+      value.multiple-lambdas = x: [ x ];
+      value.merging-lambdas = y: { inherit y; };
+    }
+  ];
+
+}
diff --git a/lib/tests/modules/types-anything/lists.nix b/lib/tests/modules/types-anything/lists.nix
new file mode 100644
index 00000000000..bd846afd3d1
--- /dev/null
+++ b/lib/tests/modules/types-anything/lists.nix
@@ -0,0 +1,16 @@
+{ lib, ... }: {
+
+  options.value = lib.mkOption {
+    type = lib.types.anything;
+  };
+
+  config = lib.mkMerge [
+    {
+      value = [ null ];
+    }
+    {
+      value = [ null ];
+    }
+  ];
+
+}
diff --git a/lib/tests/modules/types-anything/mk-mods.nix b/lib/tests/modules/types-anything/mk-mods.nix
new file mode 100644
index 00000000000..f84ad01df01
--- /dev/null
+++ b/lib/tests/modules/types-anything/mk-mods.nix
@@ -0,0 +1,44 @@
+{ lib, ... }: {
+
+  options.value = lib.mkOption {
+    type = lib.types.anything;
+  };
+
+  config = lib.mkMerge [
+    {
+      value.mkiffalse = lib.mkIf false {};
+    }
+    {
+      value.mkiftrue = lib.mkIf true {};
+    }
+    {
+      value.mkdefault = lib.mkDefault 0;
+    }
+    {
+      value.mkdefault = 1;
+    }
+    {
+      value.mkmerge = lib.mkMerge [
+        {}
+      ];
+    }
+    {
+      value.mkbefore = lib.mkBefore true;
+    }
+    {
+      value.nested = lib.mkMerge [
+        {
+          foo = lib.mkDefault 0;
+          bar = lib.mkIf false 0;
+        }
+        (lib.mkIf true {
+          foo = lib.mkIf true (lib.mkForce 1);
+          bar = {
+            baz = lib.mkDefault "baz";
+          };
+        })
+      ];
+    }
+  ];
+
+}
diff --git a/lib/tests/modules/types-anything/nested-attrs.nix b/lib/tests/modules/types-anything/nested-attrs.nix
new file mode 100644
index 00000000000..e57d33ef871
--- /dev/null
+++ b/lib/tests/modules/types-anything/nested-attrs.nix
@@ -0,0 +1,22 @@
+{ lib, ... }: {
+
+  options.value = lib.mkOption {
+    type = lib.types.anything;
+  };
+
+  config = lib.mkMerge [
+    {
+      value.foo = null;
+    }
+    {
+      value.l1.foo = null;
+    }
+    {
+      value.l1.l2.foo = null;
+    }
+    {
+      value.l1.l2.l3.foo = null;
+    }
+  ];
+
+}