aboutsummaryrefslogtreecommitdiff
path: root/home-manager/tests
diff options
context:
space:
mode:
Diffstat (limited to 'home-manager/tests')
-rw-r--r--home-manager/tests/default.nix102
-rw-r--r--home-manager/tests/lib/types/dag-merge-result.txt3
-rw-r--r--home-manager/tests/lib/types/dag-merge.nix32
-rw-r--r--home-manager/tests/lib/types/dag-submodule.nix43
-rw-r--r--home-manager/tests/lib/types/default.nix7
-rw-r--r--home-manager/tests/lib/types/gvariant-merge.nix62
-rw-r--r--home-manager/tests/lib/types/list-or-dag-merge-result.txt15
-rw-r--r--home-manager/tests/lib/types/list-or-dag-merge.nix34
-rw-r--r--home-manager/tests/meta/default.nix1
-rw-r--r--home-manager/tests/meta/formatting.nix27
-rw-r--r--home-manager/tests/modules/accounts/email-test-accounts.nix28
-rw-r--r--home-manager/tests/modules/files/.hidden1
-rw-r--r--home-manager/tests/modules/files/default.nix8
-rw-r--r--home-manager/tests/modules/files/executable.nix17
-rw-r--r--home-manager/tests/modules/files/hidden-source.nix19
-rw-r--r--home-manager/tests/modules/files/out-of-store-symlink.nix29
-rw-r--r--home-manager/tests/modules/files/source with spaces!1
-rw-r--r--home-manager/tests/modules/files/source-with-spaces.nix20
-rw-r--r--home-manager/tests/modules/files/target-with-shellvar.nix15
-rw-r--r--home-manager/tests/modules/files/text-expected.txt2
-rw-r--r--home-manager/tests/modules/files/text.nix18
-rw-r--r--home-manager/tests/modules/home-environment/default.nix3
-rw-r--r--home-manager/tests/modules/home-environment/session-variables-expected.txt9
-rw-r--r--home-manager/tests/modules/home-environment/session-variables.nix19
-rw-r--r--home-manager/tests/modules/misc/debug/default.nix25
-rw-r--r--home-manager/tests/modules/misc/fontconfig/default.nix22
-rw-r--r--home-manager/tests/modules/misc/fontconfig/multiple-font-packages.nix15
-rw-r--r--home-manager/tests/modules/misc/fontconfig/no-font-package.nix17
-rw-r--r--home-manager/tests/modules/misc/fontconfig/single-font-package.nix15
-rw-r--r--home-manager/tests/modules/misc/numlock/default.nix1
-rw-r--r--home-manager/tests/modules/misc/numlock/numlock.nix18
-rw-r--r--home-manager/tests/modules/misc/pam/default.nix1
-rw-r--r--home-manager/tests/modules/misc/pam/session-variables-expected.txt2
-rw-r--r--home-manager/tests/modules/misc/pam/session-variables.nix19
-rw-r--r--home-manager/tests/modules/misc/xdg/default.nix1
-rw-r--r--home-manager/tests/modules/misc/xdg/mime-apps-basics-expected.ini9
-rw-r--r--home-manager/tests/modules/misc/xdg/mime-apps-basics.nix28
-rw-r--r--home-manager/tests/modules/misc/xsession/basic-setxkbmap-expected.service12
-rw-r--r--home-manager/tests/modules/misc/xsession/basic-xprofile-expected.txt16
-rw-r--r--home-manager/tests/modules/misc/xsession/basic-xsession-expected.txt18
-rw-r--r--home-manager/tests/modules/misc/xsession/basic.nix40
-rw-r--r--home-manager/tests/modules/misc/xsession/default.nix4
-rw-r--r--home-manager/tests/modules/misc/xsession/keyboard-without-layout-expected.service12
-rw-r--r--home-manager/tests/modules/misc/xsession/keyboard-without-layout.nix34
-rw-r--r--home-manager/tests/modules/programs/abook/default.nix4
-rw-r--r--home-manager/tests/modules/programs/abook/no-settings.nix16
-rw-r--r--home-manager/tests/modules/programs/abook/with-settings.cfg21
-rw-r--r--home-manager/tests/modules/programs/abook/with-settings.nix39
-rw-r--r--home-manager/tests/modules/programs/alacritty/default.nix4
-rw-r--r--home-manager/tests/modules/programs/alacritty/empty-settings.nix17
-rw-r--r--home-manager/tests/modules/programs/alacritty/example-settings-expected.yml1
-rw-r--r--home-manager/tests/modules/programs/alacritty/example-settings.nix31
-rw-r--r--home-manager/tests/modules/programs/alot/alot-expected.conf37
-rw-r--r--home-manager/tests/modules/programs/alot/alot.nix36
-rw-r--r--home-manager/tests/modules/programs/alot/default.nix1
-rw-r--r--home-manager/tests/modules/programs/aria2/default.nix1
-rw-r--r--home-manager/tests/modules/programs/aria2/settings.nix41
-rw-r--r--home-manager/tests/modules/programs/autorandr/basic-configuration.conf10
-rw-r--r--home-manager/tests/modules/programs/autorandr/basic-configuration.nix48
-rw-r--r--home-manager/tests/modules/programs/autorandr/default.nix1
-rw-r--r--home-manager/tests/modules/programs/bash/default.nix4
-rw-r--r--home-manager/tests/modules/programs/bash/logout-expected.txt4
-rw-r--r--home-manager/tests/modules/programs/bash/logout.nix22
-rw-r--r--home-manager/tests/modules/programs/bash/session-variables-expected.txt8
-rw-r--r--home-manager/tests/modules/programs/bash/session-variables.nix23
-rw-r--r--home-manager/tests/modules/programs/browserpass/browserpass.nix29
-rw-r--r--home-manager/tests/modules/programs/browserpass/default.nix1
-rw-r--r--home-manager/tests/modules/programs/dircolors/default.nix1
-rw-r--r--home-manager/tests/modules/programs/dircolors/settings-expected.conf133
-rw-r--r--home-manager/tests/modules/programs/dircolors/settings.nix27
-rw-r--r--home-manager/tests/modules/programs/direnv/bash.nix17
-rw-r--r--home-manager/tests/modules/programs/direnv/default.nix6
-rw-r--r--home-manager/tests/modules/programs/direnv/nix-direnv.nix18
-rw-r--r--home-manager/tests/modules/programs/direnv/stdlib-and-nix-direnv.nix23
-rw-r--r--home-manager/tests/modules/programs/direnv/stdlib.nix19
-rw-r--r--home-manager/tests/modules/programs/firefox/default.nix4
-rw-r--r--home-manager/tests/modules/programs/firefox/profile-settings-expected-user.js6
-rw-r--r--home-manager/tests/modules/programs/firefox/profile-settings.nix36
-rw-r--r--home-manager/tests/modules/programs/firefox/state-version-19_09.nix31
-rw-r--r--home-manager/tests/modules/programs/fish/default.nix5
-rw-r--r--home-manager/tests/modules/programs/fish/functions.nix48
-rw-r--r--home-manager/tests/modules/programs/fish/no-functions.nix22
-rw-r--r--home-manager/tests/modules/programs/fish/plugins.nix60
-rw-r--r--home-manager/tests/modules/programs/getmail/default.nix1
-rw-r--r--home-manager/tests/modules/programs/getmail/getmail-expected.conf16
-rw-r--r--home-manager/tests/modules/programs/getmail/getmail.nix28
-rw-r--r--home-manager/tests/modules/programs/git/default.nix5
-rw-r--r--home-manager/tests/modules/programs/git/git-expected-include.conf3
-rw-r--r--home-manager/tests/modules/programs/git/git-expected.conf58
-rw-r--r--home-manager/tests/modules/programs/git/git-with-email-expected.conf15
-rw-r--r--home-manager/tests/modules/programs/git/git-with-email.nix38
-rw-r--r--home-manager/tests/modules/programs/git/git-with-str-extra-config-expected.conf5
-rw-r--r--home-manager/tests/modules/programs/git/git-with-str-extra-config.nix23
-rw-r--r--home-manager/tests/modules/programs/git/git.nix92
-rw-r--r--home-manager/tests/modules/programs/gpg/default.nix1
-rw-r--r--home-manager/tests/modules/programs/gpg/override-defaults-expected.conf19
-rw-r--r--home-manager/tests/modules/programs/gpg/override-defaults.nix22
-rw-r--r--home-manager/tests/modules/programs/i3status/default.nix4
-rw-r--r--home-manager/tests/modules/programs/i3status/with-custom.nix67
-rw-r--r--home-manager/tests/modules/programs/i3status/with-default.nix73
-rw-r--r--home-manager/tests/modules/programs/kakoune/default.nix7
-rw-r--r--home-manager/tests/modules/programs/kakoune/no-plugins.nix13
-rw-r--r--home-manager/tests/modules/programs/kakoune/use-plugins.nix18
-rw-r--r--home-manager/tests/modules/programs/kakoune/whitespace-highlighter-corner-cases.nix25
-rw-r--r--home-manager/tests/modules/programs/kakoune/whitespace-highlighter.nix25
-rw-r--r--home-manager/tests/modules/programs/lf/all-options.nix86
-rw-r--r--home-manager/tests/modules/programs/lf/default.nix5
-rw-r--r--home-manager/tests/modules/programs/lf/minimal-options.nix18
-rw-r--r--home-manager/tests/modules/programs/lf/no-pv-keybind.nix43
-rw-r--r--home-manager/tests/modules/programs/lieer/default.nix1
-rw-r--r--home-manager/tests/modules/programs/lieer/lieer-expected.json1
-rw-r--r--home-manager/tests/modules/programs/lieer/lieer.nix23
-rw-r--r--home-manager/tests/modules/programs/man/apropos.nix22
-rw-r--r--home-manager/tests/modules/programs/man/default.nix4
-rw-r--r--home-manager/tests/modules/programs/man/no-manpath.nix13
-rw-r--r--home-manager/tests/modules/programs/mbsync/default.nix1
-rw-r--r--home-manager/tests/modules/programs/mbsync/mbsync-expected.conf55
-rw-r--r--home-manager/tests/modules/programs/mbsync/mbsync.nix28
-rw-r--r--home-manager/tests/modules/programs/ncmpcpp-linux/default.nix1
-rw-r--r--home-manager/tests/modules/programs/ncmpcpp-linux/ncmpcpp-use-mpd-config-expected-config1
-rw-r--r--home-manager/tests/modules/programs/ncmpcpp-linux/ncmpcpp-use-mpd-config.nix25
-rw-r--r--home-manager/tests/modules/programs/ncmpcpp/default.nix4
-rw-r--r--home-manager/tests/modules/programs/ncmpcpp/ncmpcpp-empty-settings.nix16
-rw-r--r--home-manager/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings-expected-bindings16
-rw-r--r--home-manager/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings-expected-config4
-rw-r--r--home-manager/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings.nix60
-rw-r--r--home-manager/tests/modules/programs/ne/default.nix4
-rw-r--r--home-manager/tests/modules/programs/ne/defprefs.nix36
-rw-r--r--home-manager/tests/modules/programs/ne/passthroughs.nix73
-rw-r--r--home-manager/tests/modules/programs/neomutt/default.nix4
-rw-r--r--home-manager/tests/modules/programs/neomutt/hm-example.com-expected37
-rw-r--r--home-manager/tests/modules/programs/neomutt/hm-example.com-msmtp-expected.conf33
-rw-r--r--home-manager/tests/modules/programs/neomutt/neomutt-expected.conf27
-rw-r--r--home-manager/tests/modules/programs/neomutt/neomutt-with-msmtp.nix39
-rw-r--r--home-manager/tests/modules/programs/neomutt/neomutt.nix42
-rw-r--r--home-manager/tests/modules/programs/newsboat/default.nix4
-rw-r--r--home-manager/tests/modules/programs/newsboat/newsboat-basics-2003.nix35
-rw-r--r--home-manager/tests/modules/programs/newsboat/newsboat-basics-urls-2003.txt3
-rw-r--r--home-manager/tests/modules/programs/newsboat/newsboat-basics-urls.txt3
-rw-r--r--home-manager/tests/modules/programs/newsboat/newsboat-basics.nix33
-rw-r--r--home-manager/tests/modules/programs/nushell/default.nix1
-rw-r--r--home-manager/tests/modules/programs/nushell/settings-expected.toml5
-rw-r--r--home-manager/tests/modules/programs/nushell/settings.nix34
-rw-r--r--home-manager/tests/modules/programs/powerline-go/default.nix1
-rw-r--r--home-manager/tests/modules/programs/powerline-go/standard.nix28
-rw-r--r--home-manager/tests/modules/programs/qutebrowser/default.nix4
-rw-r--r--home-manager/tests/modules/programs/qutebrowser/keybindings.nix39
-rw-r--r--home-manager/tests/modules/programs/qutebrowser/settings.nix48
-rw-r--r--home-manager/tests/modules/programs/readline/default.nix1
-rw-r--r--home-manager/tests/modules/programs/readline/using-all-options.nix31
-rw-r--r--home-manager/tests/modules/programs/readline/using-all-options.txt11
-rw-r--r--home-manager/tests/modules/programs/rofi/assert-on-both-theme-and-colors-expected.json1
-rw-r--r--home-manager/tests/modules/programs/rofi/assert-on-both-theme-and-colors.nix32
-rw-r--r--home-manager/tests/modules/programs/rofi/default.nix3
-rw-r--r--home-manager/tests/modules/programs/ssh/default-config-expected.conf16
-rw-r--r--home-manager/tests/modules/programs/ssh/default-config.nix18
-rw-r--r--home-manager/tests/modules/programs/ssh/default.nix17
-rw-r--r--home-manager/tests/modules/programs/ssh/forwards-dynamic-bind-path-with-port-asserts.nix29
-rw-r--r--home-manager/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts-expected.conf20
-rw-r--r--home-manager/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts.nix38
-rw-r--r--home-manager/tests/modules/programs/ssh/forwards-local-bind-path-with-port-asserts.nix33
-rw-r--r--home-manager/tests/modules/programs/ssh/forwards-local-host-path-with-port-asserts.nix33
-rw-r--r--home-manager/tests/modules/programs/ssh/forwards-paths-with-ports-error.json1
-rw-r--r--home-manager/tests/modules/programs/ssh/forwards-remote-bind-path-with-port-asserts.nix33
-rw-r--r--home-manager/tests/modules/programs/ssh/forwards-remote-host-path-with-port-asserts.nix33
-rw-r--r--home-manager/tests/modules/programs/ssh/match-blocks-attrs-expected.conf34
-rw-r--r--home-manager/tests/modules/programs/ssh/match-blocks-attrs.nix58
-rw-r--r--home-manager/tests/modules/programs/ssh/no-assertions.json1
-rw-r--r--home-manager/tests/modules/programs/starship/default.nix1
-rw-r--r--home-manager/tests/modules/programs/starship/settings-expected.toml27
-rw-r--r--home-manager/tests/modules/programs/starship/settings.nix49
-rw-r--r--home-manager/tests/modules/programs/texlive/default.nix1
-rw-r--r--home-manager/tests/modules/programs/texlive/texlive-minimal.nix27
-rw-r--r--home-manager/tests/modules/programs/tmux/default.nix7
-rw-r--r--home-manager/tests/modules/programs/tmux/disable-confirmation-prompt.conf30
-rw-r--r--home-manager/tests/modules/programs/tmux/disable-confirmation-prompt.nix26
-rw-r--r--home-manager/tests/modules/programs/tmux/emacs-with-plugins.conf53
-rw-r--r--home-manager/tests/modules/programs/tmux/emacs-with-plugins.nix49
-rw-r--r--home-manager/tests/modules/programs/tmux/not-enabled.nix13
-rw-r--r--home-manager/tests/modules/programs/tmux/secure-socket-enabled.nix18
-rw-r--r--home-manager/tests/modules/programs/tmux/vi-all-true.conf30
-rw-r--r--home-manager/tests/modules/programs/tmux/vi-all-true.nix29
-rw-r--r--home-manager/tests/modules/programs/vscode/default.nix1
-rw-r--r--home-manager/tests/modules/programs/vscode/keybindings.nix53
-rw-r--r--home-manager/tests/modules/programs/waybar/broken-settings.nix80
-rw-r--r--home-manager/tests/modules/programs/waybar/default.nix8
-rw-r--r--home-manager/tests/modules/programs/waybar/settings-complex-expected.json46
-rw-r--r--home-manager/tests/modules/programs/waybar/settings-complex.nix59
-rw-r--r--home-manager/tests/modules/programs/waybar/styling-expected.css23
-rw-r--r--home-manager/tests/modules/programs/waybar/styling.nix46
-rw-r--r--home-manager/tests/modules/programs/waybar/systemd-with-graphical-session-target.nix24
-rw-r--r--home-manager/tests/modules/programs/waybar/systemd-with-graphical-session-target.service16
-rw-r--r--home-manager/tests/modules/programs/zplug/default.nix1
-rw-r--r--home-manager/tests/modules/programs/zplug/modules.nix50
-rw-r--r--home-manager/tests/modules/programs/zsh/default.nix7
-rw-r--r--home-manager/tests/modules/programs/zsh/history-path-new-custom.nix20
-rw-r--r--home-manager/tests/modules/programs/zsh/history-path-new-default.nix17
-rw-r--r--home-manager/tests/modules/programs/zsh/history-path-old-custom.nix20
-rw-r--r--home-manager/tests/modules/programs/zsh/history-path-old-default.nix17
-rw-r--r--home-manager/tests/modules/programs/zsh/session-variables.nix28
-rw-r--r--home-manager/tests/modules/services/dropbox/basic-configuration.nix25
-rw-r--r--home-manager/tests/modules/services/dropbox/default.nix1
-rw-r--r--home-manager/tests/modules/services/emacs/default.nix5
-rw-r--r--home-manager/tests/modules/services/emacs/emacs-emacsclient.desktop12
-rw-r--r--home-manager/tests/modules/services/emacs/emacs-service-emacs.service12
-rw-r--r--home-manager/tests/modules/services/emacs/emacs-service.nix37
-rw-r--r--home-manager/tests/modules/services/emacs/emacs-socket-26-emacs.service9
-rw-r--r--home-manager/tests/modules/services/emacs/emacs-socket-26-emacs.socket12
-rw-r--r--home-manager/tests/modules/services/emacs/emacs-socket-26.nix40
-rw-r--r--home-manager/tests/modules/services/emacs/emacs-socket-27-emacs.service9
-rw-r--r--home-manager/tests/modules/services/emacs/emacs-socket-27-emacs.socket12
-rw-r--r--home-manager/tests/modules/services/emacs/emacs-socket-27.nix42
-rw-r--r--home-manager/tests/modules/services/fluidsynth/default.nix1
-rw-r--r--home-manager/tests/modules/services/fluidsynth/service.nix24
-rw-r--r--home-manager/tests/modules/services/kanshi/basic-configuration.conf15
-rw-r--r--home-manager/tests/modules/services/kanshi/basic-configuration.nix52
-rw-r--r--home-manager/tests/modules/services/kanshi/default.nix1
-rw-r--r--home-manager/tests/modules/services/lieer/default.nix1
-rw-r--r--home-manager/tests/modules/services/lieer/lieer-service-expected.service8
-rw-r--r--home-manager/tests/modules/services/lieer/lieer-service-expected.timer9
-rw-r--r--home-manager/tests/modules/services/lieer/lieer-service.nix34
-rw-r--r--home-manager/tests/modules/services/polybar/basic-configuration.conf21
-rw-r--r--home-manager/tests/modules/services/polybar/basic-configuration.nix48
-rw-r--r--home-manager/tests/modules/services/polybar/default.nix1
-rw-r--r--home-manager/tests/modules/services/sxhkd/configuration.nix33
-rw-r--r--home-manager/tests/modules/services/sxhkd/default.nix4
-rw-r--r--home-manager/tests/modules/services/sxhkd/service.nix20
-rw-r--r--home-manager/tests/modules/services/sxhkd/sxhkdrc13
-rw-r--r--home-manager/tests/modules/services/window-managers/i3/default.nix4
-rw-r--r--home-manager/tests/modules/services/window-managers/i3/i3-followmouse-expected.conf105
-rw-r--r--home-manager/tests/modules/services/window-managers/i3/i3-followmouse.nix29
-rw-r--r--home-manager/tests/modules/services/window-managers/i3/i3-keybindings-expected.conf106
-rw-r--r--home-manager/tests/modules/services/window-managers/i3/i3-keybindings.nix35
-rw-r--r--home-manager/tests/modules/services/window-managers/sway/default.nix6
-rw-r--r--home-manager/tests/modules/services/window-managers/sway/sway-default.conf117
-rw-r--r--home-manager/tests/modules/services/window-managers/sway/sway-default.nix33
-rw-r--r--home-manager/tests/modules/services/window-managers/sway/sway-followmouse-expected.conf94
-rw-r--r--home-manager/tests/modules/services/window-managers/sway/sway-followmouse-legacy-expected.conf94
-rw-r--r--home-manager/tests/modules/services/window-managers/sway/sway-followmouse-legacy.nix37
-rw-r--r--home-manager/tests/modules/services/window-managers/sway/sway-followmouse.nix37
-rw-r--r--home-manager/tests/modules/services/window-managers/sway/sway-post-2003.nix35
-rw-r--r--home-manager/tests/modules/systemd/default.nix5
-rw-r--r--home-manager/tests/modules/systemd/services-expected.conf5
-rw-r--r--home-manager/tests/modules/systemd/services.nix23
-rw-r--r--home-manager/tests/modules/systemd/session-variables-expected.conf2
-rw-r--r--home-manager/tests/modules/systemd/session-variables.nix18
-rw-r--r--home-manager/tests/modules/systemd/timers-expected.conf8
-rw-r--r--home-manager/tests/modules/systemd/timers.nix25
-rw-r--r--home-manager/tests/modules/targets-darwin/darwin.nix20
-rw-r--r--home-manager/tests/modules/targets-darwin/default.nix5
-rw-r--r--home-manager/tests/modules/targets-linux/default.nix1
-rw-r--r--home-manager/tests/modules/targets-linux/generic-linux.nix22
-rw-r--r--home-manager/tests/modules/xresources/default.nix4
-rw-r--r--home-manager/tests/modules/xresources/empty.nix13
-rw-r--r--home-manager/tests/modules/xresources/xresources-expected.conf5
-rw-r--r--home-manager/tests/modules/xresources/xresources.nix22
256 files changed, 5927 insertions, 0 deletions
diff --git a/home-manager/tests/default.nix b/home-manager/tests/default.nix
new file mode 100644
index 00000000000..a4a4da0c94c
--- /dev/null
+++ b/home-manager/tests/default.nix
@@ -0,0 +1,102 @@
+{ pkgs ? import <nixpkgs> {} }:
+
+let
+
+ lib = import ../modules/lib/stdlib-extended.nix pkgs.lib;
+
+ nmt = pkgs.fetchFromGitLab {
+ owner = "rycee";
+ repo = "nmt";
+ rev = "8e130d655ec396ce165763c95bbf4ac429810ca8";
+ sha256 = "1jbljr06kg1ycdn24hj8xap16axq11rhb6hm4949fz48n57pwwps";
+ };
+
+ modules = import ../modules/modules.nix {
+ inherit lib pkgs;
+ check = false;
+ } ++ [
+ {
+ # Fix impurities. Without these some of the user's environment
+ # will leak into the tests through `builtins.getEnv`.
+ xdg.enable = true;
+ home.username = "hm-user";
+ home.homeDirectory = "/home/hm-user";
+
+ # Avoid including documentation since this will cause
+ # unnecessary rebuilds of the tests.
+ manual.manpages.enable = false;
+ }
+ ];
+
+in
+
+import nmt {
+ inherit lib pkgs modules;
+ testedAttrPath = [ "home" "activationPackage" ];
+ tests = builtins.foldl' (a: b: a // (import b)) { } ([
+ ./lib/types
+ ./modules/files
+ ./modules/home-environment
+ ./modules/misc/fontconfig
+ ./modules/programs/alacritty
+ ./modules/programs/alot
+ ./modules/programs/aria2
+ ./modules/programs/bash
+ ./modules/programs/browserpass
+ ./modules/programs/dircolors
+ ./modules/programs/direnv
+ ./modules/programs/fish
+ ./modules/programs/git
+ ./modules/programs/gpg
+ ./modules/programs/i3status
+ ./modules/programs/kakoune
+ ./modules/programs/lf
+ ./modules/programs/lieer
+ ./modules/programs/man
+ ./modules/programs/mbsync
+ ./modules/programs/ncmpcpp
+ ./modules/programs/ne
+ ./modules/programs/neomutt
+ ./modules/programs/newsboat
+ ./modules/programs/nushell
+ ./modules/programs/qutebrowser
+ ./modules/programs/readline
+ ./modules/programs/powerline-go
+ ./modules/programs/ssh
+ ./modules/programs/starship
+ ./modules/programs/texlive
+ ./modules/programs/tmux
+ ./modules/programs/vscode
+ ./modules/programs/zplug
+ ./modules/programs/zsh
+ ./modules/xresources
+ ] ++ lib.optionals pkgs.stdenv.hostPlatform.isDarwin [
+ ./modules/targets-darwin
+ ] ++ lib.optionals pkgs.stdenv.hostPlatform.isLinux [
+ ./meta # Suffices to run on one platform.
+ ./modules/misc/debug
+ ./modules/misc/numlock
+ ./modules/misc/pam
+ ./modules/misc/xdg
+ ./modules/misc/xsession
+ ./modules/programs/abook
+ ./modules/programs/autorandr
+ ./modules/services/dropbox
+ ./modules/services/emacs
+ ./modules/services/dropbox
+ ./modules/programs/firefox
+ ./modules/programs/getmail
+ ./modules/services/lieer
+ ./modules/programs/ncmpcpp-linux
+ ./modules/programs/rofi
+ ./modules/programs/waybar
+ ./modules/services/kanshi
+ ./modules/services/polybar
+ ./modules/services/sxhkd
+ ./modules/services/fluidsynth
+ ./modules/services/window-managers/i3
+ ./modules/services/window-managers/sway
+ ./modules/systemd
+ ./modules/targets-linux
+ ]);
+}
diff --git a/home-manager/tests/lib/types/dag-merge-result.txt b/home-manager/tests/lib/types/dag-merge-result.txt
new file mode 100644
index 00000000000..9779ef13c0f
--- /dev/null
+++ b/home-manager/tests/lib/types/dag-merge-result.txt
@@ -0,0 +1,3 @@
+before:before
+between:between
+after:after
diff --git a/home-manager/tests/lib/types/dag-merge.nix b/home-manager/tests/lib/types/dag-merge.nix
new file mode 100644
index 00000000000..138a0b64fb7
--- /dev/null
+++ b/home-manager/tests/lib/types/dag-merge.nix
@@ -0,0 +1,32 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+ dag = config.lib.dag;
+
+ result = let
+ sorted = dag.topoSort config.tested.dag;
+ data = map (e: "${e.name}:${e.data}") sorted.result;
+ in concatStringsSep "\n" data + "\n";
+
+in {
+ options.tested.dag = mkOption { type = hm.types.dagOf types.str; };
+
+ config = {
+ tested = mkMerge [
+ { dag.after = "after"; }
+ { dag.before = dag.entryBefore [ "after" ] "before"; }
+ { dag.between = dag.entryBetween [ "after" ] [ "before" ] "between"; }
+ ];
+
+ home.file."result.txt".text = result;
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/result.txt \
+ ${./dag-merge-result.txt}
+ '';
+ };
+}
diff --git a/home-manager/tests/lib/types/dag-submodule.nix b/home-manager/tests/lib/types/dag-submodule.nix
new file mode 100644
index 00000000000..552e804acbc
--- /dev/null
+++ b/home-manager/tests/lib/types/dag-submodule.nix
@@ -0,0 +1,43 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+ dag = config.lib.dag;
+
+ result = let
+ sorted = dag.topoSort config.tested.dag;
+ data = map (e: "${e.name}:${e.data.name}") sorted.result;
+ in concatStringsSep "\n" data + "\n";
+
+in {
+ options.tested.dag = mkOption {
+ type = hm.types.dagOf (types.submodule ({ dagName, ... }: {
+ options.name = mkOption { type = types.str; };
+ config.name = "dn-${dagName}";
+ }));
+ };
+
+ config = {
+ tested.dag = {
+ after = { };
+ before = dag.entryBefore [ "after" ] { };
+ between = dag.entryBetween [ "after" ] [ "before" ] { };
+ };
+
+ home.file."result.txt".text = result;
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/result.txt \
+ ${
+ pkgs.writeText "result.txt" ''
+ before:dn-before
+ between:dn-between
+ after:dn-after
+ ''
+ }
+ '';
+ };
+}
diff --git a/home-manager/tests/lib/types/default.nix b/home-manager/tests/lib/types/default.nix
new file mode 100644
index 00000000000..acb56501272
--- /dev/null
+++ b/home-manager/tests/lib/types/default.nix
@@ -0,0 +1,7 @@
+{
+ lib-types-dag-submodule = ./dag-submodule.nix;
+ lib-types-dag-merge = ./dag-merge.nix;
+ lib-types-list-or-dag-merge = ./list-or-dag-merge.nix;
+
+ lib-types-gvariant-merge = ./gvariant-merge.nix;
+}
diff --git a/home-manager/tests/lib/types/gvariant-merge.nix b/home-manager/tests/lib/types/gvariant-merge.nix
new file mode 100644
index 00000000000..867534c1f14
--- /dev/null
+++ b/home-manager/tests/lib/types/gvariant-merge.nix
@@ -0,0 +1,62 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+in {
+ options.examples = mkOption { type = types.attrsOf hm.types.gvariant; };
+
+ config = {
+ examples = with hm.gvariant;
+ mkMerge [
+ { bool = true; }
+ { bool = true; }
+
+ { float = 3.14; }
+
+ { int = 42; }
+ { int = 42; }
+
+ { list = [ "one" ]; }
+ { list = mkArray type.string [ "two" ]; }
+
+ { emptyArray1 = [ ]; }
+ { emptyArray2 = mkEmptyArray type.uint32; }
+
+ { string = "foo"; }
+ { string = "foo"; }
+ { escapedString = "' \\"; }
+
+ { tuple = mkTuple [ 1 [ "foo" ] ]; }
+
+ { maybe1 = mkNothing type.string; }
+ { maybe2 = mkJust (mkUint32 4); }
+ ];
+
+ home.file."result.txt".text = let
+ mkLine = n: v: "${n} = ${toString (hm.gvariant.mkValue v)}";
+ result = concatStringsSep "\n" (mapAttrsToList mkLine config.examples);
+ in result + "\n";
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/result.txt \
+ ${
+ pkgs.writeText "expected.txt" ''
+ bool = true
+ emptyArray1 = @as []
+ emptyArray2 = @as []
+ escapedString = '\' \\'
+ float = 3.140000
+ int = 42
+ list = @as ['one','two']
+ maybe1 = @ms nothing
+ maybe2 = just @u 4
+ string = 'foo'
+ tuple = @(ias) (1,@as ['foo'])
+ ''
+ }
+ '';
+ };
+}
diff --git a/home-manager/tests/lib/types/list-or-dag-merge-result.txt b/home-manager/tests/lib/types/list-or-dag-merge-result.txt
new file mode 100644
index 00000000000..5fb67a5101c
--- /dev/null
+++ b/home-manager/tests/lib/types/list-or-dag-merge-result.txt
@@ -0,0 +1,15 @@
+before:before
+between:between
+after:after
+unnamed-1.1:k
+unnamed-1.2:l
+unnamed-2.01:a
+unnamed-2.02:b
+unnamed-2.03:c
+unnamed-2.04:d
+unnamed-2.05:e
+unnamed-2.06:f
+unnamed-2.07:g
+unnamed-2.08:h
+unnamed-2.09:i
+unnamed-2.10:j
diff --git a/home-manager/tests/lib/types/list-or-dag-merge.nix b/home-manager/tests/lib/types/list-or-dag-merge.nix
new file mode 100644
index 00000000000..08216140e53
--- /dev/null
+++ b/home-manager/tests/lib/types/list-or-dag-merge.nix
@@ -0,0 +1,34 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+ dag = config.lib.dag;
+
+ result = let
+ sorted = dag.topoSort config.tested.dag;
+ data = map (e: "${e.name}:${e.data}") sorted.result;
+ in concatStringsSep "\n" data + "\n";
+
+in {
+ options.tested.dag = mkOption { type = hm.types.listOrDagOf types.str; };
+
+ config = {
+ tested = mkMerge [
+ { dag = [ "k" "l" ]; }
+ { dag = [ "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" ]; }
+ { dag.after = "after"; }
+ { dag.before = dag.entryBefore [ "after" ] "before"; }
+ { dag.between = dag.entryBetween [ "after" ] [ "before" ] "between"; }
+ ];
+
+ home.file."result.txt".text = result;
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/result.txt \
+ ${./list-or-dag-merge-result.txt}
+ '';
+ };
+}
diff --git a/home-manager/tests/meta/default.nix b/home-manager/tests/meta/default.nix
new file mode 100644
index 00000000000..0f02fcfb453
--- /dev/null
+++ b/home-manager/tests/meta/default.nix
@@ -0,0 +1 @@
+{ meta-formatting = ./formatting.nix; }
diff --git a/home-manager/tests/meta/formatting.nix b/home-manager/tests/meta/formatting.nix
new file mode 100644
index 00000000000..2d5800c53cd
--- /dev/null
+++ b/home-manager/tests/meta/formatting.nix
@@ -0,0 +1,27 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+ pinnedNixpkgs = builtins.fetchTarball {
+ url =
+ "https://github.com/NixOS/nixpkgs/archive/05f0934825c2a0750d4888c4735f9420c906b388.tar.gz";
+ sha256 = "1g8c2w0661qn89ajp44znmwfmghbbiygvdzq0rzlvlpdiz28v6gy";
+ };
+
+ pinnedPkgs = import pinnedNixpkgs { };
+
+in {
+ config = {
+ nmt.script = ''
+ PATH="${with pinnedPkgs; lib.makeBinPath [ findutils nixfmt ]}:$PATH"
+ cd ${../..}
+ if ! ${pkgs.runtimeShell} format -c; then
+ fail "${''
+ Expected source code to be formatted with nixfmt but it was not.
+ This error can be resolved by running the './format' in the project root directory.''}"
+ fi
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/accounts/email-test-accounts.nix b/home-manager/tests/modules/accounts/email-test-accounts.nix
new file mode 100644
index 00000000000..9a4e0b8e72f
--- /dev/null
+++ b/home-manager/tests/modules/accounts/email-test-accounts.nix
@@ -0,0 +1,28 @@
+{ ... }:
+
+{
+ accounts.email = {
+ maildirBasePath = "Mail";
+
+ accounts = {
+ "hm@example.com" = {
+ address = "hm@example.com";
+ userName = "home.manager";
+ realName = "H. M. Test";
+ passwordCommand = "password-command";
+ imap.host = "imap.example.com";
+ smtp.host = "smtp.example.com";
+ };
+
+ hm-account = {
+ address = "hm@example.org";
+ userName = "home.manager.jr";
+ realName = "H. M. Test Jr.";
+ passwordCommand = "password-command 2";
+ imap.host = "imap.example.org";
+ smtp.host = "smtp.example.org";
+ smtp.tls.useStartTls = true;
+ };
+ };
+ };
+}
diff --git a/home-manager/tests/modules/files/.hidden b/home-manager/tests/modules/files/.hidden
new file mode 100644
index 00000000000..ca05448e7a0
--- /dev/null
+++ b/home-manager/tests/modules/files/.hidden
@@ -0,0 +1 @@
+The name of this file has a dot prefix.
diff --git a/home-manager/tests/modules/files/default.nix b/home-manager/tests/modules/files/default.nix
new file mode 100644
index 00000000000..6f1ef24b810
--- /dev/null
+++ b/home-manager/tests/modules/files/default.nix
@@ -0,0 +1,8 @@
+{
+ files-executable = ./executable.nix;
+ files-hidden-source = ./hidden-source.nix;
+ files-out-of-store-symlink = ./out-of-store-symlink.nix;
+ files-source-with-spaces = ./source-with-spaces.nix;
+ files-target-with-shellvar = ./target-with-shellvar.nix;
+ files-text = ./text.nix;
+}
diff --git a/home-manager/tests/modules/files/executable.nix b/home-manager/tests/modules/files/executable.nix
new file mode 100644
index 00000000000..b286c2b499f
--- /dev/null
+++ b/home-manager/tests/modules/files/executable.nix
@@ -0,0 +1,17 @@
+{ config, lib, ... }:
+
+with lib;
+
+{
+ config = {
+ home.file."executable" = {
+ text = "";
+ executable = true;
+ };
+
+ nmt.script = ''
+ assertFileExists home-files/executable
+ assertFileIsExecutable home-files/executable;
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/files/hidden-source.nix b/home-manager/tests/modules/files/hidden-source.nix
new file mode 100644
index 00000000000..8169fedcd7f
--- /dev/null
+++ b/home-manager/tests/modules/files/hidden-source.nix
@@ -0,0 +1,19 @@
+{ config, lib, ... }:
+
+with lib;
+
+{
+ config = {
+ home.file.".hidden".source = ./.hidden;
+
+ nmt.script = ''
+ assertFileExists home-files/.hidden;
+ assertFileContent home-files/.hidden ${
+ builtins.path {
+ path = ./.hidden;
+ name = "expected";
+ }
+ }
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/files/out-of-store-symlink.nix b/home-manager/tests/modules/files/out-of-store-symlink.nix
new file mode 100644
index 00000000000..af274aaebec
--- /dev/null
+++ b/home-manager/tests/modules/files/out-of-store-symlink.nix
@@ -0,0 +1,29 @@
+{ config, lib, ... }:
+
+with lib;
+
+let
+
+ filePath = ./. + "/source with spaces!";
+
+in {
+ config = {
+ home.file."oos".source = config.lib.file.mkOutOfStoreSymlink filePath;
+
+ nmt.script = ''
+ assertLinkExists "home-files/oos"
+
+ storePath="$(readlink $TESTED/home-files/oos)"
+
+ if [[ ! -L $storePath ]]; then
+ fail "Expected $storePath to be a symbolic link, but it was not."
+ fi
+
+ actual="$(readlink "$storePath")"
+ expected="${toString filePath}"
+ if [[ $actual != $expected ]]; then
+ fail "Symlink home-files/oos should point to $expected via the Nix store, but it actually points to $actual."
+ fi
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/files/source with spaces! b/home-manager/tests/modules/files/source with spaces!
new file mode 100644
index 00000000000..e1ace404174
--- /dev/null
+++ b/home-manager/tests/modules/files/source with spaces!
@@ -0,0 +1 @@
+Source with spaces!
diff --git a/home-manager/tests/modules/files/source-with-spaces.nix b/home-manager/tests/modules/files/source-with-spaces.nix
new file mode 100644
index 00000000000..1d593c64256
--- /dev/null
+++ b/home-manager/tests/modules/files/source-with-spaces.nix
@@ -0,0 +1,20 @@
+{ config, lib, ... }:
+
+with lib;
+
+{
+ config = {
+ home.file."source with spaces!".source = ./. + "/source with spaces!";
+
+ nmt.script = ''
+ assertFileExists 'home-files/source with spaces!';
+ assertFileContent 'home-files/source with spaces!' \
+ ${
+ builtins.path {
+ path = ./. + "/source with spaces!";
+ name = "source-with-spaces-expected";
+ }
+ }
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/files/target-with-shellvar.nix b/home-manager/tests/modules/files/target-with-shellvar.nix
new file mode 100644
index 00000000000..c54946eb9eb
--- /dev/null
+++ b/home-manager/tests/modules/files/target-with-shellvar.nix
@@ -0,0 +1,15 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ home.file."$HOME/$FOO/bar baz".text = "blah";
+
+ nmt.script = ''
+ assertFileExists 'home-files/$HOME/$FOO/bar baz';
+ assertFileContent 'home-files/$HOME/$FOO/bar baz' \
+ ${pkgs.writeText "expected" "blah"}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/files/text-expected.txt b/home-manager/tests/modules/files/text-expected.txt
new file mode 100644
index 00000000000..b3a0ff2db12
--- /dev/null
+++ b/home-manager/tests/modules/files/text-expected.txt
@@ -0,0 +1,2 @@
+This is the
+expected text.
diff --git a/home-manager/tests/modules/files/text.nix b/home-manager/tests/modules/files/text.nix
new file mode 100644
index 00000000000..6fc9a26fcb4
--- /dev/null
+++ b/home-manager/tests/modules/files/text.nix
@@ -0,0 +1,18 @@
+{ config, lib, ... }:
+
+with lib;
+
+{
+ config = {
+ home.file."using-text".text = ''
+ This is the
+ expected text.
+ '';
+
+ nmt.script = ''
+ assertFileExists home-files/using-text
+ assertFileIsNotExecutable home-files/using-text
+ assertFileContent home-files/using-text ${./text-expected.txt}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/home-environment/default.nix b/home-manager/tests/modules/home-environment/default.nix
new file mode 100644
index 00000000000..2a1201a2f0a
--- /dev/null
+++ b/home-manager/tests/modules/home-environment/default.nix
@@ -0,0 +1,3 @@
+{
+ home-session-variables = ./session-variables.nix;
+}
diff --git a/home-manager/tests/modules/home-environment/session-variables-expected.txt b/home-manager/tests/modules/home-environment/session-variables-expected.txt
new file mode 100644
index 00000000000..4e18e2b31a8
--- /dev/null
+++ b/home-manager/tests/modules/home-environment/session-variables-expected.txt
@@ -0,0 +1,9 @@
+# Only source this once.
+if [ -n "$__HM_SESS_VARS_SOURCED" ]; then return; fi
+export __HM_SESS_VARS_SOURCED=1
+
+export V1="v1"
+export V2="v2-v1"
+export XDG_CACHE_HOME="/home/hm-user/.cache"
+export XDG_CONFIG_HOME="/home/hm-user/.config"
+export XDG_DATA_HOME="/home/hm-user/.local/share"
diff --git a/home-manager/tests/modules/home-environment/session-variables.nix b/home-manager/tests/modules/home-environment/session-variables.nix
new file mode 100644
index 00000000000..9f326ebc1b8
--- /dev/null
+++ b/home-manager/tests/modules/home-environment/session-variables.nix
@@ -0,0 +1,19 @@
+{ config, lib, ... }:
+
+with lib;
+
+{
+ config = {
+ home.sessionVariables = {
+ V1 = "v1";
+ V2 = "v2-${config.home.sessionVariables.V1}";
+ };
+
+ nmt.script = ''
+ assertFileExists home-path/etc/profile.d/hm-session-vars.sh
+ assertFileContent \
+ home-path/etc/profile.d/hm-session-vars.sh \
+ ${./session-variables-expected.txt}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/misc/debug/default.nix b/home-manager/tests/modules/misc/debug/default.nix
new file mode 100644
index 00000000000..b42462d0802
--- /dev/null
+++ b/home-manager/tests/modules/misc/debug/default.nix
@@ -0,0 +1,25 @@
+{
+ debug = { pkgs, config, lib, ... }: {
+ home.enableDebugInfo = true;
+ home.packages = with pkgs; [ curl gdb ];
+
+ nmt.script = ''
+ [ -L $TESTED/home-path/lib/debug/curl ] \
+ || fail "Debug-symbols for pkgs.curl should exist in \`/home-path/lib/debug'!"
+
+ #source $TESTED/home-path/etc/profile.d/hm-session-vars.sh
+ #[[ "$NIX_DEBUG_INFO_DIRS" =~ /lib/debug$ ]] \
+ #|| fail "Invalid NIX_DEBUG_INFO_DIRS!"
+ assertFileExists home-path/etc/profile.d/hm-session-vars.sh
+ assertFileRegex home-path/etc/profile.d/hm-session-vars.sh \
+ 'NIX_DEBUG_INFO_DIRS=.*/lib/debug'
+
+ # We need to override NIX_DEBUG_INFO_DIRS here as $HOME evalutes to the home
+ # of the user who executes this testcase :/
+ { echo quit | PATH="$TESTED/home-path/bin''${PATH:+:}$PATH" NIX_DEBUG_INFO_DIRS=$TESTED/home-path/lib/debug \
+ gdb curl 2>&1 | \
+ grep 'Reading symbols from ${builtins.storeDir}/'; \
+ } || fail "Failed to read debug symbols from curl in gdb"
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/misc/fontconfig/default.nix b/home-manager/tests/modules/misc/fontconfig/default.nix
new file mode 100644
index 00000000000..bea306165c4
--- /dev/null
+++ b/home-manager/tests/modules/misc/fontconfig/default.nix
@@ -0,0 +1,22 @@
+{
+ fontconfig-no-font-package = ./no-font-package.nix;
+ fontconfig-single-font-package = ./single-font-package.nix;
+ # Disabled due to test failing with message
+ #
+ # Expected directory home-path/lib/fontconfig/cache to exist but it was not found.
+ #
+ # Verbose output from fc-cache:
+ #
+ # Font directories:
+ # /nix/store/da…g5-home-manager-path/lib/X11/fonts
+ # /nix/store/da…g5-home-manager-path/share/fonts
+ # /nix/store/da…g5-home-manager-path/share/fonts/truetype
+ # /nix/store/da…g5-home-manager-path/lib/X11/fonts: skipping, no such directory
+ # /nix/store/da…g5-home-manager-path/share/fonts: caching, new cache contents: 1 fonts, 1 dirs
+ # /nix/store/da…g5-home-manager-path/share/fonts/truetype: caching, new cache contents: 3 fonts, 0 dirs
+ # /nix/store/da…g5-home-manager-path/share/fonts/truetype: skipping, looped directory detected
+ # /nix/store/da…g5-home-manager-path/lib/fontconfig/cache: cleaning cache directory
+ # /nix/store/da…g5-home-manager-path/lib/fontconfig/cache: invalid cache file: 786068e7df13f7c2105017ef3d78e351-x86_64.cache-7
+ # /nix/store/da…g5-home-manager-path/lib/fontconfig/cache: invalid cache file: 4766193978ddda4bd196f2b98c00fb00-x86_64.cache-7
+ #fontconfig-multiple-font-packages = ./multiple-font-packages.nix;
+}
diff --git a/home-manager/tests/modules/misc/fontconfig/multiple-font-packages.nix b/home-manager/tests/modules/misc/fontconfig/multiple-font-packages.nix
new file mode 100644
index 00000000000..3845b4ba4b1
--- /dev/null
+++ b/home-manager/tests/modules/misc/fontconfig/multiple-font-packages.nix
@@ -0,0 +1,15 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ home.packages = [ pkgs.comic-relief pkgs.unifont ];
+
+ fonts.fontconfig.enable = true;
+
+ nmt.script = ''
+ assertDirectoryNotEmpty home-path/lib/fontconfig/cache
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/misc/fontconfig/no-font-package.nix b/home-manager/tests/modules/misc/fontconfig/no-font-package.nix
new file mode 100644
index 00000000000..c4c687a1320
--- /dev/null
+++ b/home-manager/tests/modules/misc/fontconfig/no-font-package.nix
@@ -0,0 +1,17 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ home.packages = [
+ # Look, no font!
+ ];
+
+ fonts.fontconfig.enable = true;
+
+ nmt.script = ''
+ assertPathNotExists home-path/lib/fontconfig/cache
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/misc/fontconfig/single-font-package.nix b/home-manager/tests/modules/misc/fontconfig/single-font-package.nix
new file mode 100644
index 00000000000..b70bdf8a9a7
--- /dev/null
+++ b/home-manager/tests/modules/misc/fontconfig/single-font-package.nix
@@ -0,0 +1,15 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ home.packages = [ pkgs.comic-relief ];
+
+ fonts.fontconfig.enable = true;
+
+ nmt.script = ''
+ assertDirectoryNotEmpty home-path/lib/fontconfig/cache
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/misc/numlock/default.nix b/home-manager/tests/modules/misc/numlock/default.nix
new file mode 100644
index 00000000000..47ca563fec0
--- /dev/null
+++ b/home-manager/tests/modules/misc/numlock/default.nix
@@ -0,0 +1 @@
+{ numlock = ./numlock.nix; }
diff --git a/home-manager/tests/modules/misc/numlock/numlock.nix b/home-manager/tests/modules/misc/numlock/numlock.nix
new file mode 100644
index 00000000000..aa468c212c3
--- /dev/null
+++ b/home-manager/tests/modules/misc/numlock/numlock.nix
@@ -0,0 +1,18 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ xsession.numlock.enable = true;
+
+ nixpkgs.overlays = [
+ (self: super: { numlockx = pkgs.writeScriptBin "dummy-numlockx" ""; })
+ ];
+
+ nmt.script = ''
+ serviceFile=home-files/.config/systemd/user/numlockx.service
+ assertFileExists $serviceFile
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/misc/pam/default.nix b/home-manager/tests/modules/misc/pam/default.nix
new file mode 100644
index 00000000000..81c435e7641
--- /dev/null
+++ b/home-manager/tests/modules/misc/pam/default.nix
@@ -0,0 +1 @@
+{ pam-session-variables = ./session-variables.nix; }
diff --git a/home-manager/tests/modules/misc/pam/session-variables-expected.txt b/home-manager/tests/modules/misc/pam/session-variables-expected.txt
new file mode 100644
index 00000000000..b84a12b7675
--- /dev/null
+++ b/home-manager/tests/modules/misc/pam/session-variables-expected.txt
@@ -0,0 +1,2 @@
+V1 OVERRIDE="v1"
+V2 OVERRIDE="v2-v1"
diff --git a/home-manager/tests/modules/misc/pam/session-variables.nix b/home-manager/tests/modules/misc/pam/session-variables.nix
new file mode 100644
index 00000000000..4fbec4163b5
--- /dev/null
+++ b/home-manager/tests/modules/misc/pam/session-variables.nix
@@ -0,0 +1,19 @@
+{ config, lib, ... }:
+
+with lib;
+
+{
+ config = {
+ pam.sessionVariables = {
+ V1 = "v1";
+ V2 = "v2-${config.pam.sessionVariables.V1}";
+ };
+
+ nmt.script = ''
+ assertFileExists home-files/.pam_environment
+ assertFileContent \
+ home-files/.pam_environment \
+ ${./session-variables-expected.txt}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/misc/xdg/default.nix b/home-manager/tests/modules/misc/xdg/default.nix
new file mode 100644
index 00000000000..e5d015759d5
--- /dev/null
+++ b/home-manager/tests/modules/misc/xdg/default.nix
@@ -0,0 +1 @@
+{ xdg-mime-apps-basics = ./mime-apps-basics.nix; }
diff --git a/home-manager/tests/modules/misc/xdg/mime-apps-basics-expected.ini b/home-manager/tests/modules/misc/xdg/mime-apps-basics-expected.ini
new file mode 100644
index 00000000000..c27181eb58f
--- /dev/null
+++ b/home-manager/tests/modules/misc/xdg/mime-apps-basics-expected.ini
@@ -0,0 +1,9 @@
+[Added Associations]
+mimetype1=foo1.desktop;foo2.desktop;foo3.desktop
+mimetype2=foo4.desktop
+
+[Default Applications]
+mimetype1=default1.desktop;default2.desktop
+
+[Removed Associations]
+mimetype1=foo5.desktop
diff --git a/home-manager/tests/modules/misc/xdg/mime-apps-basics.nix b/home-manager/tests/modules/misc/xdg/mime-apps-basics.nix
new file mode 100644
index 00000000000..e181e8206f6
--- /dev/null
+++ b/home-manager/tests/modules/misc/xdg/mime-apps-basics.nix
@@ -0,0 +1,28 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ xdg.mimeApps = {
+ enable = true;
+ associations = {
+ added = {
+ "mimetype1" = [ "foo1.desktop" "foo2.desktop" "foo3.desktop" ];
+ "mimetype2" = "foo4.desktop";
+ };
+ removed = { mimetype1 = "foo5.desktop"; };
+ };
+ defaultApplications = {
+ "mimetype1" = [ "default1.desktop" "default2.desktop" ];
+ };
+ };
+
+ nmt.script = ''
+ assertFileExists home-files/.config/mimeapps.list
+ assertFileContent \
+ home-files/.config/mimeapps.list \
+ ${./mime-apps-basics-expected.ini}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/misc/xsession/basic-setxkbmap-expected.service b/home-manager/tests/modules/misc/xsession/basic-setxkbmap-expected.service
new file mode 100644
index 00000000000..39f876dd60e
--- /dev/null
+++ b/home-manager/tests/modules/misc/xsession/basic-setxkbmap-expected.service
@@ -0,0 +1,12 @@
+[Install]
+WantedBy=graphical-session.target
+
+[Service]
+ExecStart=@setxkbmap@/bin/setxkbmap -layout 'us' -variant ''
+RemainAfterExit=true
+Type=oneshot
+
+[Unit]
+After=graphical-session-pre.target
+Description=Set up keyboard in X
+PartOf=graphical-session.target
diff --git a/home-manager/tests/modules/misc/xsession/basic-xprofile-expected.txt b/home-manager/tests/modules/misc/xsession/basic-xprofile-expected.txt
new file mode 100644
index 00000000000..282f8f5c5de
--- /dev/null
+++ b/home-manager/tests/modules/misc/xsession/basic-xprofile-expected.txt
@@ -0,0 +1,16 @@
+. "/home/hm-user/.nix-profile/etc/profile.d/hm-session-vars.sh"
+
+if [ -e "$HOME/.profile" ]; then
+ . "$HOME/.profile"
+fi
+
+# If there are any running services from a previous session.
+# Need to run this in xprofile because the NixOS xsession
+# script starts up graphical-session.target.
+systemctl --user stop graphical-session.target graphical-session-pre.target
+
+systemctl --user import-environment DBUS_SESSION_BUS_ADDRESS DISPLAY SSH_AUTH_SOCK XAUTHORITY XDG_DATA_DIRS XDG_RUNTIME_DIR XDG_SESSION_ID EXTRA_IMPORTED_VARIABLE
+
+profile extra commands
+
+export HM_XPROFILE_SOURCED=1
diff --git a/home-manager/tests/modules/misc/xsession/basic-xsession-expected.txt b/home-manager/tests/modules/misc/xsession/basic-xsession-expected.txt
new file mode 100644
index 00000000000..c11b7c33048
--- /dev/null
+++ b/home-manager/tests/modules/misc/xsession/basic-xsession-expected.txt
@@ -0,0 +1,18 @@
+if [ -z "$HM_XPROFILE_SOURCED" ]; then
+ . ~/.xprofile
+fi
+unset HM_XPROFILE_SOURCED
+
+systemctl --user start hm-graphical-session.target
+
+init extra commands
+
+window manager command
+
+systemctl --user stop graphical-session.target
+systemctl --user stop graphical-session-pre.target
+
+# Wait until the units actually stop.
+while [ -n "$(systemctl --user --no-legend --state=deactivating list-units)" ]; do
+ sleep 0.5
+done
diff --git a/home-manager/tests/modules/misc/xsession/basic.nix b/home-manager/tests/modules/misc/xsession/basic.nix
new file mode 100644
index 00000000000..d6756291cfe
--- /dev/null
+++ b/home-manager/tests/modules/misc/xsession/basic.nix
@@ -0,0 +1,40 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ xsession = {
+ enable = true;
+ windowManager.command = "window manager command";
+ importedVariables = [ "EXTRA_IMPORTED_VARIABLE" ];
+ initExtra = "init extra commands";
+ profileExtra = "profile extra commands";
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ xorg = super.xorg // {
+ setxkbmap = super.xorg.setxkbmap // { outPath = "@setxkbmap@"; };
+ };
+ })
+ ];
+
+ nmt.script = ''
+ assertFileExists home-files/.xprofile
+ assertFileContent \
+ home-files/.xprofile \
+ ${./basic-xprofile-expected.txt}
+
+ assertFileExists home-files/.xsession
+ assertFileContent \
+ home-files/.xsession \
+ ${./basic-xsession-expected.txt}
+
+ assertFileExists home-files/.config/systemd/user/setxkbmap.service
+ assertFileContent \
+ home-files/.config/systemd/user/setxkbmap.service \
+ ${./basic-setxkbmap-expected.service}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/misc/xsession/default.nix b/home-manager/tests/modules/misc/xsession/default.nix
new file mode 100644
index 00000000000..2ddbf47efac
--- /dev/null
+++ b/home-manager/tests/modules/misc/xsession/default.nix
@@ -0,0 +1,4 @@
+{
+ xsession-basic = ./basic.nix;
+ xsession-keyboard-without-layout = ./keyboard-without-layout.nix;
+}
diff --git a/home-manager/tests/modules/misc/xsession/keyboard-without-layout-expected.service b/home-manager/tests/modules/misc/xsession/keyboard-without-layout-expected.service
new file mode 100644
index 00000000000..a04af53dad7
--- /dev/null
+++ b/home-manager/tests/modules/misc/xsession/keyboard-without-layout-expected.service
@@ -0,0 +1,12 @@
+[Install]
+WantedBy=graphical-session.target
+
+[Service]
+ExecStart=@setxkbmap@/bin/setxkbmap -option 'ctrl:nocaps' -option 'altwin:no_win'
+RemainAfterExit=true
+Type=oneshot
+
+[Unit]
+After=graphical-session-pre.target
+Description=Set up keyboard in X
+PartOf=graphical-session.target
diff --git a/home-manager/tests/modules/misc/xsession/keyboard-without-layout.nix b/home-manager/tests/modules/misc/xsession/keyboard-without-layout.nix
new file mode 100644
index 00000000000..90038cfd034
--- /dev/null
+++ b/home-manager/tests/modules/misc/xsession/keyboard-without-layout.nix
@@ -0,0 +1,34 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ home.stateVersion = "19.09";
+
+ home.keyboard = { options = [ "ctrl:nocaps" "altwin:no_win" ]; };
+
+ xsession = {
+ enable = true;
+ windowManager.command = "window manager command";
+ importedVariables = [ "EXTRA_IMPORTED_VARIABLE" ];
+ initExtra = "init extra commands";
+ profileExtra = "profile extra commands";
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ xorg = super.xorg // {
+ setxkbmap = super.xorg.setxkbmap // { outPath = "@setxkbmap@"; };
+ };
+ })
+ ];
+
+ nmt.script = ''
+ assertFileExists home-files/.config/systemd/user/setxkbmap.service
+ assertFileContent \
+ home-files/.config/systemd/user/setxkbmap.service \
+ ${./keyboard-without-layout-expected.service}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/abook/default.nix b/home-manager/tests/modules/programs/abook/default.nix
new file mode 100644
index 00000000000..12ad238ed25
--- /dev/null
+++ b/home-manager/tests/modules/programs/abook/default.nix
@@ -0,0 +1,4 @@
+{
+ abook-no-settings = ./no-settings.nix;
+ abook-with-settings = ./with-settings.nix;
+}
diff --git a/home-manager/tests/modules/programs/abook/no-settings.nix b/home-manager/tests/modules/programs/abook/no-settings.nix
new file mode 100644
index 00000000000..ad04acd2365
--- /dev/null
+++ b/home-manager/tests/modules/programs/abook/no-settings.nix
@@ -0,0 +1,16 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.abook.enable = true;
+
+ nixpkgs.overlays =
+ [ (self: super: { abook = pkgs.writeScriptBin "dummy-abook" ""; }) ];
+
+ nmt.script = ''
+ assertPathNotExists home-files/.config/abook/abookrc
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/abook/with-settings.cfg b/home-manager/tests/modules/programs/abook/with-settings.cfg
new file mode 100644
index 00000000000..d73445f4d83
--- /dev/null
+++ b/home-manager/tests/modules/programs/abook/with-settings.cfg
@@ -0,0 +1,21 @@
+# Generated by Home Manager.
+# See http://abook.sourceforge.net/
+
+# Defining a new custom field
+# -----------------------------
+
+field pager = Pager
+field address_lines = Address, list
+field birthday = Birthday, date
+
+# Defining a view/tab
+# ---------------------
+
+view CONTACT = name, email
+view ADDRESS = address_lines, city, state, zip, country
+view PHONE = phone, workphone, pager, mobile, fax
+view OTHER = url, birthday
+
+# Automatically save database on exit
+set autosave=true
+
diff --git a/home-manager/tests/modules/programs/abook/with-settings.nix b/home-manager/tests/modules/programs/abook/with-settings.nix
new file mode 100644
index 00000000000..3cb02a2666c
--- /dev/null
+++ b/home-manager/tests/modules/programs/abook/with-settings.nix
@@ -0,0 +1,39 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.abook = {
+ enable = true;
+
+ extraConfig = ''
+ # Defining a new custom field
+ # -----------------------------
+
+ field pager = Pager
+ field address_lines = Address, list
+ field birthday = Birthday, date
+
+ # Defining a view/tab
+ # ---------------------
+
+ view CONTACT = name, email
+ view ADDRESS = address_lines, city, state, zip, country
+ view PHONE = phone, workphone, pager, mobile, fax
+ view OTHER = url, birthday
+
+ # Automatically save database on exit
+ set autosave=true
+ '';
+ };
+
+ nixpkgs.overlays =
+ [ (self: super: { abook = pkgs.writeScriptBin "dummy-abook" ""; }) ];
+
+ nmt.script = ''
+ assertFileExists home-files/.config/abook/abookrc
+ assertFileContent home-files/.config/abook/abookrc ${./with-settings.cfg}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/alacritty/default.nix b/home-manager/tests/modules/programs/alacritty/default.nix
new file mode 100644
index 00000000000..f63e033d846
--- /dev/null
+++ b/home-manager/tests/modules/programs/alacritty/default.nix
@@ -0,0 +1,4 @@
+{
+ alacritty-example-settings = ./example-settings.nix;
+ alacritty-empty-settings = ./empty-settings.nix;
+}
diff --git a/home-manager/tests/modules/programs/alacritty/empty-settings.nix b/home-manager/tests/modules/programs/alacritty/empty-settings.nix
new file mode 100644
index 00000000000..65470473c1a
--- /dev/null
+++ b/home-manager/tests/modules/programs/alacritty/empty-settings.nix
@@ -0,0 +1,17 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.alacritty.enable = true;
+
+ nixpkgs.overlays = [
+ (self: super: { alacritty = pkgs.writeScriptBin "dummy-alacritty" ""; })
+ ];
+
+ nmt.script = ''
+ assertPathNotExists home-files/.config/alacritty
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/alacritty/example-settings-expected.yml b/home-manager/tests/modules/programs/alacritty/example-settings-expected.yml
new file mode 100644
index 00000000000..061624192c3
--- /dev/null
+++ b/home-manager/tests/modules/programs/alacritty/example-settings-expected.yml
@@ -0,0 +1 @@
+{"key_bindings":[{"chars":"\x0c","key":"K","mods":"Control"}],"window":{"dimensions":{"columns":200,"lines":3}}} \ No newline at end of file
diff --git a/home-manager/tests/modules/programs/alacritty/example-settings.nix b/home-manager/tests/modules/programs/alacritty/example-settings.nix
new file mode 100644
index 00000000000..c3671aa0ca3
--- /dev/null
+++ b/home-manager/tests/modules/programs/alacritty/example-settings.nix
@@ -0,0 +1,31 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.alacritty = {
+ enable = true;
+ package = pkgs.writeScriptBin "dummy-alacritty" "";
+
+ settings = {
+ window.dimensions = {
+ lines = 3;
+ columns = 200;
+ };
+
+ key_bindings = [{
+ key = "K";
+ mods = "Control";
+ chars = "\\x0c";
+ }];
+ };
+ };
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/.config/alacritty/alacritty.yml \
+ ${./example-settings-expected.yml}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/alot/alot-expected.conf b/home-manager/tests/modules/programs/alot/alot-expected.conf
new file mode 100644
index 00000000000..6d3ace4a372
--- /dev/null
+++ b/home-manager/tests/modules/programs/alot/alot-expected.conf
@@ -0,0 +1,37 @@
+# Generated by Home Manager.
+# See http://alot.readthedocs.io/en/latest/configuration/config_options.html
+
+auto_remove_unread = True
+handle_mouse = True
+initial_command = search tag:inbox AND NOT tag:killed
+prefer_plaintext = True
+
+
+[tags]
+[bindings]
+
+
+[[bufferlist]]
+
+[[search]]
+
+[[envelope]]
+
+[[taglist]]
+
+[[thread]]
+
+
+[accounts]
+
+[[hm@example.com]]
+address=hm@example.com
+draft_box=maildir:///home/hm-user/Mail/hm@example.com/Drafts
+realname=H. M. Test
+sendmail_command=
+sent_box=maildir:///home/hm-user/Mail/hm@example.com/Sent
+auto_remove_unread = True
+ask_subject = False
+handle_mouse = True
+
+[[[abook]]]
diff --git a/home-manager/tests/modules/programs/alot/alot.nix b/home-manager/tests/modules/programs/alot/alot.nix
new file mode 100644
index 00000000000..40028b7aac6
--- /dev/null
+++ b/home-manager/tests/modules/programs/alot/alot.nix
@@ -0,0 +1,36 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ imports = [ ../../accounts/email-test-accounts.nix ];
+
+ config = {
+ accounts.email.accounts = {
+ "hm@example.com" = {
+ primary = true;
+ notmuch.enable = true;
+ alot = {
+ contactCompletion = { };
+ extraConfig = ''
+ auto_remove_unread = True
+ ask_subject = False
+ handle_mouse = True
+ '';
+ };
+ imap.port = 993;
+ };
+ };
+
+ programs.alot = { enable = true; };
+
+ nixpkgs.overlays =
+ [ (self: super: { alot = pkgs.writeScriptBin "dummy-alot" ""; }) ];
+
+ nmt.script = ''
+ assertFileExists home-files/.config/alot/config
+ assertFileContent home-files/.config/alot/config ${./alot-expected.conf}
+ '';
+ };
+}
+
diff --git a/home-manager/tests/modules/programs/alot/default.nix b/home-manager/tests/modules/programs/alot/default.nix
new file mode 100644
index 00000000000..9c912fdb43a
--- /dev/null
+++ b/home-manager/tests/modules/programs/alot/default.nix
@@ -0,0 +1 @@
+{ alot = ./alot.nix; }
diff --git a/home-manager/tests/modules/programs/aria2/default.nix b/home-manager/tests/modules/programs/aria2/default.nix
new file mode 100644
index 00000000000..2964841d098
--- /dev/null
+++ b/home-manager/tests/modules/programs/aria2/default.nix
@@ -0,0 +1 @@
+{ aria2-settings = ./settings.nix; }
diff --git a/home-manager/tests/modules/programs/aria2/settings.nix b/home-manager/tests/modules/programs/aria2/settings.nix
new file mode 100644
index 00000000000..0b5a52d90c5
--- /dev/null
+++ b/home-manager/tests/modules/programs/aria2/settings.nix
@@ -0,0 +1,41 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.aria2 = {
+ enable = true;
+
+ settings = {
+ listen-port = 60000;
+ dht-listen-port = 60000;
+ seed-ratio = 1.0;
+ max-upload-limit = "50K";
+ ftp-pasv = true;
+ };
+
+ extraConfig = ''
+ # Extra aria2 configuration.
+ '';
+ };
+
+ nixpkgs.overlays =
+ [ (self: super: { aria2 = pkgs.writeScriptBin "dummy-aria2" ""; }) ];
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/.config/aria2/aria2.conf \
+ ${
+ pkgs.writeText "aria2-expected-config.conf" ''
+ dht-listen-port=60000
+ ftp-pasv=true
+ listen-port=60000
+ max-upload-limit=50K
+ seed-ratio=1.000000
+ # Extra aria2 configuration.
+ ''
+ }
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/autorandr/basic-configuration.conf b/home-manager/tests/modules/programs/autorandr/basic-configuration.conf
new file mode 100644
index 00000000000..681574cf204
--- /dev/null
+++ b/home-manager/tests/modules/programs/autorandr/basic-configuration.conf
@@ -0,0 +1,10 @@
+output DP1
+off
+
+output DP2
+pos 0x0
+crtc 0
+primary
+mode 1920x1080
+transform 0.600000,0.000000,0.000000,0.000000,0.600000,0.000000,0.000000,0.000000,1.000000
+scale 2x4 \ No newline at end of file
diff --git a/home-manager/tests/modules/programs/autorandr/basic-configuration.nix b/home-manager/tests/modules/programs/autorandr/basic-configuration.nix
new file mode 100644
index 00000000000..190511016fe
--- /dev/null
+++ b/home-manager/tests/modules/programs/autorandr/basic-configuration.nix
@@ -0,0 +1,48 @@
+{ config, pkgs, ... }:
+
+{
+ config = {
+ programs.autorandr = {
+ enable = true;
+ profiles = {
+ default = {
+ fingerprint = {
+ DP1 = "XXX";
+ DP2 = "YYY";
+ };
+ config = {
+ DP1.enable = false;
+ DP2 = {
+ crtc = 0;
+ primary = true;
+ position = "0x0";
+ mode = "1920x1080";
+ scale = {
+ x = 2;
+ y = 4;
+ };
+ transform = [
+ [ 0.6 0.0 0.0 ] # a b c
+ [ 0.0 0.6 0.0 ] # d e f
+ [ 0.0 0.0 1.0 ] # g h i
+ ];
+ };
+ };
+ };
+ };
+ };
+
+ nmt.script = ''
+ config=home-files/.config/autorandr/default/config
+ setup=home-files/.config/autorandr/default/setup
+
+ assertFileExists $setup
+ assertFileRegex $setup 'DP1 XXX'
+ assertFileRegex $setup 'DP2 YYY'
+
+ assertFileExists $config
+ assertFileContent $config \
+ ${./basic-configuration.conf}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/autorandr/default.nix b/home-manager/tests/modules/programs/autorandr/default.nix
new file mode 100644
index 00000000000..5f12d409380
--- /dev/null
+++ b/home-manager/tests/modules/programs/autorandr/default.nix
@@ -0,0 +1 @@
+{ autorandr-basic-configuration = ./basic-configuration.nix; }
diff --git a/home-manager/tests/modules/programs/bash/default.nix b/home-manager/tests/modules/programs/bash/default.nix
new file mode 100644
index 00000000000..e9f431cd2b9
--- /dev/null
+++ b/home-manager/tests/modules/programs/bash/default.nix
@@ -0,0 +1,4 @@
+{
+ bash-logout = ./logout.nix;
+ bash-session-variables = ./session-variables.nix;
+}
diff --git a/home-manager/tests/modules/programs/bash/logout-expected.txt b/home-manager/tests/modules/programs/bash/logout-expected.txt
new file mode 100644
index 00000000000..9462f58f732
--- /dev/null
+++ b/home-manager/tests/modules/programs/bash/logout-expected.txt
@@ -0,0 +1,4 @@
+# -*- mode: sh -*-
+
+clear-console
+
diff --git a/home-manager/tests/modules/programs/bash/logout.nix b/home-manager/tests/modules/programs/bash/logout.nix
new file mode 100644
index 00000000000..8f96dc7e1ae
--- /dev/null
+++ b/home-manager/tests/modules/programs/bash/logout.nix
@@ -0,0 +1,22 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.bash = {
+ enable = true;
+
+ logoutExtra = ''
+ clear-console
+ '';
+ };
+
+ nmt.script = ''
+ assertFileExists home-files/.bash_logout
+ assertFileContent \
+ home-files/.bash_logout \
+ ${./logout-expected.txt}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/bash/session-variables-expected.txt b/home-manager/tests/modules/programs/bash/session-variables-expected.txt
new file mode 100644
index 00000000000..0d93217a915
--- /dev/null
+++ b/home-manager/tests/modules/programs/bash/session-variables-expected.txt
@@ -0,0 +1,8 @@
+# -*- mode: sh -*-
+
+. "/home/hm-user/.nix-profile/etc/profile.d/hm-session-vars.sh"
+
+export V1="v1"
+export V2="v2-v1"
+
+
diff --git a/home-manager/tests/modules/programs/bash/session-variables.nix b/home-manager/tests/modules/programs/bash/session-variables.nix
new file mode 100644
index 00000000000..1ef65a34442
--- /dev/null
+++ b/home-manager/tests/modules/programs/bash/session-variables.nix
@@ -0,0 +1,23 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.bash = {
+ enable = true;
+
+ sessionVariables = {
+ V1 = "v1";
+ V2 = "v2-${config.programs.bash.sessionVariables.V1}";
+ };
+ };
+
+ nmt.script = ''
+ assertFileExists home-files/.profile
+ assertFileContent \
+ home-files/.profile \
+ ${./session-variables-expected.txt}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/browserpass/browserpass.nix b/home-manager/tests/modules/programs/browserpass/browserpass.nix
new file mode 100644
index 00000000000..9189a445ac0
--- /dev/null
+++ b/home-manager/tests/modules/programs/browserpass/browserpass.nix
@@ -0,0 +1,29 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.browserpass = {
+ enable = true;
+ browsers = [ "chrome" "chromium" "firefox" "vivaldi" ];
+ };
+
+ nmt.script = if pkgs.stdenv.hostPlatform.isDarwin then ''
+ for dir in "Google/Chrome" "Chromium" "Mozilla" "Vivaldi"; do
+ assertFileExists "home-files/Library/Application Support/$dir/NativeMessagingHosts/com.github.browserpass.native.json"
+ done
+
+ for dir in "Google/Chrome" "Chromium" "Vivaldi"; do
+ assertFileExists "home-files/Library/Application Support/$dir/policies/managed/com.github.browserpass.native.json"
+ done
+ '' else ''
+ for dir in "google-chrome" "chromium" "vivaldi"; do
+ assertFileExists "home-files/.config/$dir/NativeMessagingHosts/com.github.browserpass.native.json"
+ assertFileExists "home-files/.config/$dir/policies/managed/com.github.browserpass.native.json"
+ done
+
+ assertFileExists "home-files/.mozilla/native-messaging-hosts/com.github.browserpass.native.json"
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/browserpass/default.nix b/home-manager/tests/modules/programs/browserpass/default.nix
new file mode 100644
index 00000000000..fa40ddcab31
--- /dev/null
+++ b/home-manager/tests/modules/programs/browserpass/default.nix
@@ -0,0 +1 @@
+{ browserpass = ./browserpass.nix; }
diff --git a/home-manager/tests/modules/programs/dircolors/default.nix b/home-manager/tests/modules/programs/dircolors/default.nix
new file mode 100644
index 00000000000..a82e2b859af
--- /dev/null
+++ b/home-manager/tests/modules/programs/dircolors/default.nix
@@ -0,0 +1 @@
+{ dircolors-settings = ./settings.nix; }
diff --git a/home-manager/tests/modules/programs/dircolors/settings-expected.conf b/home-manager/tests/modules/programs/dircolors/settings-expected.conf
new file mode 100644
index 00000000000..17bc247c0c2
--- /dev/null
+++ b/home-manager/tests/modules/programs/dircolors/settings-expected.conf
@@ -0,0 +1,133 @@
+# Extra dircolors configuration.
+
+.7z 01;31
+.aac 00;36
+.ace 01;31
+.alz 01;31
+.arc 01;31
+.arj 01;31
+.asf 01;35
+.au 00;36
+.avi 01;35
+.bmp 01;35
+.bz 01;31
+.bz2 01;31
+.cab 01;31
+.cgm 01;35
+.cpio 01;31
+.csh 01;32
+.deb 01;31
+.dl 01;35
+.dwm 01;31
+.dz 01;31
+.ear 01;31
+.emf 01;35
+.esd 01;31
+.flac 00;36
+.flc 01;35
+.fli 01;35
+.flv 01;35
+.gif 01;35
+.gl 01;35
+.gz 01;31
+.jar 01;31
+.jpeg 01;35
+.jpg 01;35
+.lha 01;31
+.lrz 01;31
+.lz 01;31
+.lz4 01;31
+.lzh 01;31
+.lzma 01;31
+.lzo 01;31
+.m2v 01;35
+.m4a 00;36
+.m4v 01;35
+.mid 00;36
+.midi 00;36
+.mjpeg 01;35
+.mjpg 01;35
+.mka 00;36
+.mkv 01;35
+.mng 01;35
+.mov 01;35
+.mp3 00;36
+.mp4 01;35
+.mp4v 01;35
+.mpc 00;36
+.mpeg 01;35
+.mpg 01;35
+.nuv 01;35
+.oga 00;36
+.ogg 00;36
+.ogm 01;35
+.ogv 01;35
+.ogx 01;35
+.opus 00;36
+.pbm 01;35
+.pcx 01;35
+.pgm 01;35
+.png 01;35
+.ppm 01;35
+.qt 01;35
+.ra 00;36
+.rar 01;31
+.rm 01;35
+.rmvb 01;35
+.rpm 01;31
+.rz 01;31
+.sar 01;31
+.sh 01;32
+.spx 00;36
+.svg 01;35
+.svgz 01;35
+.swm 01;31
+.t7z 01;31
+.tar 01;31
+.taz 01;31
+.tbz 01;31
+.tbz2 01;31
+.tga 01;35
+.tgz 01;31
+.tif 01;35
+.tiff 01;35
+.tlz 01;31
+.txz 01;31
+.tz 01;31
+.tzo 01;31
+.tzst 01;31
+.vob 01;35
+.war 01;31
+.wav 00;36
+.webm 01;35
+.wim 01;31
+.wmv 01;35
+.xbm 01;35
+.xcf 01;35
+.xpm 01;35
+.xspf 00;36
+.xwd 01;35
+.xz 01;31
+.yuv 01;35
+.z 01;31
+.zip 01;31
+.zoo 01;31
+.zst 01;31
+BLK 40;33;01
+CAPABILITY 30;41
+CHR 40;33;01
+DIR 01;34
+DOOR 01;35
+EXEC 01;32
+FIFO 40;33
+LINK 01;36
+MISSING 00
+MULTIHARDLINK 00
+ORPHAN 40;31;01
+OTHER_WRITABLE 30;46
+RESET 0
+SETGID 30;43
+SETUID 37;41
+SOCK 01;35
+STICKY 37;44
+STICKY_OTHER_WRITABLE 30;42
diff --git a/home-manager/tests/modules/programs/dircolors/settings.nix b/home-manager/tests/modules/programs/dircolors/settings.nix
new file mode 100644
index 00000000000..9ca676ef9c0
--- /dev/null
+++ b/home-manager/tests/modules/programs/dircolors/settings.nix
@@ -0,0 +1,27 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.dircolors = {
+ enable = true;
+
+ settings = {
+ OTHER_WRITABLE = "30;46";
+ ".sh" = "01;32";
+ ".csh" = "01;32";
+ };
+
+ extraConfig = ''
+ # Extra dircolors configuration.
+ '';
+ };
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/.dir_colors \
+ ${./settings-expected.conf}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/direnv/bash.nix b/home-manager/tests/modules/programs/direnv/bash.nix
new file mode 100644
index 00000000000..db0d6b391f5
--- /dev/null
+++ b/home-manager/tests/modules/programs/direnv/bash.nix
@@ -0,0 +1,17 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.bash.enable = true;
+ programs.direnv.enable = true;
+
+ nmt.script = ''
+ assertFileExists home-files/.bashrc
+ assertFileRegex \
+ home-files/.bashrc \
+ 'eval "\$(/nix/store/.*direnv.*/bin/direnv hook bash)"'
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/direnv/default.nix b/home-manager/tests/modules/programs/direnv/default.nix
new file mode 100644
index 00000000000..3efad2b6945
--- /dev/null
+++ b/home-manager/tests/modules/programs/direnv/default.nix
@@ -0,0 +1,6 @@
+{
+ direnv-bash = ./bash.nix;
+ direnv-nix-direnv = ./nix-direnv.nix;
+ direnv-stdlib = ./stdlib.nix;
+ direnv-stdlib-and-nix-direnv = ./stdlib-and-nix-direnv.nix;
+}
diff --git a/home-manager/tests/modules/programs/direnv/nix-direnv.nix b/home-manager/tests/modules/programs/direnv/nix-direnv.nix
new file mode 100644
index 00000000000..57b3907dda8
--- /dev/null
+++ b/home-manager/tests/modules/programs/direnv/nix-direnv.nix
@@ -0,0 +1,18 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.bash.enable = true;
+ programs.direnv.enable = true;
+ programs.direnv.enableNixDirenvIntegration = true;
+
+ nmt.script = ''
+ assertFileExists home-files/.bashrc
+ assertFileRegex \
+ home-files/.config/direnv/direnvrc \
+ 'source /nix/store/.*nix-direnv.*/share/nix-direnv/direnvrc'
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/direnv/stdlib-and-nix-direnv.nix b/home-manager/tests/modules/programs/direnv/stdlib-and-nix-direnv.nix
new file mode 100644
index 00000000000..1dc224317a2
--- /dev/null
+++ b/home-manager/tests/modules/programs/direnv/stdlib-and-nix-direnv.nix
@@ -0,0 +1,23 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let expectedContent = "something important";
+in {
+ config = {
+ programs.bash.enable = true;
+ programs.direnv.enable = true;
+ programs.direnv.enableNixDirenvIntegration = true;
+ programs.direnv.stdlib = expectedContent;
+
+ nmt.script = ''
+ assertFileExists home-files/.bashrc
+ assertFileRegex \
+ home-files/.config/direnv/direnvrc \
+ 'source /nix/store/.*nix-direnv.*/share/nix-direnv/direnvrc'
+ assertFileRegex \
+ home-files/.config/direnv/direnvrc \
+ '${expectedContent}'
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/direnv/stdlib.nix b/home-manager/tests/modules/programs/direnv/stdlib.nix
new file mode 100644
index 00000000000..1d06a0bc2a9
--- /dev/null
+++ b/home-manager/tests/modules/programs/direnv/stdlib.nix
@@ -0,0 +1,19 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let expectedContent = "something important";
+in {
+ config = {
+ programs.bash.enable = true;
+ programs.direnv.enable = true;
+ programs.direnv.stdlib = expectedContent;
+
+ nmt.script = ''
+ assertFileExists home-files/.bashrc
+ assertFileRegex \
+ home-files/.config/direnv/direnvrc \
+ '${expectedContent}'
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/firefox/default.nix b/home-manager/tests/modules/programs/firefox/default.nix
new file mode 100644
index 00000000000..6612a9ac978
--- /dev/null
+++ b/home-manager/tests/modules/programs/firefox/default.nix
@@ -0,0 +1,4 @@
+{
+ firefox-profile-settings = ./profile-settings.nix;
+ firefox-state-version-19_09 = ./state-version-19_09.nix;
+}
diff --git a/home-manager/tests/modules/programs/firefox/profile-settings-expected-user.js b/home-manager/tests/modules/programs/firefox/profile-settings-expected-user.js
new file mode 100644
index 00000000000..0edd47b9101
--- /dev/null
+++ b/home-manager/tests/modules/programs/firefox/profile-settings-expected-user.js
@@ -0,0 +1,6 @@
+// Generated by Home Manager.
+
+user_pref("general.smoothScroll", false);
+
+
+
diff --git a/home-manager/tests/modules/programs/firefox/profile-settings.nix b/home-manager/tests/modules/programs/firefox/profile-settings.nix
new file mode 100644
index 00000000000..8c5fb4ec1fc
--- /dev/null
+++ b/home-manager/tests/modules/programs/firefox/profile-settings.nix
@@ -0,0 +1,36 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.firefox = {
+ enable = true;
+ profiles.test.settings = { "general.smoothScroll" = false; };
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ firefox-unwrapped = pkgs.runCommand "firefox-0" {
+ meta.description = "I pretend to be Firefox";
+ preferLocalBuild = true;
+ allowSubstitutes = false;
+ } ''
+ mkdir -p "$out/bin"
+ touch "$out/bin/firefox"
+ chmod 755 "$out/bin/firefox"
+ '';
+ })
+ ];
+
+ nmt.script = ''
+ assertFileRegex \
+ home-path/bin/firefox \
+ MOZ_APP_LAUNCHER
+
+ assertFileContent \
+ home-files/.mozilla/firefox/test/user.js \
+ ${./profile-settings-expected-user.js}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/firefox/state-version-19_09.nix b/home-manager/tests/modules/programs/firefox/state-version-19_09.nix
new file mode 100644
index 00000000000..27dc867ad29
--- /dev/null
+++ b/home-manager/tests/modules/programs/firefox/state-version-19_09.nix
@@ -0,0 +1,31 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ home.stateVersion = "19.09";
+
+ programs.firefox.enable = true;
+
+ nixpkgs.overlays = [
+ (self: super: {
+ firefox-unwrapped = pkgs.runCommand "firefox-0" {
+ meta.description = "I pretend to be Firefox";
+ preferLocalBuild = true;
+ allowSubstitutes = false;
+ } ''
+ mkdir -p "$out/bin"
+ touch "$out/bin/firefox"
+ chmod 755 "$out/bin/firefox"
+ '';
+ })
+ ];
+
+ nmt.script = ''
+ assertFileRegex \
+ home-path/bin/firefox \
+ MOZ_APP_LAUNCHER
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/fish/default.nix b/home-manager/tests/modules/programs/fish/default.nix
new file mode 100644
index 00000000000..99fe8136700
--- /dev/null
+++ b/home-manager/tests/modules/programs/fish/default.nix
@@ -0,0 +1,5 @@
+{
+ fish-functions = ./functions.nix;
+ fish-no-functions = ./no-functions.nix;
+ fish-plugins = ./plugins.nix;
+}
diff --git a/home-manager/tests/modules/programs/fish/functions.nix b/home-manager/tests/modules/programs/fish/functions.nix
new file mode 100644
index 00000000000..424d0a288c7
--- /dev/null
+++ b/home-manager/tests/modules/programs/fish/functions.nix
@@ -0,0 +1,48 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+ func = pkgs.writeText "func.fish" ''
+ function func
+ echo "Hello"
+ end
+ '';
+
+ funcEvent = pkgs.writeText "func-event.fish" ''
+ function func-event --on-event="fish_command_not_found"
+ echo "Not found!"
+ end
+ '';
+
+in {
+ config = {
+ programs.fish = {
+ enable = true;
+
+ functions = {
+ func = ''echo "Hello"'';
+ func-event = {
+ body = ''echo "Not found!"'';
+ onEvent = "fish_command_not_found";
+ };
+ };
+ };
+
+ nmt = {
+ description =
+ "if fish.function is set, check file exists and contents match";
+ script = ''
+ assertFileExists home-files/.config/fish/functions/func.fish
+ echo ${func}
+ assertFileContent home-files/.config/fish/functions/func.fish ${func}
+
+ assertFileExists home-files/.config/fish/functions/func-event.fish
+ echo ${funcEvent}
+ assertFileContent home-files/.config/fish/functions/func-event.fish ${funcEvent}
+ '';
+
+ };
+ };
+}
diff --git a/home-manager/tests/modules/programs/fish/no-functions.nix b/home-manager/tests/modules/programs/fish/no-functions.nix
new file mode 100644
index 00000000000..c817b388953
--- /dev/null
+++ b/home-manager/tests/modules/programs/fish/no-functions.nix
@@ -0,0 +1,22 @@
+{ config, lib, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.fish = {
+ enable = true;
+
+ functions = { };
+ };
+
+ nmt = {
+ description =
+ "if fish.functions is blank, the functions folder should not exist.";
+ script = ''
+ assertPathNotExists home-files/.config/fish/functions
+ '';
+
+ };
+ };
+}
diff --git a/home-manager/tests/modules/programs/fish/plugins.nix b/home-manager/tests/modules/programs/fish/plugins.nix
new file mode 100644
index 00000000000..657c33f39bf
--- /dev/null
+++ b/home-manager/tests/modules/programs/fish/plugins.nix
@@ -0,0 +1,60 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+ fooPluginSrc = pkgs.writeText "fooPluginSrc" "";
+
+ generatedConfdFile = pkgs.writeText "plugin-foo.fish" ''
+ # Plugin foo
+ set -l plugin_dir ${fooPluginSrc}
+
+ # Set paths to import plugin components
+ if test -d $plugin_dir/functions
+ set fish_function_path $fish_function_path[1] $plugin_dir/functions $fish_function_path[2..-1]
+ end
+
+ if test -d $plugin_dir/completions
+ set fish_complete_path $fish_complete_path[1] $plugin_dir/completions $fish_complete_path[2..-1]
+ end
+
+ # Source initialization code if it exists.
+ if test -d $plugin_dir/conf.d
+ for f in $plugin_dir/conf.d/*.fish
+ source $f
+ end
+ end
+
+ if test -f $plugin_dir/key_bindings.fish
+ source $plugin_dir/key_bindings.fish
+ end
+
+ if test -f $plugin_dir/init.fish
+ source $plugin_dir/init.fish
+ end
+ '';
+
+in {
+ config = {
+ programs.fish = {
+ enable = true;
+
+ plugins = [{
+ name = "foo";
+ src = fooPluginSrc;
+ }];
+ };
+
+ nmt = {
+ description =
+ "if fish.plugins set, check conf.d file exists and contents match";
+ script = ''
+ assertDirectoryExists home-files/.config/fish/conf.d
+ assertFileExists home-files/.config/fish/conf.d/plugin-foo.fish
+ assertFileContent home-files/.config/fish/conf.d/plugin-foo.fish ${generatedConfdFile}
+ '';
+
+ };
+ };
+}
diff --git a/home-manager/tests/modules/programs/getmail/default.nix b/home-manager/tests/modules/programs/getmail/default.nix
new file mode 100644
index 00000000000..cb789a90d64
--- /dev/null
+++ b/home-manager/tests/modules/programs/getmail/default.nix
@@ -0,0 +1 @@
+{ getmail = ./getmail.nix; }
diff --git a/home-manager/tests/modules/programs/getmail/getmail-expected.conf b/home-manager/tests/modules/programs/getmail/getmail-expected.conf
new file mode 100644
index 00000000000..90dc963e574
--- /dev/null
+++ b/home-manager/tests/modules/programs/getmail/getmail-expected.conf
@@ -0,0 +1,16 @@
+# Generated by Home-Manager.
+[retriever]
+type = SimpleIMAPSSLRetriever
+server = imap.example.com
+port = 993
+username = home.manager
+password_command = ('password-command')
+mailboxes = ( 'INBOX', 'Sent', 'Work' )
+
+[destination]
+type = MDA_external
+path = /bin/maildrop
+
+[options]
+delete = false
+read_all = true
diff --git a/home-manager/tests/modules/programs/getmail/getmail.nix b/home-manager/tests/modules/programs/getmail/getmail.nix
new file mode 100644
index 00000000000..b0d979c4672
--- /dev/null
+++ b/home-manager/tests/modules/programs/getmail/getmail.nix
@@ -0,0 +1,28 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ imports = [ ../../accounts/email-test-accounts.nix ];
+
+ config = {
+ accounts.email.accounts = {
+ "hm@example.com" = {
+ getmail = {
+ enable = true;
+ mailboxes = [ "INBOX" "Sent" "Work" ];
+ destinationCommand = "/bin/maildrop";
+ delete = false;
+ };
+ imap.port = 993;
+ };
+ };
+
+ nmt.script = ''
+ assertFileExists home-files/.getmail/getmailhm@example.com
+ assertFileContent home-files/.getmail/getmailhm@example.com ${
+ ./getmail-expected.conf
+ }
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/git/default.nix b/home-manager/tests/modules/programs/git/default.nix
new file mode 100644
index 00000000000..45aface8d26
--- /dev/null
+++ b/home-manager/tests/modules/programs/git/default.nix
@@ -0,0 +1,5 @@
+{
+ git-with-email = ./git-with-email.nix;
+ git-with-most-options = ./git.nix;
+ git-with-str-extra-config = ./git-with-str-extra-config.nix;
+}
diff --git a/home-manager/tests/modules/programs/git/git-expected-include.conf b/home-manager/tests/modules/programs/git/git-expected-include.conf
new file mode 100644
index 00000000000..f05c7b6c7fc
--- /dev/null
+++ b/home-manager/tests/modules/programs/git/git-expected-include.conf
@@ -0,0 +1,3 @@
+[user]
+ email = "user@example.org"
+ name = "John Doe"
diff --git a/home-manager/tests/modules/programs/git/git-expected.conf b/home-manager/tests/modules/programs/git/git-expected.conf
new file mode 100644
index 00000000000..c3e534af058
--- /dev/null
+++ b/home-manager/tests/modules/programs/git/git-expected.conf
@@ -0,0 +1,58 @@
+[alias]
+ a1 = "foo"
+ a2 = "baz"
+ escapes = "\"\\n\t"
+
+[commit]
+ gpgSign = true
+
+[core]
+ pager = "@deltaCommand@"
+
+[delta]
+ features = "decorations"
+ whitespace-error-style = "22 reverse"
+
+[delta "decorations"]
+ commit-decoration-style = "bold yellow box ul"
+ file-decoration-style = "none"
+ file-style = "bold yellow ul"
+
+[extra]
+ boolean = true
+ integer = 38
+ multiple = 1
+ multiple = 2
+ name = "value"
+
+[extra "backcompat.with.dots"]
+ previously = "worked"
+
+[extra "subsection"]
+ value = "test"
+
+[filter "lfs"]
+ clean = "git-lfs clean -- %f"
+ process = "git-lfs filter-process"
+ required = true
+ smudge = "git-lfs smudge -- %f"
+
+[gpg]
+ program = "path-to-gpg"
+
+[interactive]
+ diffFilter = "@deltaCommand@ --color-only"
+
+[user]
+ email = "user@example.org"
+ name = "John Doe"
+ signingKey = "00112233445566778899AABBCCDDEEFF"
+
+[include]
+ path = "~/path/to/config.inc"
+
+[includeIf "gitdir:~/src/dir"]
+ path = "~/path/to/conditional.inc"
+
+[includeIf "gitdir:~/src/dir"]
+ path = "@git_include_path@"
diff --git a/home-manager/tests/modules/programs/git/git-with-email-expected.conf b/home-manager/tests/modules/programs/git/git-with-email-expected.conf
new file mode 100644
index 00000000000..f48b7c33334
--- /dev/null
+++ b/home-manager/tests/modules/programs/git/git-with-email-expected.conf
@@ -0,0 +1,15 @@
+[sendemail "hm-account"]
+ from = "hm@example.org"
+ smtpEncryption = "tls"
+ smtpServer = "smtp.example.org"
+ smtpUser = "home.manager.jr"
+
+[sendemail "hm@example.com"]
+ from = "hm@example.com"
+ smtpEncryption = "ssl"
+ smtpServer = "smtp.example.com"
+ smtpUser = "home.manager"
+
+[user]
+ email = "hm@example.com"
+ name = "H. M. Test"
diff --git a/home-manager/tests/modules/programs/git/git-with-email.nix b/home-manager/tests/modules/programs/git/git-with-email.nix
new file mode 100644
index 00000000000..d7ed7e185de
--- /dev/null
+++ b/home-manager/tests/modules/programs/git/git-with-email.nix
@@ -0,0 +1,38 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ imports = [ ../../accounts/email-test-accounts.nix ];
+
+ config = {
+ programs.git = {
+ enable = true;
+ package = pkgs.gitMinimal;
+ userEmail = "hm@example.com";
+ userName = "H. M. Test";
+ };
+
+ home.stateVersion = "20.09";
+
+ nmt.script = ''
+ function assertGitConfig() {
+ local value
+ value=$(${pkgs.git}/bin/git config \
+ --file $TESTED/home-files/.config/git/config \
+ --get $1)
+ if [[ $value != $2 ]]; then
+ fail "Expected option '$1' to have value '$2' but it was '$value'"
+ fi
+ }
+
+ assertFileExists home-files/.config/git/config
+ assertFileContent home-files/.config/git/config ${
+ ./git-with-email-expected.conf
+ }
+
+ assertGitConfig "sendemail.hm@example.com.from" "hm@example.com"
+ assertGitConfig "sendemail.hm-account.from" "hm@example.org"
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/git/git-with-str-extra-config-expected.conf b/home-manager/tests/modules/programs/git/git-with-str-extra-config-expected.conf
new file mode 100644
index 00000000000..071268e831c
--- /dev/null
+++ b/home-manager/tests/modules/programs/git/git-with-str-extra-config-expected.conf
@@ -0,0 +1,5 @@
+This can be anything.
+
+[user]
+ email = "user@example.org"
+ name = "John Doe"
diff --git a/home-manager/tests/modules/programs/git/git-with-str-extra-config.nix b/home-manager/tests/modules/programs/git/git-with-str-extra-config.nix
new file mode 100644
index 00000000000..3dbc497a5ea
--- /dev/null
+++ b/home-manager/tests/modules/programs/git/git-with-str-extra-config.nix
@@ -0,0 +1,23 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.git = {
+ enable = true;
+ package = pkgs.gitMinimal;
+ extraConfig = ''
+ This can be anything.
+ '';
+ userEmail = "user@example.org";
+ userName = "John Doe";
+ };
+
+ nmt.script = ''
+ assertFileExists home-files/.config/git/config
+ assertFileContent home-files/.config/git/config \
+ ${./git-with-str-extra-config-expected.conf}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/git/git.nix b/home-manager/tests/modules/programs/git/git.nix
new file mode 100644
index 00000000000..feefff54b61
--- /dev/null
+++ b/home-manager/tests/modules/programs/git/git.nix
@@ -0,0 +1,92 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+ gitInclude = {
+ user = {
+ name = "John Doe";
+ email = "user@example.org";
+ };
+ };
+
+ substituteExpected = path:
+ pkgs.substituteAll {
+ src = path;
+
+ deltaCommand = "${pkgs.gitAndTools.delta}/bin/delta";
+
+ git_include_path = pkgs.writeText "contents"
+ (builtins.readFile ./git-expected-include.conf);
+ };
+
+in {
+ config = {
+ programs.git = mkMerge [
+ {
+ enable = true;
+ package = pkgs.gitMinimal;
+ aliases = {
+ a1 = "foo";
+ a2 = "bar";
+ escapes = ''"\n '';
+ };
+ extraConfig = {
+ extra = {
+ name = "value";
+ multiple = [ 1 ];
+ };
+ };
+ ignores = [ "*~" "*.swp" ];
+ includes = [
+ { path = "~/path/to/config.inc"; }
+ {
+ path = "~/path/to/conditional.inc";
+ condition = "gitdir:~/src/dir";
+ }
+ {
+ condition = "gitdir:~/src/dir";
+ contents = gitInclude;
+ }
+ ];
+ signing = {
+ gpgPath = "path-to-gpg";
+ key = "00112233445566778899AABBCCDDEEFF";
+ signByDefault = true;
+ };
+ userEmail = "user@example.org";
+ userName = "John Doe";
+ lfs.enable = true;
+ delta = {
+ enable = true;
+ options = {
+ features = "decorations";
+ whitespace-error-style = "22 reverse";
+ decorations = {
+ commit-decoration-style = "bold yellow box ul";
+ file-style = "bold yellow ul";
+ file-decoration-style = "none";
+ };
+ };
+ };
+ }
+
+ {
+ aliases.a2 = mkForce "baz";
+ extraConfig."extra \"backcompat.with.dots\"".previously = "worked";
+ extraConfig.extra.boolean = true;
+ extraConfig.extra.integer = 38;
+ extraConfig.extra.multiple = [ 2 ];
+ extraConfig.extra.subsection.value = "test";
+ }
+ ];
+
+ nmt.script = ''
+ assertFileExists home-files/.config/git/config
+ assertFileContent home-files/.config/git/config ${
+ substituteExpected ./git-expected.conf
+ }
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/gpg/default.nix b/home-manager/tests/modules/programs/gpg/default.nix
new file mode 100644
index 00000000000..7fed2cdcc69
--- /dev/null
+++ b/home-manager/tests/modules/programs/gpg/default.nix
@@ -0,0 +1 @@
+{ gpg-override-defaults = ./override-defaults.nix; }
diff --git a/home-manager/tests/modules/programs/gpg/override-defaults-expected.conf b/home-manager/tests/modules/programs/gpg/override-defaults-expected.conf
new file mode 100644
index 00000000000..3198183f723
--- /dev/null
+++ b/home-manager/tests/modules/programs/gpg/override-defaults-expected.conf
@@ -0,0 +1,19 @@
+cert-digest-algo SHA512
+charset utf-8
+default-preference-list SHA512 SHA384 SHA256 AES256 AES192 AES ZLIB BZIP2 ZIP Uncompressed
+fixed-list-mode
+keyid-format 0xlong
+list-options show-uid-validity
+
+no-emit-version
+no-symkey-cache
+personal-cipher-preferences AES256 AES192 AES
+personal-compress-preferences ZLIB BZIP2 ZIP Uncompressed
+personal-digest-preferences SHA512 SHA384 SHA256
+require-cross-certification
+s2k-cipher-algo AES128
+s2k-digest-algo SHA512
+throw-keyids
+use-agent
+verify-options show-uid-validity
+with-fingerprint \ No newline at end of file
diff --git a/home-manager/tests/modules/programs/gpg/override-defaults.nix b/home-manager/tests/modules/programs/gpg/override-defaults.nix
new file mode 100644
index 00000000000..850334dc589
--- /dev/null
+++ b/home-manager/tests/modules/programs/gpg/override-defaults.nix
@@ -0,0 +1,22 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.gpg = {
+ enable = true;
+
+ settings = {
+ no-comments = false;
+ s2k-cipher-algo = "AES128";
+ throw-keyids = true;
+ };
+ };
+
+ nmt.script = ''
+ assertFileExists home-files/.gnupg/gpg.conf
+ assertFileContent home-files/.gnupg/gpg.conf ${./override-defaults-expected.conf}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/i3status/default.nix b/home-manager/tests/modules/programs/i3status/default.nix
new file mode 100644
index 00000000000..c8d55755861
--- /dev/null
+++ b/home-manager/tests/modules/programs/i3status/default.nix
@@ -0,0 +1,4 @@
+{
+ i3status-with-custom = ./with-custom.nix;
+ i3status-with-default = ./with-default.nix;
+}
diff --git a/home-manager/tests/modules/programs/i3status/with-custom.nix b/home-manager/tests/modules/programs/i3status/with-custom.nix
new file mode 100644
index 00000000000..4aa01773e4e
--- /dev/null
+++ b/home-manager/tests/modules/programs/i3status/with-custom.nix
@@ -0,0 +1,67 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.i3status = {
+ enable = true;
+ enableDefault = false;
+
+ general = {
+ colors = true;
+ color_good = "#e0e0e0";
+ color_degraded = "#d7ae00";
+ color_bad = "#f69d6a";
+ interval = 1;
+ };
+
+ modules = {
+ "volume master" = {
+ position = 1;
+ settings = {
+ format = "♪ %volume";
+ format_muted = "♪ muted (%volume)";
+ device = "pulse:1";
+ };
+ };
+ "disk /" = {
+ position = 2;
+ settings = { format = "/ %avail"; };
+ };
+ };
+ };
+
+ nixpkgs.overlays = [
+ (self: super: { i3status = pkgs.writeScriptBin "dummy-i3status" ""; })
+ ];
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/.config/i3status/config \
+ ${
+ pkgs.writeText "i3status-expected-config" ''
+ general {
+ color_bad = "#f69d6a"
+ color_degraded = "#d7ae00"
+ color_good = "#e0e0e0"
+ colors = true
+ interval = 1
+ }
+
+ order += "volume master"
+ order += "disk /"
+ disk / {
+ format = "/ %avail"
+ }
+
+ volume master {
+ device = "pulse:1"
+ format = "♪ %volume"
+ format_muted = "♪ muted (%volume)"
+ }
+ ''
+ }
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/i3status/with-default.nix b/home-manager/tests/modules/programs/i3status/with-default.nix
new file mode 100644
index 00000000000..0b7e4ee2fac
--- /dev/null
+++ b/home-manager/tests/modules/programs/i3status/with-default.nix
@@ -0,0 +1,73 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.i3status = {
+ enable = true;
+ enableDefault = true;
+ };
+
+ nixpkgs.overlays = [
+ (self: super: { i3status = pkgs.writeScriptBin "dummy-i3status" ""; })
+ ];
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/.config/i3status/config \
+ ${
+ pkgs.writeText "i3status-expected-config" ''
+ general {
+ colors = true
+ interval = 5
+ }
+
+ order += "ipv6"
+ order += "wireless _first_"
+ order += "ethernet _first_"
+ order += "battery all"
+ order += "disk /"
+ order += "load"
+ order += "memory"
+ order += "tztime local"
+ battery all {
+ format = "%status %percentage %remaining"
+ }
+
+ disk / {
+ format = "%avail"
+ }
+
+ ethernet _first_ {
+ format_down = "E: down"
+ format_up = "E: %ip (%speed)"
+ }
+
+ ipv6 {
+
+ }
+
+ load {
+ format = "%1min"
+ }
+
+ memory {
+ format = "%used | %available"
+ format_degraded = "MEMORY < %available"
+ threshold_degraded = "1G"
+ }
+
+ tztime local {
+ format = "%Y-%m-%d %H:%M:%S"
+ }
+
+ wireless _first_ {
+ format_down = "W: down"
+ format_up = "W: (%quality at %essid) %ip"
+ }
+ ''
+ }
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/kakoune/default.nix b/home-manager/tests/modules/programs/kakoune/default.nix
new file mode 100644
index 00000000000..1e6e077df1f
--- /dev/null
+++ b/home-manager/tests/modules/programs/kakoune/default.nix
@@ -0,0 +1,7 @@
+{
+ kakoune-no-plugins = ./no-plugins.nix;
+ kakoune-use-plugins = ./use-plugins.nix;
+ kakoune-whitespace-highlighter = ./whitespace-highlighter.nix;
+ kakoune-whitespace-highlighter-corner-cases =
+ ./whitespace-highlighter-corner-cases.nix;
+}
diff --git a/home-manager/tests/modules/programs/kakoune/no-plugins.nix b/home-manager/tests/modules/programs/kakoune/no-plugins.nix
new file mode 100644
index 00000000000..76dea5440ac
--- /dev/null
+++ b/home-manager/tests/modules/programs/kakoune/no-plugins.nix
@@ -0,0 +1,13 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.kakoune = { enable = true; };
+
+ nmt.script = ''
+ assertFileNotRegex home-path/share/kak/plugins.kak . # file is empty
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/kakoune/use-plugins.nix b/home-manager/tests/modules/programs/kakoune/use-plugins.nix
new file mode 100644
index 00000000000..7b23627dbbd
--- /dev/null
+++ b/home-manager/tests/modules/programs/kakoune/use-plugins.nix
@@ -0,0 +1,18 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.kakoune = {
+ enable = true;
+ plugins = [ pkgs.kakounePlugins.kak-powerline ];
+ };
+
+ nmt.script = let plugins_kak = "home-path/share/kak/plugins.kak";
+ in ''
+ assertFileRegex ${plugins_kak} \
+ '^source "/nix/store/.*-kak-powerline/share/kak/autoload/plugins/powerline/.*.kak"$'
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/kakoune/whitespace-highlighter-corner-cases.nix b/home-manager/tests/modules/programs/kakoune/whitespace-highlighter-corner-cases.nix
new file mode 100644
index 00000000000..142aaac8fe3
--- /dev/null
+++ b/home-manager/tests/modules/programs/kakoune/whitespace-highlighter-corner-cases.nix
@@ -0,0 +1,25 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.kakoune = {
+ enable = true;
+ config.showWhitespace = {
+ enable = true;
+ lineFeed = ''"'';
+ space = " ";
+ nonBreakingSpace = "' '"; # backwards compat
+ tab = "'";
+ # tabStop = <default>
+ };
+ };
+
+ nmt.script = ''
+ assertFileExists home-files/.config/kak/kakrc
+ assertFileContains home-files/.config/kak/kakrc \
+ "add-highlighter global/ show-whitespaces -tab \"'\" -spc ' ' -nbsp ' ' -lf '\"'"
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/kakoune/whitespace-highlighter.nix b/home-manager/tests/modules/programs/kakoune/whitespace-highlighter.nix
new file mode 100644
index 00000000000..514c26a118b
--- /dev/null
+++ b/home-manager/tests/modules/programs/kakoune/whitespace-highlighter.nix
@@ -0,0 +1,25 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.kakoune = {
+ enable = true;
+ config.showWhitespace = {
+ enable = true;
+ lineFeed = "1";
+ space = "2";
+ nonBreakingSpace = "3";
+ tab = "4";
+ tabStop = "5";
+ };
+ };
+
+ nmt.script = ''
+ assertFileExists home-files/.config/kak/kakrc
+ assertFileContains home-files/.config/kak/kakrc \
+ "add-highlighter global/ show-whitespaces -tab '4' -tabpad '5' -spc '2' -nbsp '3' -lf '1'"
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/lf/all-options.nix b/home-manager/tests/modules/programs/lf/all-options.nix
new file mode 100644
index 00000000000..a25467a26b7
--- /dev/null
+++ b/home-manager/tests/modules/programs/lf/all-options.nix
@@ -0,0 +1,86 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ pvScript = builtins.toFile "pv.sh" "cat $1";
+ expected = builtins.toFile "settings-expected" ''
+ set icons
+ set noignorecase
+ set ratios "2:2:3"
+ set tabstop 4
+
+ cmd added :echo "foo"
+ cmd multiline :{{
+ push gg
+ echo "bar"
+ push i
+ }}
+ cmd removed
+
+ map aa should-be-added
+ map ab
+
+ cmap <c-a> should-be-added
+ cmap <c-b>
+
+ set previewer ${pvScript}
+ map i ${"$"}${pvScript} "$f" | less -R
+
+
+
+ # More config...
+
+ '';
+in {
+ config = {
+ programs.lf = {
+ enable = true;
+
+ cmdKeybindings = {
+ "<c-a>" = "should-be-added";
+ "<c-b>" = null;
+ };
+
+ commands = {
+ added = '':echo "foo"'';
+ removed = null;
+ multiline = ''
+ :{{
+ push gg
+ echo "bar"
+ push i
+ }}'';
+ };
+
+ extraConfig = ''
+ # More config...
+ '';
+
+ keybindings = {
+ aa = "should-be-added";
+ ab = null;
+ };
+
+ previewer = {
+ keybinding = "i";
+ source = pvScript;
+ };
+
+ settings = {
+ ignorecase = false;
+ icons = true;
+ tabstop = 4;
+ ratios = "2:2:3";
+ };
+ };
+
+ nixpkgs.overlays =
+ [ (self: super: { lf = pkgs.writeScriptBin "dummy-lf" ""; }) ];
+
+ nmt.script = ''
+ assertFileExists home-files/.config/lf/lfrc
+ assertFileContent home-files/.config/lf/lfrc ${expected}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/lf/default.nix b/home-manager/tests/modules/programs/lf/default.nix
new file mode 100644
index 00000000000..65cf24fcf60
--- /dev/null
+++ b/home-manager/tests/modules/programs/lf/default.nix
@@ -0,0 +1,5 @@
+{
+ lf-all-options = ./all-options.nix;
+ lf-minimal-options = ./minimal-options.nix;
+ lf-no-pv-keybind = ./no-pv-keybind.nix;
+}
diff --git a/home-manager/tests/modules/programs/lf/minimal-options.nix b/home-manager/tests/modules/programs/lf/minimal-options.nix
new file mode 100644
index 00000000000..b3c26ba9b57
--- /dev/null
+++ b/home-manager/tests/modules/programs/lf/minimal-options.nix
@@ -0,0 +1,18 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let expected = builtins.toFile "settings-expected" "\n\n\n\n\n\n\n\n\n\n\n";
+in {
+ config = {
+ programs.lf = { enable = true; };
+
+ nixpkgs.overlays =
+ [ (self: super: { lf = pkgs.writeScriptBin "dummy-lf" ""; }) ];
+
+ nmt.script = ''
+ assertFileExists home-files/.config/lf/lfrc
+ assertFileContent home-files/.config/lf/lfrc ${expected}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/lf/no-pv-keybind.nix b/home-manager/tests/modules/programs/lf/no-pv-keybind.nix
new file mode 100644
index 00000000000..524a41a3643
--- /dev/null
+++ b/home-manager/tests/modules/programs/lf/no-pv-keybind.nix
@@ -0,0 +1,43 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ pvScript = builtins.toFile "pv.sh" "cat $1";
+ expected = builtins.toFile "settings-expected" ''
+
+
+
+
+
+
+
+
+ set previewer ${pvScript}
+
+
+
+ # More config...
+
+ '';
+in {
+ config = {
+ programs.lf = {
+ enable = true;
+
+ extraConfig = ''
+ # More config...
+ '';
+
+ previewer = { source = pvScript; };
+ };
+
+ nixpkgs.overlays =
+ [ (self: super: { lf = pkgs.writeScriptBin "dummy-lf" ""; }) ];
+
+ nmt.script = ''
+ assertFileExists home-files/.config/lf/lfrc
+ assertFileContent home-files/.config/lf/lfrc ${expected}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/lieer/default.nix b/home-manager/tests/modules/programs/lieer/default.nix
new file mode 100644
index 00000000000..16f8627cf0d
--- /dev/null
+++ b/home-manager/tests/modules/programs/lieer/default.nix
@@ -0,0 +1 @@
+{ lieer = ./lieer.nix; }
diff --git a/home-manager/tests/modules/programs/lieer/lieer-expected.json b/home-manager/tests/modules/programs/lieer/lieer-expected.json
new file mode 100644
index 00000000000..e7318f65dc3
--- /dev/null
+++ b/home-manager/tests/modules/programs/lieer/lieer-expected.json
@@ -0,0 +1 @@
+{"account":"hm@example.com","drop_non_existing_label":false,"ignore_remote_labels":["CATEGORY_FORUMS","CATEGORY_PROMOTIONS","CATEGORY_UPDATES","CATEGORY_SOCIAL","CATEGORY_PERSONAL"],"ignore_tags":[],"replace_slash_with_dot":false,"timeout":0}
diff --git a/home-manager/tests/modules/programs/lieer/lieer.nix b/home-manager/tests/modules/programs/lieer/lieer.nix
new file mode 100644
index 00000000000..2ce4fb4e031
--- /dev/null
+++ b/home-manager/tests/modules/programs/lieer/lieer.nix
@@ -0,0 +1,23 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ imports = [ ../../accounts/email-test-accounts.nix ];
+
+ config = {
+ programs.lieer.enable = true;
+
+ accounts.email.accounts = { "hm@example.com".lieer.enable = true; };
+
+ nixpkgs.overlays = [
+ (self: super: { gmailieer = pkgs.writeScriptBin "dummy-gmailieer" ""; })
+ ];
+
+ nmt.script = ''
+ assertFileExists home-files/Mail/hm@example.com/.gmailieer.json
+ assertFileContent home-files/Mail/hm@example.com/.gmailieer.json \
+ ${./lieer-expected.json}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/man/apropos.nix b/home-manager/tests/modules/programs/man/apropos.nix
new file mode 100644
index 00000000000..a8ec35ead92
--- /dev/null
+++ b/home-manager/tests/modules/programs/man/apropos.nix
@@ -0,0 +1,22 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.man = {
+ enable = true;
+ generateCaches = true;
+ };
+
+ nmt.script = ''
+ assertFileExists home-files/.manpath
+
+ CACHE_DIR=$(cat $TESTED/home-files/.manpath | cut --delimiter=' ' --fields=3)
+
+ if [[ ! -f "$CACHE_DIR/index.bt" ]]; then
+ fail "Expected man cache files to exist (in $CACHE_DIR) but they were not found."
+ fi
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/man/default.nix b/home-manager/tests/modules/programs/man/default.nix
new file mode 100644
index 00000000000..2e9d340f98d
--- /dev/null
+++ b/home-manager/tests/modules/programs/man/default.nix
@@ -0,0 +1,4 @@
+{
+ man-apropos = ./apropos.nix;
+ man-no-manpath = ./no-manpath.nix;
+}
diff --git a/home-manager/tests/modules/programs/man/no-manpath.nix b/home-manager/tests/modules/programs/man/no-manpath.nix
new file mode 100644
index 00000000000..1b8cfb40c6e
--- /dev/null
+++ b/home-manager/tests/modules/programs/man/no-manpath.nix
@@ -0,0 +1,13 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.man = { enable = true; };
+
+ nmt.script = ''
+ assertPathNotExists home-files/.manpath
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/mbsync/default.nix b/home-manager/tests/modules/programs/mbsync/default.nix
new file mode 100644
index 00000000000..9c369fa5018
--- /dev/null
+++ b/home-manager/tests/modules/programs/mbsync/default.nix
@@ -0,0 +1 @@
+{ mbsync = ./mbsync.nix; }
diff --git a/home-manager/tests/modules/programs/mbsync/mbsync-expected.conf b/home-manager/tests/modules/programs/mbsync/mbsync-expected.conf
new file mode 100644
index 00000000000..f1ca79fe738
--- /dev/null
+++ b/home-manager/tests/modules/programs/mbsync/mbsync-expected.conf
@@ -0,0 +1,55 @@
+# Generated by Home Manager.
+
+IMAPAccount hm-account
+CertificateFile /etc/ssl/certs/ca-certificates.crt
+Host imap.example.org
+PassCmd "password-command 2"
+SSLType IMAPS
+User home.manager.jr
+
+IMAPStore hm-account-remote
+Account hm-account
+
+MaildirStore hm-account-local
+Inbox /home/hm-user/Mail/hm-account/Inbox
+Path /home/hm-user/Mail/hm-account/
+SubFolders Verbatim
+
+Channel hm-account
+Create None
+Expunge None
+Master :hm-account-remote:
+Patterns *
+Remove None
+Slave :hm-account-local:
+SyncState *
+
+
+IMAPAccount hm@example.com
+CertificateFile /etc/ssl/certs/ca-certificates.crt
+Host imap.example.com
+PassCmd password-command
+SSLType IMAPS
+User home.manager
+
+IMAPStore hm@example.com-remote
+Account hm@example.com
+
+MaildirStore hm@example.com-local
+Inbox /home/hm-user/Mail/hm@example.com/Inbox
+Path /home/hm-user/Mail/hm@example.com/
+SubFolders Verbatim
+
+Channel hm@example.com
+Create None
+Expunge None
+Master :hm@example.com-remote:
+Patterns *
+Remove None
+Slave :hm@example.com-local:
+SyncState *
+
+
+Group inboxes
+Channel hm-account:Inbox
+Channel hm@example.com:Inbox1,Inbox2
diff --git a/home-manager/tests/modules/programs/mbsync/mbsync.nix b/home-manager/tests/modules/programs/mbsync/mbsync.nix
new file mode 100644
index 00000000000..fa8e28cb4a6
--- /dev/null
+++ b/home-manager/tests/modules/programs/mbsync/mbsync.nix
@@ -0,0 +1,28 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ imports = [ ../../accounts/email-test-accounts.nix ];
+
+ config = {
+ programs.mbsync = {
+ enable = true;
+ groups.inboxes = {
+ "hm@example.com" = [ "Inbox1" "Inbox2" ];
+ hm-account = [ "Inbox" ];
+ };
+ };
+
+ accounts.email.accounts = {
+ "hm@example.com".mbsync = { enable = true; };
+
+ hm-account.mbsync = { enable = true; };
+ };
+
+ nmt.script = ''
+ assertFileExists home-files/.mbsyncrc
+ assertFileContent home-files/.mbsyncrc ${./mbsync-expected.conf}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/ncmpcpp-linux/default.nix b/home-manager/tests/modules/programs/ncmpcpp-linux/default.nix
new file mode 100644
index 00000000000..b1185c85249
--- /dev/null
+++ b/home-manager/tests/modules/programs/ncmpcpp-linux/default.nix
@@ -0,0 +1 @@
+{ ncmpcpp-use-mpd-config = ./ncmpcpp-use-mpd-config.nix; }
diff --git a/home-manager/tests/modules/programs/ncmpcpp-linux/ncmpcpp-use-mpd-config-expected-config b/home-manager/tests/modules/programs/ncmpcpp-linux/ncmpcpp-use-mpd-config-expected-config
new file mode 100644
index 00000000000..8aa57d08f16
--- /dev/null
+++ b/home-manager/tests/modules/programs/ncmpcpp-linux/ncmpcpp-use-mpd-config-expected-config
@@ -0,0 +1 @@
+mpd_music_dir=/home/user/music
diff --git a/home-manager/tests/modules/programs/ncmpcpp-linux/ncmpcpp-use-mpd-config.nix b/home-manager/tests/modules/programs/ncmpcpp-linux/ncmpcpp-use-mpd-config.nix
new file mode 100644
index 00000000000..5262f031472
--- /dev/null
+++ b/home-manager/tests/modules/programs/ncmpcpp-linux/ncmpcpp-use-mpd-config.nix
@@ -0,0 +1,25 @@
+{ pkgs, ... }:
+
+{
+ config = {
+ programs.ncmpcpp.enable = true;
+
+ services.mpd.enable = true;
+ services.mpd.musicDirectory = "/home/user/music";
+
+ nixpkgs.overlays = [
+ (self: super: {
+ ncmpcpp = pkgs.writeScriptBin "dummy-ncmpcpp" "";
+ mpd = pkgs.writeScriptBin "dummy-mpd" "";
+ })
+ ];
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/.config/ncmpcpp/config \
+ ${./ncmpcpp-use-mpd-config-expected-config}
+
+ assertPathNotExists home-files/.config/ncmpcpp/bindings
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/ncmpcpp/default.nix b/home-manager/tests/modules/programs/ncmpcpp/default.nix
new file mode 100644
index 00000000000..c150b0d8248
--- /dev/null
+++ b/home-manager/tests/modules/programs/ncmpcpp/default.nix
@@ -0,0 +1,4 @@
+{
+ ncmpcpp-empty-settings = ./ncmpcpp-empty-settings.nix;
+ ncmpcpp-example-settings = ./ncmpcpp-example-settings.nix;
+}
diff --git a/home-manager/tests/modules/programs/ncmpcpp/ncmpcpp-empty-settings.nix b/home-manager/tests/modules/programs/ncmpcpp/ncmpcpp-empty-settings.nix
new file mode 100644
index 00000000000..e5134002d3e
--- /dev/null
+++ b/home-manager/tests/modules/programs/ncmpcpp/ncmpcpp-empty-settings.nix
@@ -0,0 +1,16 @@
+{ pkgs, ... }:
+
+{
+ config = {
+ programs.ncmpcpp.enable = true;
+
+ nixpkgs.overlays =
+ [ (self: super: { ncmpcpp = pkgs.writeScriptBin "dummy-ncmpcpp" ""; }) ];
+
+ nmt.script = ''
+ assertPathNotExists home-files/.config/ncmpcpp/config
+
+ assertPathNotExists home-files/.config/ncmpcpp/bindings
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings-expected-bindings b/home-manager/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings-expected-bindings
new file mode 100644
index 00000000000..a73bd129ffd
--- /dev/null
+++ b/home-manager/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings-expected-bindings
@@ -0,0 +1,16 @@
+def_key "j"
+ scroll_down
+def_key "k"
+ scroll_up
+def_key "J"
+ select_item
+ scroll_down
+def_key "K"
+ select_item
+ scroll_up
+def_key "x"
+ delete_playlist_items
+def_key "x"
+ delete_browser_items
+def_key "x"
+ delete_stored_playlist
diff --git a/home-manager/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings-expected-config b/home-manager/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings-expected-config
new file mode 100644
index 00000000000..6aedb6110e4
--- /dev/null
+++ b/home-manager/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings-expected-config
@@ -0,0 +1,4 @@
+display_volume_level=no
+mpd_music_dir=/home/user/music
+playlist_disable_highlight_delay=0
+user_interface=alternative
diff --git a/home-manager/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings.nix b/home-manager/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings.nix
new file mode 100644
index 00000000000..02a1f09c902
--- /dev/null
+++ b/home-manager/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings.nix
@@ -0,0 +1,60 @@
+{ pkgs, ... }:
+
+{
+ config = {
+ programs.ncmpcpp = {
+ enable = true;
+ mpdMusicDir = "/home/user/music";
+
+ settings = {
+ user_interface = "alternative";
+ display_volume_level = false;
+ playlist_disable_highlight_delay = 0;
+ };
+
+ bindings = [
+ {
+ key = "j";
+ command = "scroll_down";
+ }
+ {
+ key = "k";
+ command = "scroll_up";
+ }
+ {
+ key = "J";
+ command = [ "select_item" "scroll_down" ];
+ }
+ {
+ key = "K";
+ command = [ "select_item" "scroll_up" ];
+ }
+ {
+ key = "x";
+ command = "delete_playlist_items";
+ }
+ {
+ key = "x";
+ command = "delete_browser_items";
+ }
+ {
+ key = "x";
+ command = "delete_stored_playlist";
+ }
+ ];
+ };
+
+ nixpkgs.overlays =
+ [ (self: super: { ncmpcpp = pkgs.writeScriptBin "dummy-ncmpcpp" ""; }) ];
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/.config/ncmpcpp/config \
+ ${./ncmpcpp-example-settings-expected-config}
+
+ assertFileContent \
+ home-files/.config/ncmpcpp/bindings \
+ ${./ncmpcpp-example-settings-expected-bindings}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/ne/default.nix b/home-manager/tests/modules/programs/ne/default.nix
new file mode 100644
index 00000000000..7a1c843d432
--- /dev/null
+++ b/home-manager/tests/modules/programs/ne/default.nix
@@ -0,0 +1,4 @@
+{
+ ne-defprefs = ./defprefs.nix;
+ ne-passthroughs = ./passthroughs.nix;
+}
diff --git a/home-manager/tests/modules/programs/ne/defprefs.nix b/home-manager/tests/modules/programs/ne/defprefs.nix
new file mode 100644
index 00000000000..dce98b28648
--- /dev/null
+++ b/home-manager/tests/modules/programs/ne/defprefs.nix
@@ -0,0 +1,36 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ defpref = ''
+ defined through defaultPreferences
+ '';
+
+ autopref = ''
+ defined through automaticPreferences
+ '';
+
+in {
+ config = {
+ programs.ne = {
+ enable = true;
+ defaultPreferences = defpref;
+ automaticPreferences.".default" = autopref;
+ };
+
+ nixpkgs.overlays =
+ [ (self: super: { ne = pkgs.writeScriptBin "dummy-ne" ""; }) ];
+
+ nmt = {
+ description =
+ "Check that it gracefully handles the case of both defaultPreferences and automaticPreferences.'.default' being set, defaulting to the former.";
+ script = ''
+ assertFileExists home-files/.ne/.default#ap
+ assertFileContent home-files/.ne/.default#ap ${
+ builtins.toFile "defpref" defpref
+ }
+ '';
+ };
+ };
+}
diff --git a/home-manager/tests/modules/programs/ne/passthroughs.nix b/home-manager/tests/modules/programs/ne/passthroughs.nix
new file mode 100644
index 00000000000..4c129e94489
--- /dev/null
+++ b/home-manager/tests/modules/programs/ne/passthroughs.nix
@@ -0,0 +1,73 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+ # Samples taken from the ne manual.
+ keybindings = ''
+ SEQ "\x1b[1;5D" 14A
+ KEY 14A HELP
+ '';
+
+ menus = ''
+ MENU "File"
+ ITEM "Open... ^O" Open
+ ITEM "Close " Close
+ ITEM "DoIt " Macro DoIt
+ '';
+
+ virtualExtensions = ''
+ sh 1 ^#!\s*/.*\b(bash|sh|ksh|zsh)\s*
+ csh 1 ^#!\s*/.*\b(csh|tcsh)\s*
+ pl 1 ^#!\s*/.*\bperl\b
+ py 1 ^#!\s*/.*\bpython[0-9]*\s*
+ rb 1 ^#!\s*/.*\bruby\s*
+ xml 1 ^<\?xml
+ '';
+
+ automaticPreferences = {
+ nix = ''
+ TAB 0
+ TS 2
+ '';
+ js = ''
+ TS 4
+ '';
+ };
+
+ checkFile = filename: contents: ''
+ assertFileExists home-files/.ne/${filename}
+ assertFileContent home-files/.ne/${filename} ${
+ builtins.toFile "checkFile" contents
+ }
+ '';
+
+in {
+ config = {
+ programs.ne = {
+ enable = true;
+ inherit keybindings;
+ inherit menus;
+ inherit virtualExtensions;
+ inherit automaticPreferences;
+ };
+
+ nixpkgs.overlays =
+ [ (self: super: { ne = pkgs.writeScriptBin "dummy-ne" ""; }) ];
+
+ nmt = {
+ description = "Check that configuration files are correctly written";
+ script = concatStringsSep "\n" [
+ (checkFile ".keys" keybindings)
+ (checkFile ".extensions" virtualExtensions)
+ (checkFile ".menus" menus)
+
+ # Generates a check command for each entry in automaticPreferences.
+ (concatStringsSep "\n" (mapAttrsToList
+ (extension: contents: checkFile "${extension}#ap" contents)
+ automaticPreferences))
+ ];
+ };
+ };
+}
diff --git a/home-manager/tests/modules/programs/neomutt/default.nix b/home-manager/tests/modules/programs/neomutt/default.nix
new file mode 100644
index 00000000000..aef9f37e02c
--- /dev/null
+++ b/home-manager/tests/modules/programs/neomutt/default.nix
@@ -0,0 +1,4 @@
+{
+ neomutt-simple = ./neomutt.nix;
+ neomutt-with-msmtp = ./neomutt-with-msmtp.nix;
+}
diff --git a/home-manager/tests/modules/programs/neomutt/hm-example.com-expected b/home-manager/tests/modules/programs/neomutt/hm-example.com-expected
new file mode 100644
index 00000000000..430509c36bd
--- /dev/null
+++ b/home-manager/tests/modules/programs/neomutt/hm-example.com-expected
@@ -0,0 +1,37 @@
+# Generated by Home Manager.
+set ssl_force_tls = yes
+set certificate_file=/etc/ssl/certs/ca-certificates.crt
+
+# GPG section
+set crypt_use_gpgme = yes
+set crypt_autosign = no
+set pgp_use_gpg_agent = yes
+set mbox_type = Maildir
+set sort = "threads"
+
+# MTA section
+set smtp_pass='`password-command`'
+set smtp_url='smtps://home.manager@smtp.example.com'
+
+
+
+
+
+# MRA section
+set folder='/home/hm-user/Mail/hm@example.com'
+set from='hm@example.com'
+set postponed='+Drafts'
+set realname='H. M. Test'
+set record='+Sent'
+set spoolfile='+Inbox'
+set trash='+Trash'
+color status cyan default
+
+
+
+# Extra configuration
+color status cyan default
+
+# notmuch section
+set nm_default_uri = "notmuch:///home/hm-user/Mail"
+virtual-mailboxes "My INBOX" "notmuch://?query=tag:inbox"
diff --git a/home-manager/tests/modules/programs/neomutt/hm-example.com-msmtp-expected.conf b/home-manager/tests/modules/programs/neomutt/hm-example.com-msmtp-expected.conf
new file mode 100644
index 00000000000..1850620f313
--- /dev/null
+++ b/home-manager/tests/modules/programs/neomutt/hm-example.com-msmtp-expected.conf
@@ -0,0 +1,33 @@
+# Generated by Home Manager.
+set ssl_force_tls = yes
+set certificate_file=/etc/ssl/certs/ca-certificates.crt
+
+# GPG section
+set crypt_use_gpgme = yes
+set crypt_autosign = no
+set pgp_use_gpg_agent = yes
+set mbox_type = Maildir
+set sort = "threads"
+
+# MTA section
+set sendmail='msmtpq --read-envelope-from --read-recipients'
+
+
+
+
+
+# MRA section
+set folder='/home/hm-user/Mail/hm@example.com'
+set from='hm@example.com'
+set postponed='+Drafts'
+set realname='H. M. Test'
+set record='+Sent'
+set spoolfile='+Inbox'
+set trash='+Trash'
+color status cyan default
+
+
+
+# Extra configuration
+color status cyan default
+
diff --git a/home-manager/tests/modules/programs/neomutt/neomutt-expected.conf b/home-manager/tests/modules/programs/neomutt/neomutt-expected.conf
new file mode 100644
index 00000000000..7711aa5a652
--- /dev/null
+++ b/home-manager/tests/modules/programs/neomutt/neomutt-expected.conf
@@ -0,0 +1,27 @@
+# Generated by Home Manager.
+set header_cache = "/home/hm-user/.cache/neomutt/headers/"
+set message_cachedir = "/home/hm-user/.cache/neomutt/messages/"
+set editor = "$EDITOR"
+set implicit_autoview = yes
+
+alternative_order text/enriched text/plain text
+
+set delete = yes
+
+# Binds
+
+
+# Macros
+
+
+
+
+# Extra configuration
+
+
+
+# register account hm@example.com
+mailboxes "/home/hm-user/Mail/hm@example.com/Inbox"
+folder-hook /home/hm-user/Mail/hm@example.com/ " \
+ source /home/hm-user/.config/neomutt/hm@example.com "
+source /home/hm-user/.config/neomutt/hm@example.com \ No newline at end of file
diff --git a/home-manager/tests/modules/programs/neomutt/neomutt-with-msmtp.nix b/home-manager/tests/modules/programs/neomutt/neomutt-with-msmtp.nix
new file mode 100644
index 00000000000..22f65599cf4
--- /dev/null
+++ b/home-manager/tests/modules/programs/neomutt/neomutt-with-msmtp.nix
@@ -0,0 +1,39 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ imports = [ ../../accounts/email-test-accounts.nix ];
+
+ config = {
+ accounts.email.accounts = {
+ "hm@example.com" = {
+ primary = true;
+ msmtp.enable = true;
+ neomutt = {
+ enable = true;
+ extraConfig = ''
+ color status cyan default
+ '';
+ };
+ imap.port = 993;
+ };
+ };
+
+ programs.neomutt.enable = true;
+
+ nixpkgs.overlays =
+ [ (self: super: { neomutt = pkgs.writeScriptBin "dummy-neomutt" ""; }) ];
+
+ nmt.script = ''
+ assertFileExists home-files/.config/neomutt/neomuttrc
+ assertFileExists home-files/.config/neomutt/hm@example.com
+ assertFileContent home-files/.config/neomutt/neomuttrc ${
+ ./neomutt-expected.conf
+ }
+ assertFileContent home-files/.config/neomutt/hm@example.com ${
+ ./hm-example.com-msmtp-expected.conf
+ }
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/neomutt/neomutt.nix b/home-manager/tests/modules/programs/neomutt/neomutt.nix
new file mode 100644
index 00000000000..c0caa44af4a
--- /dev/null
+++ b/home-manager/tests/modules/programs/neomutt/neomutt.nix
@@ -0,0 +1,42 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ imports = [ ../../accounts/email-test-accounts.nix ];
+
+ config = {
+ accounts.email.accounts = {
+ "hm@example.com" = {
+ primary = true;
+ notmuch.enable = true;
+ neomutt = {
+ enable = true;
+ extraConfig = ''
+ color status cyan default
+ '';
+ };
+ imap.port = 993;
+ };
+ };
+
+ programs.neomutt = {
+ enable = true;
+ vimKeys = false;
+ };
+
+ nixpkgs.overlays =
+ [ (self: super: { neomutt = pkgs.writeScriptBin "dummy-neomutt" ""; }) ];
+
+ nmt.script = ''
+ assertFileExists home-files/.config/neomutt/neomuttrc
+ assertFileExists home-files/.config/neomutt/hm@example.com
+ assertFileContent home-files/.config/neomutt/neomuttrc ${
+ ./neomutt-expected.conf
+ }
+ assertFileContent home-files/.config/neomutt/hm@example.com ${
+ ./hm-example.com-expected
+ }
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/newsboat/default.nix b/home-manager/tests/modules/programs/newsboat/default.nix
new file mode 100644
index 00000000000..f12f640ef29
--- /dev/null
+++ b/home-manager/tests/modules/programs/newsboat/default.nix
@@ -0,0 +1,4 @@
+{
+ newsboat-basics = ./newsboat-basics.nix;
+ newsboat-basics-2003 = ./newsboat-basics-2003.nix;
+}
diff --git a/home-manager/tests/modules/programs/newsboat/newsboat-basics-2003.nix b/home-manager/tests/modules/programs/newsboat/newsboat-basics-2003.nix
new file mode 100644
index 00000000000..587a31bb255
--- /dev/null
+++ b/home-manager/tests/modules/programs/newsboat/newsboat-basics-2003.nix
@@ -0,0 +1,35 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ home.stateVersion = "20.03";
+
+ programs.newsboat = {
+ enable = true;
+
+ urls = [
+ {
+ url = "http://example.org/feed.xml";
+ tags = [ "tag1" "tag2" ];
+ title = "Cool feed";
+ }
+
+ { url = "http://example.org/feed2.xml"; }
+ ];
+
+ queries = { "foo" = ''rssurl =~ "example.com"''; };
+ };
+
+ nixpkgs.overlays = [
+ (self: super: { newsboat = pkgs.writeScriptBin "dummy-newsboat" ""; })
+ ];
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/.newsboat/urls \
+ ${./newsboat-basics-urls-2003.txt}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/newsboat/newsboat-basics-urls-2003.txt b/home-manager/tests/modules/programs/newsboat/newsboat-basics-urls-2003.txt
new file mode 100644
index 00000000000..68f81118053
--- /dev/null
+++ b/home-manager/tests/modules/programs/newsboat/newsboat-basics-urls-2003.txt
@@ -0,0 +1,3 @@
+"query:foo:rssurl =~ \"example.com\""
+http://example.org/feed.xml "tag1" "tag2" "~Cool feed"
+http://example.org/feed2.xml
diff --git a/home-manager/tests/modules/programs/newsboat/newsboat-basics-urls.txt b/home-manager/tests/modules/programs/newsboat/newsboat-basics-urls.txt
new file mode 100644
index 00000000000..7f084961345
--- /dev/null
+++ b/home-manager/tests/modules/programs/newsboat/newsboat-basics-urls.txt
@@ -0,0 +1,3 @@
+http://example.org/feed.xml "tag1" "tag2" "~Cool feed"
+http://example.org/feed2.xml
+"query:foo:rssurl =~ \"example.com\""
diff --git a/home-manager/tests/modules/programs/newsboat/newsboat-basics.nix b/home-manager/tests/modules/programs/newsboat/newsboat-basics.nix
new file mode 100644
index 00000000000..e6eb4151776
--- /dev/null
+++ b/home-manager/tests/modules/programs/newsboat/newsboat-basics.nix
@@ -0,0 +1,33 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.newsboat = {
+ enable = true;
+
+ urls = [
+ {
+ url = "http://example.org/feed.xml";
+ tags = [ "tag1" "tag2" ];
+ title = "Cool feed";
+ }
+
+ { url = "http://example.org/feed2.xml"; }
+ ];
+
+ queries = { "foo" = ''rssurl =~ "example.com"''; };
+ };
+
+ nixpkgs.overlays = [
+ (self: super: { newsboat = pkgs.writeScriptBin "dummy-newsboat" ""; })
+ ];
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/.newsboat/urls \
+ ${./newsboat-basics-urls.txt}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/nushell/default.nix b/home-manager/tests/modules/programs/nushell/default.nix
new file mode 100644
index 00000000000..5b3bfa1a5bf
--- /dev/null
+++ b/home-manager/tests/modules/programs/nushell/default.nix
@@ -0,0 +1 @@
+{ nushell-settings = ./settings.nix; }
diff --git a/home-manager/tests/modules/programs/nushell/settings-expected.toml b/home-manager/tests/modules/programs/nushell/settings-expected.toml
new file mode 100644
index 00000000000..87c5de2500d
--- /dev/null
+++ b/home-manager/tests/modules/programs/nushell/settings-expected.toml
@@ -0,0 +1,5 @@
+completion_mode = "circular"
+edit_mode = "vi"
+key_timeout = 10
+no_auto_pivot = true
+startup = ["alias la [] { ls -a }", "alias e [msg] { echo $msg }"]
diff --git a/home-manager/tests/modules/programs/nushell/settings.nix b/home-manager/tests/modules/programs/nushell/settings.nix
new file mode 100644
index 00000000000..09c192b3ba3
--- /dev/null
+++ b/home-manager/tests/modules/programs/nushell/settings.nix
@@ -0,0 +1,34 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.nushell = {
+ enable = true;
+
+ settings = mkMerge [
+ {
+ edit_mode = "vi";
+ startup = [ "alias la [] { ls -a }" ];
+ completion_mode = "circular";
+ key_timeout = 10;
+ }
+
+ {
+ startup = [ "alias e [msg] { echo $msg }" ];
+ no_auto_pivot = true;
+ }
+ ];
+ };
+
+ nixpkgs.overlays =
+ [ (self: super: { nushell = pkgs.writeScriptBin "dummy-nushell" ""; }) ];
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/.config/nu/config.toml \
+ ${./settings-expected.toml}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/powerline-go/default.nix b/home-manager/tests/modules/programs/powerline-go/default.nix
new file mode 100644
index 00000000000..50febefbccd
--- /dev/null
+++ b/home-manager/tests/modules/programs/powerline-go/default.nix
@@ -0,0 +1 @@
+{ powerline-go-standard = ./standard.nix; }
diff --git a/home-manager/tests/modules/programs/powerline-go/standard.nix b/home-manager/tests/modules/programs/powerline-go/standard.nix
new file mode 100644
index 00000000000..b01fcb1a75d
--- /dev/null
+++ b/home-manager/tests/modules/programs/powerline-go/standard.nix
@@ -0,0 +1,28 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs = {
+ bash.enable = true;
+
+ powerline-go = {
+ enable = true;
+ newline = true;
+ modules = [ "nix-shell" ];
+ pathAliases = { "\\~/project/foo" = "prj-foo"; };
+ settings = {
+ ignore-repos = [ "/home/me/project1" "/home/me/project2" ];
+ };
+ };
+ };
+
+ nmt.script = ''
+ assertFileExists home-files/.bashrc
+ assertFileContains \
+ home-files/.bashrc \
+ '/bin/powerline-go -error $old_exit_status -modules nix-shell -newline -path-aliases \~/project/foo=prj-foo -ignore-repos /home/me/project1,/home/me/project2'
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/qutebrowser/default.nix b/home-manager/tests/modules/programs/qutebrowser/default.nix
new file mode 100644
index 00000000000..581b4a5834e
--- /dev/null
+++ b/home-manager/tests/modules/programs/qutebrowser/default.nix
@@ -0,0 +1,4 @@
+{
+ qutebrowser-settings = ./settings.nix;
+ qutebrowser-keybindings = ./keybindings.nix;
+}
diff --git a/home-manager/tests/modules/programs/qutebrowser/keybindings.nix b/home-manager/tests/modules/programs/qutebrowser/keybindings.nix
new file mode 100644
index 00000000000..e89e44b46d9
--- /dev/null
+++ b/home-manager/tests/modules/programs/qutebrowser/keybindings.nix
@@ -0,0 +1,39 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.qutebrowser = {
+ enable = true;
+
+ enableDefaultBindings = false;
+
+ keyBindings = {
+ normal = {
+ "<Ctrl-v>" = "spawn mpv {url}";
+ ",l" = ''config-cycle spellcheck.languages ["en-GB"] ["en-US"]'';
+ };
+ prompt = { "<Ctrl-y>" = "prompt-yes"; };
+ };
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ qutebrowser = pkgs.writeScriptBin "dummy-qutebrowser" "";
+ })
+ ];
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/.config/qutebrowser/config.py \
+ ${
+ pkgs.writeText "qutebrowser-expected-config.py" ''
+ c.bindings.default = {}
+ config.bind(",l", "config-cycle spellcheck.languages [\"en-GB\"] [\"en-US\"]", mode="normal")
+ config.bind("<Ctrl-v>", "spawn mpv {url}", mode="normal")
+ config.bind("<Ctrl-y>", "prompt-yes", mode="prompt")''
+ }
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/qutebrowser/settings.nix b/home-manager/tests/modules/programs/qutebrowser/settings.nix
new file mode 100644
index 00000000000..1f0f5db049b
--- /dev/null
+++ b/home-manager/tests/modules/programs/qutebrowser/settings.nix
@@ -0,0 +1,48 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.qutebrowser = {
+ enable = true;
+
+ settings = {
+ colors = {
+ hints = {
+ bg = "#000000";
+ fg = "#ffffff";
+ };
+ tabs.bar.bg = "#000000";
+ };
+ spellcheck.languages = [ "en-US" "sv-SE" ];
+ tabs.tabs_are_windows = true;
+ };
+
+ extraConfig = ''
+ # Extra qutebrowser configuration.
+ '';
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ qutebrowser = pkgs.writeScriptBin "dummy-qutebrowser" "";
+ })
+ ];
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/.config/qutebrowser/config.py \
+ ${
+ pkgs.writeText "qutebrowser-expected-config.py" ''
+ c.colors.hints.bg = "#000000"
+ c.colors.hints.fg = "#ffffff"
+ c.colors.tabs.bar.bg = "#000000"
+ c.spellcheck.languages = ["en-US", "sv-SE"]
+ c.tabs.tabs_are_windows = True
+ # Extra qutebrowser configuration.
+ ''
+ }
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/readline/default.nix b/home-manager/tests/modules/programs/readline/default.nix
new file mode 100644
index 00000000000..c95745d19cd
--- /dev/null
+++ b/home-manager/tests/modules/programs/readline/default.nix
@@ -0,0 +1 @@
+{ readline-using-all-options = ./using-all-options.nix; }
diff --git a/home-manager/tests/modules/programs/readline/using-all-options.nix b/home-manager/tests/modules/programs/readline/using-all-options.nix
new file mode 100644
index 00000000000..ab851020c2e
--- /dev/null
+++ b/home-manager/tests/modules/programs/readline/using-all-options.nix
@@ -0,0 +1,31 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.readline = {
+ enable = true;
+
+ bindings = { "\\C-h" = "backward-kill-word"; };
+
+ variables = {
+ bell-style = "audible";
+ completion-map-case = true;
+ completion-prefix-display-length = 2;
+ };
+
+ extraConfig = ''
+ $if mode=emacs
+ "\e[1~": beginning-of-line
+ $endif
+ '';
+ };
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/.inputrc \
+ ${./using-all-options.txt}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/readline/using-all-options.txt b/home-manager/tests/modules/programs/readline/using-all-options.txt
new file mode 100644
index 00000000000..6b4aef51e69
--- /dev/null
+++ b/home-manager/tests/modules/programs/readline/using-all-options.txt
@@ -0,0 +1,11 @@
+# Generated by Home Manager.
+
+$include /etc/inputrc
+set bell-style audible
+set completion-map-case on
+set completion-prefix-display-length 2
+"\C-h": backward-kill-word
+$if mode=emacs
+"\e[1~": beginning-of-line
+$endif
+
diff --git a/home-manager/tests/modules/programs/rofi/assert-on-both-theme-and-colors-expected.json b/home-manager/tests/modules/programs/rofi/assert-on-both-theme-and-colors-expected.json
new file mode 100644
index 00000000000..808288f4193
--- /dev/null
+++ b/home-manager/tests/modules/programs/rofi/assert-on-both-theme-and-colors-expected.json
@@ -0,0 +1 @@
+["Cannot use the rofi options 'theme' and 'colors' simultaneously.\n"] \ No newline at end of file
diff --git a/home-manager/tests/modules/programs/rofi/assert-on-both-theme-and-colors.nix b/home-manager/tests/modules/programs/rofi/assert-on-both-theme-and-colors.nix
new file mode 100644
index 00000000000..f162a486b8b
--- /dev/null
+++ b/home-manager/tests/modules/programs/rofi/assert-on-both-theme-and-colors.nix
@@ -0,0 +1,32 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.rofi = {
+ enable = true;
+ theme = "foo";
+ colors = {
+ window = {
+ background = "background";
+ border = "border";
+ separator = "separator";
+ };
+ rows = { };
+ };
+ };
+
+ home.file.result.text = builtins.toJSON
+ (map (a: a.message) (filter (a: !a.assertion) config.assertions));
+
+ nixpkgs.overlays =
+ [ (self: super: { rofi = pkgs.writeScriptBin "dummy-rofi" ""; }) ];
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/result \
+ ${./assert-on-both-theme-and-colors-expected.json}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/rofi/default.nix b/home-manager/tests/modules/programs/rofi/default.nix
new file mode 100644
index 00000000000..c18c3b0ed6a
--- /dev/null
+++ b/home-manager/tests/modules/programs/rofi/default.nix
@@ -0,0 +1,3 @@
+{
+ rofi-assert-on-both-theme-and-colors = ./assert-on-both-theme-and-colors.nix;
+}
diff --git a/home-manager/tests/modules/programs/ssh/default-config-expected.conf b/home-manager/tests/modules/programs/ssh/default-config-expected.conf
new file mode 100644
index 00000000000..6885392b26c
--- /dev/null
+++ b/home-manager/tests/modules/programs/ssh/default-config-expected.conf
@@ -0,0 +1,16 @@
+
+
+
+
+Host *
+ ForwardAgent no
+ Compression no
+ ServerAliveInterval 0
+ ServerAliveCountMax 3
+ HashKnownHosts no
+ UserKnownHostsFile ~/.ssh/known_hosts
+ ControlMaster no
+ ControlPath ~/.ssh/master-%r@%n:%p
+ ControlPersist no
+
+
diff --git a/home-manager/tests/modules/programs/ssh/default-config.nix b/home-manager/tests/modules/programs/ssh/default-config.nix
new file mode 100644
index 00000000000..6d7e5508a2f
--- /dev/null
+++ b/home-manager/tests/modules/programs/ssh/default-config.nix
@@ -0,0 +1,18 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.ssh = { enable = true; };
+
+ home.file.assertions.text = builtins.toJSON
+ (map (a: a.message) (filter (a: !a.assertion) config.assertions));
+
+ nmt.script = ''
+ assertFileExists home-files/.ssh/config
+ assertFileContent home-files/.ssh/config ${./default-config-expected.conf}
+ assertFileContent home-files/assertions ${./no-assertions.json}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/ssh/default.nix b/home-manager/tests/modules/programs/ssh/default.nix
new file mode 100644
index 00000000000..507eef0bdb8
--- /dev/null
+++ b/home-manager/tests/modules/programs/ssh/default.nix
@@ -0,0 +1,17 @@
+{
+ ssh-defaults = ./default-config.nix;
+ ssh-match-blocks = ./match-blocks-attrs.nix;
+
+ ssh-forwards-dynamic-valid-bind-no-asserts =
+ ./forwards-dynamic-valid-bind-no-asserts.nix;
+ ssh-forwards-dynamic-bind-path-with-port-asserts =
+ ./forwards-dynamic-bind-path-with-port-asserts.nix;
+ ssh-forwards-local-bind-path-with-port-asserts =
+ ./forwards-local-bind-path-with-port-asserts.nix;
+ ssh-forwards-local-host-path-with-port-asserts =
+ ./forwards-local-host-path-with-port-asserts.nix;
+ ssh-forwards-remote-bind-path-with-port-asserts =
+ ./forwards-remote-bind-path-with-port-asserts.nix;
+ ssh-forwards-remote-host-path-with-port-asserts =
+ ./forwards-remote-host-path-with-port-asserts.nix;
+}
diff --git a/home-manager/tests/modules/programs/ssh/forwards-dynamic-bind-path-with-port-asserts.nix b/home-manager/tests/modules/programs/ssh/forwards-dynamic-bind-path-with-port-asserts.nix
new file mode 100644
index 00000000000..cf2efe5a5a5
--- /dev/null
+++ b/home-manager/tests/modules/programs/ssh/forwards-dynamic-bind-path-with-port-asserts.nix
@@ -0,0 +1,29 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.ssh = {
+ enable = true;
+ matchBlocks = {
+ dynamicBindPathWithPort = {
+ dynamicForwards = [{
+ # Error:
+ address = "/run/user/1000/gnupg/S.gpg-agent.extra";
+ port = 3000;
+ }];
+ };
+ };
+ };
+
+ home.file.result.text = builtins.toJSON
+ (map (a: a.message) (filter (a: !a.assertion) config.assertions));
+
+ nmt.script = ''
+ assertFileContent home-files/result ${
+ ./forwards-paths-with-ports-error.json
+ }
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts-expected.conf b/home-manager/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts-expected.conf
new file mode 100644
index 00000000000..02268e8cb8b
--- /dev/null
+++ b/home-manager/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts-expected.conf
@@ -0,0 +1,20 @@
+
+
+Host dynamicBindAddressWithPort
+ DynamicForward [127.0.0.1]:3000
+
+Host dynamicBindPathNoPort
+ DynamicForward /run/user/1000/gnupg/S.gpg-agent.extra
+
+Host *
+ ForwardAgent no
+ Compression no
+ ServerAliveInterval 0
+ ServerAliveCountMax 3
+ HashKnownHosts no
+ UserKnownHostsFile ~/.ssh/known_hosts
+ ControlMaster no
+ ControlPath ~/.ssh/master-%r@%n:%p
+ ControlPersist no
+
+
diff --git a/home-manager/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts.nix b/home-manager/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts.nix
new file mode 100644
index 00000000000..d0c3a732256
--- /dev/null
+++ b/home-manager/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts.nix
@@ -0,0 +1,38 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.ssh = {
+ enable = true;
+ matchBlocks = {
+ dynamicBindPathNoPort = {
+ dynamicForwards = [{
+ # OK:
+ address = "/run/user/1000/gnupg/S.gpg-agent.extra";
+ }];
+ };
+
+ dynamicBindAddressWithPort = {
+ dynamicForwards = [{
+ # OK:
+ address = "127.0.0.1";
+ port = 3000;
+ }];
+ };
+ };
+ };
+
+ home.file.result.text = builtins.toJSON
+ (map (a: a.message) (filter (a: !a.assertion) config.assertions));
+
+ nmt.script = ''
+ assertFileExists home-files/.ssh/config
+ assertFileContent \
+ home-files/.ssh/config \
+ ${./forwards-dynamic-valid-bind-no-asserts-expected.conf}
+ assertFileContent home-files/result ${./no-assertions.json}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/ssh/forwards-local-bind-path-with-port-asserts.nix b/home-manager/tests/modules/programs/ssh/forwards-local-bind-path-with-port-asserts.nix
new file mode 100644
index 00000000000..f9d8e2daf85
--- /dev/null
+++ b/home-manager/tests/modules/programs/ssh/forwards-local-bind-path-with-port-asserts.nix
@@ -0,0 +1,33 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.ssh = {
+ enable = true;
+ matchBlocks = {
+ localBindPathWithPort = {
+ localForwards = [{
+ # OK:
+ host.address = "127.0.0.1";
+ host.port = 3000;
+
+ # Error:
+ bind.address = "/run/user/1000/gnupg/S.gpg-agent.extra";
+ bind.port = 3000;
+ }];
+ };
+ };
+ };
+
+ home.file.result.text = builtins.toJSON
+ (map (a: a.message) (filter (a: !a.assertion) config.assertions));
+
+ nmt.script = ''
+ assertFileContent home-files/result ${
+ ./forwards-paths-with-ports-error.json
+ }
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/ssh/forwards-local-host-path-with-port-asserts.nix b/home-manager/tests/modules/programs/ssh/forwards-local-host-path-with-port-asserts.nix
new file mode 100644
index 00000000000..02a7e5b168d
--- /dev/null
+++ b/home-manager/tests/modules/programs/ssh/forwards-local-host-path-with-port-asserts.nix
@@ -0,0 +1,33 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.ssh = {
+ enable = true;
+ matchBlocks = {
+ localHostPathWithPort = {
+ localForwards = [{
+ # OK:
+ bind.address = "127.0.0.1";
+ bind.port = 3000;
+
+ # Error:
+ host.address = "/run/user/1000/gnupg/S.gpg-agent.extra";
+ host.port = 3000;
+ }];
+ };
+ };
+ };
+
+ home.file.result.text = builtins.toJSON
+ (map (a: a.message) (filter (a: !a.assertion) config.assertions));
+
+ nmt.script = ''
+ assertFileContent home-files/result ${
+ ./forwards-paths-with-ports-error.json
+ }
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/ssh/forwards-paths-with-ports-error.json b/home-manager/tests/modules/programs/ssh/forwards-paths-with-ports-error.json
new file mode 100644
index 00000000000..e7e3a374ecc
--- /dev/null
+++ b/home-manager/tests/modules/programs/ssh/forwards-paths-with-ports-error.json
@@ -0,0 +1 @@
+["Forwarded paths cannot have ports."] \ No newline at end of file
diff --git a/home-manager/tests/modules/programs/ssh/forwards-remote-bind-path-with-port-asserts.nix b/home-manager/tests/modules/programs/ssh/forwards-remote-bind-path-with-port-asserts.nix
new file mode 100644
index 00000000000..61ce9ae0385
--- /dev/null
+++ b/home-manager/tests/modules/programs/ssh/forwards-remote-bind-path-with-port-asserts.nix
@@ -0,0 +1,33 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.ssh = {
+ enable = true;
+ matchBlocks = {
+ remoteBindPathWithPort = {
+ remoteForwards = [{
+ # OK:
+ host.address = "127.0.0.1";
+ host.port = 3000;
+
+ # Error:
+ bind.address = "/run/user/1000/gnupg/S.gpg-agent.extra";
+ bind.port = 3000;
+ }];
+ };
+ };
+ };
+
+ home.file.result.text = builtins.toJSON
+ (map (a: a.message) (filter (a: !a.assertion) config.assertions));
+
+ nmt.script = ''
+ assertFileContent home-files/result ${
+ ./forwards-paths-with-ports-error.json
+ }
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/ssh/forwards-remote-host-path-with-port-asserts.nix b/home-manager/tests/modules/programs/ssh/forwards-remote-host-path-with-port-asserts.nix
new file mode 100644
index 00000000000..71bdbcb70fd
--- /dev/null
+++ b/home-manager/tests/modules/programs/ssh/forwards-remote-host-path-with-port-asserts.nix
@@ -0,0 +1,33 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.ssh = {
+ enable = true;
+ matchBlocks = {
+ remoteHostPathWithPort = {
+ remoteForwards = [{
+ # OK:
+ bind.address = "127.0.0.1";
+ bind.port = 3000;
+
+ # Error:
+ host.address = "/run/user/1000/gnupg/S.gpg-agent.extra";
+ host.port = 3000;
+ }];
+ };
+ };
+ };
+
+ home.file.result.text = builtins.toJSON
+ (map (a: a.message) (filter (a: !a.assertion) config.assertions));
+
+ nmt.script = ''
+ assertFileContent home-files/result ${
+ ./forwards-paths-with-ports-error.json
+ }
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/ssh/match-blocks-attrs-expected.conf b/home-manager/tests/modules/programs/ssh/match-blocks-attrs-expected.conf
new file mode 100644
index 00000000000..e2c3290153d
--- /dev/null
+++ b/home-manager/tests/modules/programs/ssh/match-blocks-attrs-expected.conf
@@ -0,0 +1,34 @@
+
+
+Host * !github.com
+ Port 516
+ IdentityFile file1
+ IdentityFile file2
+
+Host abc
+ ProxyJump jump-host
+
+Host xyz
+ ServerAliveInterval 60
+ ServerAliveCountMax 10
+ IdentityFile file
+ LocalForward [localhost]:8080 [10.0.0.1]:80
+ RemoteForward [localhost]:8081 [10.0.0.2]:80
+ RemoteForward /run/user/1000/gnupg/S.gpg-agent.extra /run/user/1000/gnupg/S.gpg-agent
+ DynamicForward [localhost]:2839
+
+Host ordered
+ Port 1
+
+Host *
+ ForwardAgent no
+ Compression no
+ ServerAliveInterval 0
+ ServerAliveCountMax 3
+ HashKnownHosts no
+ UserKnownHostsFile ~/.ssh/known_hosts
+ ControlMaster no
+ ControlPath ~/.ssh/master-%r@%n:%p
+ ControlPersist no
+
+
diff --git a/home-manager/tests/modules/programs/ssh/match-blocks-attrs.nix b/home-manager/tests/modules/programs/ssh/match-blocks-attrs.nix
new file mode 100644
index 00000000000..eaa20c6e32d
--- /dev/null
+++ b/home-manager/tests/modules/programs/ssh/match-blocks-attrs.nix
@@ -0,0 +1,58 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.ssh = {
+ enable = true;
+ matchBlocks = {
+ abc = {
+ identityFile = null;
+ proxyJump = "jump-host";
+ };
+
+ ordered = hm.dag.entryAfter [ "xyz" ] { port = 1; };
+
+ xyz = {
+ identityFile = "file";
+ serverAliveInterval = 60;
+ serverAliveCountMax = 10;
+ localForwards = [{
+ bind.port = 8080;
+ host.address = "10.0.0.1";
+ host.port = 80;
+ }];
+ remoteForwards = [
+ {
+ bind.port = 8081;
+ host.address = "10.0.0.2";
+ host.port = 80;
+ }
+ {
+ bind.address = "/run/user/1000/gnupg/S.gpg-agent.extra";
+ host.address = "/run/user/1000/gnupg/S.gpg-agent";
+ }
+ ];
+ dynamicForwards = [{ port = 2839; }];
+ };
+
+ "* !github.com" = {
+ identityFile = [ "file1" "file2" ];
+ port = 516;
+ };
+ };
+ };
+
+ home.file.assertions.text = builtins.toJSON
+ (map (a: a.message) (filter (a: !a.assertion) config.assertions));
+
+ nmt.script = ''
+ assertFileExists home-files/.ssh/config
+ assertFileContent \
+ home-files/.ssh/config \
+ ${./match-blocks-attrs-expected.conf}
+ assertFileContent home-files/assertions ${./no-assertions.json}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/ssh/no-assertions.json b/home-manager/tests/modules/programs/ssh/no-assertions.json
new file mode 100644
index 00000000000..0637a088a01
--- /dev/null
+++ b/home-manager/tests/modules/programs/ssh/no-assertions.json
@@ -0,0 +1 @@
+[] \ No newline at end of file
diff --git a/home-manager/tests/modules/programs/starship/default.nix b/home-manager/tests/modules/programs/starship/default.nix
new file mode 100644
index 00000000000..814aed65874
--- /dev/null
+++ b/home-manager/tests/modules/programs/starship/default.nix
@@ -0,0 +1 @@
+{ starship-settings = ./settings.nix; }
diff --git a/home-manager/tests/modules/programs/starship/settings-expected.toml b/home-manager/tests/modules/programs/starship/settings-expected.toml
new file mode 100644
index 00000000000..a4fb0ee55de
--- /dev/null
+++ b/home-manager/tests/modules/programs/starship/settings-expected.toml
@@ -0,0 +1,27 @@
+add_newline = false
+prompt_order = ["line_break", "package", "line_break", "character"]
+scan_timeout = 10
+
+[aws]
+disabled = true
+style = "bold blue"
+
+[battery]
+charging_symbol = "⚡️"
+
+[[battery.display]]
+style = "bold red"
+threshold = 10
+
+[[battery.display]]
+style = "bold yellow"
+threshold = 30
+
+[character]
+symbol = "➜"
+
+[memory_usage]
+threshold = -1
+
+[package]
+disabled = true
diff --git a/home-manager/tests/modules/programs/starship/settings.nix b/home-manager/tests/modules/programs/starship/settings.nix
new file mode 100644
index 00000000000..e7a27733d90
--- /dev/null
+++ b/home-manager/tests/modules/programs/starship/settings.nix
@@ -0,0 +1,49 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.starship = {
+ enable = true;
+
+ settings = mkMerge [
+ {
+ add_newline = false;
+ prompt_order = [ "line_break" "package" "line_break" "character" ];
+ scan_timeout = 10;
+ character.symbol = "➜";
+ package.disabled = true;
+ memory_usage.threshold = -1;
+ aws.style = "bold blue";
+ battery = {
+ charging_symbol = "⚡️";
+ display = [{
+ threshold = 10;
+ style = "bold red";
+ }];
+ };
+ }
+
+ {
+ aws.disabled = true;
+
+ battery.display = [{
+ threshold = 30;
+ style = "bold yellow";
+ }];
+ }
+ ];
+ };
+
+ nixpkgs.overlays = [
+ (self: super: { starship = pkgs.writeScriptBin "dummy-starship" ""; })
+ ];
+
+ nmt.script = ''
+ assertFileContent \
+ home-files/.config/starship.toml \
+ ${./settings-expected.toml}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/texlive/default.nix b/home-manager/tests/modules/programs/texlive/default.nix
new file mode 100644
index 00000000000..23bfe2daf0a
--- /dev/null
+++ b/home-manager/tests/modules/programs/texlive/default.nix
@@ -0,0 +1 @@
+{ texlive-minimal = ./texlive-minimal.nix; }
diff --git a/home-manager/tests/modules/programs/texlive/texlive-minimal.nix b/home-manager/tests/modules/programs/texlive/texlive-minimal.nix
new file mode 100644
index 00000000000..1b13936beac
--- /dev/null
+++ b/home-manager/tests/modules/programs/texlive/texlive-minimal.nix
@@ -0,0 +1,27 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.texlive.enable = true;
+
+ # Set up a minimal mocked texlive package set.
+ nixpkgs.overlays = [
+ (self: super: {
+ texlive = {
+ collection-basic = pkgs.writeTextDir "collection-basic" "";
+ combine = tpkgs:
+ pkgs.symlinkJoin {
+ name = "dummy-texlive-combine";
+ paths = attrValues tpkgs;
+ };
+ };
+ })
+ ];
+
+ nmt.script = ''
+ assertFileExists home-path/collection-basic
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/tmux/default.nix b/home-manager/tests/modules/programs/tmux/default.nix
new file mode 100644
index 00000000000..d4501c60981
--- /dev/null
+++ b/home-manager/tests/modules/programs/tmux/default.nix
@@ -0,0 +1,7 @@
+{
+ tmux-emacs-with-plugins = ./emacs-with-plugins.nix;
+ tmux-not-enabled = ./not-enabled.nix;
+ tmux-vi-all-true = ./vi-all-true.nix;
+ tmux-secure-socket-enabled = ./secure-socket-enabled.nix;
+ tmux-disable-confirmation-prompt = ./disable-confirmation-prompt.nix;
+}
diff --git a/home-manager/tests/modules/programs/tmux/disable-confirmation-prompt.conf b/home-manager/tests/modules/programs/tmux/disable-confirmation-prompt.conf
new file mode 100644
index 00000000000..222f733d5f3
--- /dev/null
+++ b/home-manager/tests/modules/programs/tmux/disable-confirmation-prompt.conf
@@ -0,0 +1,30 @@
+# ============================================= #
+# Start with defaults from the Sensible plugin #
+# --------------------------------------------- #
+run-shell @sensible_rtp@
+# ============================================= #
+
+set -g default-terminal "screen"
+set -g base-index 0
+setw -g pane-base-index 0
+
+
+
+
+
+set -g status-keys emacs
+set -g mode-keys emacs
+
+
+
+
+
+bind-key & kill-window
+bind-key x kill-pane
+
+
+setw -g aggressive-resize off
+setw -g clock-mode-style 12
+set -s escape-time 500
+set -g history-limit 2000
+
diff --git a/home-manager/tests/modules/programs/tmux/disable-confirmation-prompt.nix b/home-manager/tests/modules/programs/tmux/disable-confirmation-prompt.nix
new file mode 100644
index 00000000000..9c65ad6eee4
--- /dev/null
+++ b/home-manager/tests/modules/programs/tmux/disable-confirmation-prompt.nix
@@ -0,0 +1,26 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.tmux = {
+ enable = true;
+ disableConfirmationPrompt = true;
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ tmuxPlugins = super.tmuxPlugins // {
+ sensible = super.tmuxPlugins.sensible // { rtp = "@sensible_rtp@"; };
+ };
+ })
+ ];
+
+ nmt.script = ''
+ assertFileExists home-files/.tmux.conf
+ assertFileContent home-files/.tmux.conf \
+ ${./disable-confirmation-prompt.conf}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/tmux/emacs-with-plugins.conf b/home-manager/tests/modules/programs/tmux/emacs-with-plugins.conf
new file mode 100644
index 00000000000..97e226316f4
--- /dev/null
+++ b/home-manager/tests/modules/programs/tmux/emacs-with-plugins.conf
@@ -0,0 +1,53 @@
+# ============================================= #
+# Start with defaults from the Sensible plugin #
+# --------------------------------------------- #
+run-shell @tmuxplugin_sensible_rtp@
+# ============================================= #
+
+set -g default-terminal "screen"
+set -g base-index 0
+setw -g pane-base-index 0
+
+new-session
+
+bind v split-window -h
+bind s split-window -v
+
+
+set -g status-keys emacs
+set -g mode-keys emacs
+
+
+
+
+
+
+
+setw -g aggressive-resize on
+setw -g clock-mode-style 24
+set -s escape-time 500
+set -g history-limit 2000
+
+# ============================================= #
+# Load plugins with Home Manager #
+# --------------------------------------------- #
+
+# tmuxplugin-logging
+# ---------------------
+
+run-shell @tmuxplugin_logging_rtp@
+
+
+# tmuxplugin-prefix-highlight
+# ---------------------
+
+run-shell @tmuxplugin_prefix_highlight_rtp@
+
+
+# tmuxplugin-fzf-tmux-url
+# ---------------------
+
+run-shell @tmuxplugin_fzf_tmux_url_rtp@
+
+# ============================================= #
+
diff --git a/home-manager/tests/modules/programs/tmux/emacs-with-plugins.nix b/home-manager/tests/modules/programs/tmux/emacs-with-plugins.nix
new file mode 100644
index 00000000000..f9bccaa2ce4
--- /dev/null
+++ b/home-manager/tests/modules/programs/tmux/emacs-with-plugins.nix
@@ -0,0 +1,49 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.tmux = {
+ aggressiveResize = true;
+ clock24 = true;
+ enable = true;
+ keyMode = "emacs";
+ newSession = true;
+ reverseSplit = true;
+
+ plugins = with pkgs.tmuxPlugins; [
+ logging
+ prefix-highlight
+ fzf-tmux-url
+ ];
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ tmuxPlugins = super.tmuxPlugins // {
+ fzf-tmux-url = super.tmuxPlugins.fzf-tmux-url // {
+ rtp = "@tmuxplugin_fzf_tmux_url_rtp@";
+ };
+
+ logging = super.tmuxPlugins.logging // {
+ rtp = "@tmuxplugin_logging_rtp@";
+ };
+
+ prefix-highlight = super.tmuxPlugins.prefix-highlight // {
+ rtp = "@tmuxplugin_prefix_highlight_rtp@";
+ };
+
+ sensible = super.tmuxPlugins.sensible // {
+ rtp = "@tmuxplugin_sensible_rtp@";
+ };
+ };
+ })
+ ];
+
+ nmt.script = ''
+ assertFileExists home-files/.tmux.conf
+ assertFileContent home-files/.tmux.conf ${./emacs-with-plugins.conf}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/tmux/not-enabled.nix b/home-manager/tests/modules/programs/tmux/not-enabled.nix
new file mode 100644
index 00000000000..b7c675a83a2
--- /dev/null
+++ b/home-manager/tests/modules/programs/tmux/not-enabled.nix
@@ -0,0 +1,13 @@
+{ config, lib, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.tmux = { enable = false; };
+
+ nmt.script = ''
+ assertPathNotExists home-files/.tmux.conf
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/tmux/secure-socket-enabled.nix b/home-manager/tests/modules/programs/tmux/secure-socket-enabled.nix
new file mode 100644
index 00000000000..ca2de66310d
--- /dev/null
+++ b/home-manager/tests/modules/programs/tmux/secure-socket-enabled.nix
@@ -0,0 +1,18 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.tmux = {
+ enable = true;
+ secureSocket = true;
+ };
+
+ nmt.script = ''
+ assertFileExists home-path/etc/profile.d/hm-session-vars.sh
+ assertFileContains home-path/etc/profile.d/hm-session-vars.sh \
+ 'export TMUX_TMPDIR="''${XDG_RUNTIME_DIR:-"/run/user/\$(id -u)"}"'
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/tmux/vi-all-true.conf b/home-manager/tests/modules/programs/tmux/vi-all-true.conf
new file mode 100644
index 00000000000..de1cbe06ebc
--- /dev/null
+++ b/home-manager/tests/modules/programs/tmux/vi-all-true.conf
@@ -0,0 +1,30 @@
+# ============================================= #
+# Start with defaults from the Sensible plugin #
+# --------------------------------------------- #
+run-shell @sensible_rtp@
+# ============================================= #
+
+set -g default-terminal "screen"
+set -g base-index 0
+setw -g pane-base-index 0
+
+new-session
+
+bind v split-window -h
+bind s split-window -v
+
+
+set -g status-keys vi
+set -g mode-keys vi
+
+
+
+
+
+
+
+setw -g aggressive-resize on
+setw -g clock-mode-style 24
+set -s escape-time 500
+set -g history-limit 2000
+
diff --git a/home-manager/tests/modules/programs/tmux/vi-all-true.nix b/home-manager/tests/modules/programs/tmux/vi-all-true.nix
new file mode 100644
index 00000000000..bce032fd654
--- /dev/null
+++ b/home-manager/tests/modules/programs/tmux/vi-all-true.nix
@@ -0,0 +1,29 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.tmux = {
+ aggressiveResize = true;
+ clock24 = true;
+ enable = true;
+ keyMode = "vi";
+ newSession = true;
+ reverseSplit = true;
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ tmuxPlugins = super.tmuxPlugins // {
+ sensible = super.tmuxPlugins.sensible // { rtp = "@sensible_rtp@"; };
+ };
+ })
+ ];
+
+ nmt.script = ''
+ assertFileExists home-files/.tmux.conf
+ assertFileContent home-files/.tmux.conf ${./vi-all-true.conf}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/vscode/default.nix b/home-manager/tests/modules/programs/vscode/default.nix
new file mode 100644
index 00000000000..70f6d2e7060
--- /dev/null
+++ b/home-manager/tests/modules/programs/vscode/default.nix
@@ -0,0 +1 @@
+{ vscode-keybindings = ./keybindings.nix; }
diff --git a/home-manager/tests/modules/programs/vscode/keybindings.nix b/home-manager/tests/modules/programs/vscode/keybindings.nix
new file mode 100644
index 00000000000..420b212dce9
--- /dev/null
+++ b/home-manager/tests/modules/programs/vscode/keybindings.nix
@@ -0,0 +1,53 @@
+# Test that keybdinings.json is created correctly.
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ bindings = [
+ {
+ key = "ctrl+c";
+ command = "editor.action.clipboardCopyAction";
+ when = "textInputFocus && false";
+ }
+ {
+ key = "ctrl+c";
+ command = "deleteFile";
+ when = "";
+ }
+ {
+ key = "d";
+ command = "deleteFile";
+ when = "explorerViewletVisible";
+ }
+ ];
+
+ targetPath = if pkgs.stdenv.hostPlatform.isDarwin then
+ "Library/Application Support/Code/User/keybindings.json"
+ else
+ ".config/Code/User/keybindings.json";
+
+ expectedJson = pkgs.writeText "expected.json" (builtins.toJSON bindings);
+in {
+ config = {
+ programs.vscode = {
+ enable = true;
+ keybindings = bindings;
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ vscode = pkgs.runCommandLocal "vscode" { pname = "vscode"; } ''
+ mkdir -p $out/bin
+ touch $out/bin/code
+ chmod +x $out/bin/code;
+ '';
+ })
+ ];
+
+ nmt.script = ''
+ assertFileExists "home-files/${targetPath}"
+ assertFileContent "home-files/${targetPath}" "${expectedJson}"
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/waybar/broken-settings.nix b/home-manager/tests/modules/programs/waybar/broken-settings.nix
new file mode 100644
index 00000000000..68f0b90bfca
--- /dev/null
+++ b/home-manager/tests/modules/programs/waybar/broken-settings.nix
@@ -0,0 +1,80 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ package = pkgs.writeScriptBin "dummy-waybar" "" // { outPath = "@waybar@"; };
+ expected = pkgs.writeText "expected-json" ''
+ [
+ {
+ "height": 26,
+ "layer": "top",
+ "modules-center": [
+ "sway/window"
+ ],
+ "modules-left": [
+ "sway/workspaces",
+ "sway/mode"
+ ],
+ "modules-right": [
+ "idle_inhibitor",
+ "pulseaudio",
+ "network",
+ "cpu",
+ "memory",
+ "backlight",
+ "tray",
+ "clock"
+ ],
+ "output": [
+ "DP-1",
+ "eDP-1",
+ "HEADLESS-1"
+ ],
+ "position": "top",
+ "sway/workspaces": {
+ "all-outputs": true
+ }
+ }
+ ]
+ '';
+in {
+ config = {
+ programs.waybar = {
+ inherit package;
+ enable = true;
+ systemd.enable = true;
+ settings = [{
+ layer = "top";
+ position = "top";
+ height = 26;
+ output = [ "DP-1" "eDP-1" "HEADLESS-1" ];
+ modules-left = [ "sway/workspaces" "sway/mode" ];
+ modules-center = [ "sway/window" ];
+ modules-right = [
+ "idle_inhibitor"
+ "pulseaudio"
+ "network"
+ "cpu"
+ "memory"
+ "backlight"
+ "tray"
+ "clock"
+ ];
+
+ modules = { "sway/workspaces".all-outputs = true; };
+ }];
+ };
+
+ nmt.description = ''
+ Test for the broken configuration
+ https://github.com/rycee/home-manager/pull/1329#issuecomment-653253069
+ '';
+ nmt.script = ''
+ assertPathNotExists home-files/.config/waybar/style.css
+ assertFileContent \
+ home-files/.config/waybar/config \
+ ${expected}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/waybar/default.nix b/home-manager/tests/modules/programs/waybar/default.nix
new file mode 100644
index 00000000000..d50b1b8d368
--- /dev/null
+++ b/home-manager/tests/modules/programs/waybar/default.nix
@@ -0,0 +1,8 @@
+{
+ waybar-systemd-with-graphical-session-target =
+ ./systemd-with-graphical-session-target.nix;
+ waybar-styling = ./styling.nix;
+ waybar-settings-complex = ./settings-complex.nix;
+ # Broken configuration from https://github.com/rycee/home-manager/pull/1329#issuecomment-653253069
+ waybar-broken-settings = ./broken-settings.nix;
+}
diff --git a/home-manager/tests/modules/programs/waybar/settings-complex-expected.json b/home-manager/tests/modules/programs/waybar/settings-complex-expected.json
new file mode 100644
index 00000000000..0d020c19c97
--- /dev/null
+++ b/home-manager/tests/modules/programs/waybar/settings-complex-expected.json
@@ -0,0 +1,46 @@
+[
+ {
+ "custom/my-module": {
+ "exec": "@dummy@/bin/dummy",
+ "format": "hello from {}"
+ },
+ "height": 30,
+ "idle_inhibitor": {
+ "format": "{icon}"
+ },
+ "layer": "top",
+ "modules-center": [
+ "sway/window"
+ ],
+ "modules-left": [
+ "sway/workspaces",
+ "sway/mode",
+ "custom/my-module"
+ ],
+ "modules-right": [
+ "idle_inhibitor",
+ "pulseaudio",
+ "network",
+ "cpu",
+ "memory",
+ "backlight",
+ "tray",
+ "battery",
+ "clock"
+ ],
+ "output": [
+ "DP-1"
+ ],
+ "position": "top",
+ "sway/mode": {
+ "tooltip": false
+ },
+ "sway/window": {
+ "max-length": 120
+ },
+ "sway/workspaces": {
+ "all-outputs": true,
+ "disable-scroll": true
+ }
+ }
+]
diff --git a/home-manager/tests/modules/programs/waybar/settings-complex.nix b/home-manager/tests/modules/programs/waybar/settings-complex.nix
new file mode 100644
index 00000000000..750e52f4581
--- /dev/null
+++ b/home-manager/tests/modules/programs/waybar/settings-complex.nix
@@ -0,0 +1,59 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ package = pkgs.writeScriptBin "dummy-waybar" "" // { outPath = "@waybar@"; };
+in {
+ config = {
+ programs.waybar = {
+ inherit package;
+ enable = true;
+ settings = [{
+ layer = "top";
+ position = "top";
+ height = 30;
+ output = [ "DP-1" ];
+ modules-left = [ "sway/workspaces" "sway/mode" "custom/my-module" ];
+ modules-center = [ "sway/window" ];
+ modules-right = [
+ "idle_inhibitor"
+ "pulseaudio"
+ "network"
+ "cpu"
+ "memory"
+ "backlight"
+ "tray"
+ "battery"
+ "clock"
+ ];
+
+ modules = {
+ "sway/workspaces" = {
+ disable-scroll = true;
+ all-outputs = true;
+ };
+ "sway/mode" = { tooltip = false; };
+ "sway/window" = { max-length = 120; };
+ "idle_inhibitor" = { format = "{icon}"; };
+ "custom/my-module" = {
+ format = "hello from {}";
+ exec = let
+ dummyScript =
+ pkgs.writeShellScriptBin "dummy" "echo within waybar" // {
+ outPath = "@dummy@";
+ };
+ in "${dummyScript}/bin/dummy";
+ };
+ };
+ }];
+ };
+
+ nmt.script = ''
+ assertPathNotExists home-files/.config/waybar/style.css
+ assertFileContent \
+ home-files/.config/waybar/config \
+ ${./settings-complex-expected.json}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/waybar/styling-expected.css b/home-manager/tests/modules/programs/waybar/styling-expected.css
new file mode 100644
index 00000000000..dc779e58770
--- /dev/null
+++ b/home-manager/tests/modules/programs/waybar/styling-expected.css
@@ -0,0 +1,23 @@
+* {
+ border: none;
+ border-radius: 0;
+ font-family: Source Code Pro;
+ font-weight: bold;
+ color: #abb2bf;
+ font-size: 18px;
+ min-height: 0px;
+}
+window#waybar {
+ background: #16191C;
+ color: #aab2bf;
+}
+#window {
+ padding: 0 0px;
+}
+#workspaces button:hover {
+ box-shadow: inherit;
+ text-shadow: inherit;
+ background: #16191C;
+ border: #16191C;
+ padding: 0 3px;
+}
diff --git a/home-manager/tests/modules/programs/waybar/styling.nix b/home-manager/tests/modules/programs/waybar/styling.nix
new file mode 100644
index 00000000000..bd73f2aafd2
--- /dev/null
+++ b/home-manager/tests/modules/programs/waybar/styling.nix
@@ -0,0 +1,46 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ package = pkgs.writeScriptBin "dummy-waybar" "" // { outPath = "@waybar@"; };
+in {
+ config = {
+ programs.waybar = {
+ inherit package;
+ enable = true;
+ style = ''
+ * {
+ border: none;
+ border-radius: 0;
+ font-family: Source Code Pro;
+ font-weight: bold;
+ color: #abb2bf;
+ font-size: 18px;
+ min-height: 0px;
+ }
+ window#waybar {
+ background: #16191C;
+ color: #aab2bf;
+ }
+ #window {
+ padding: 0 0px;
+ }
+ #workspaces button:hover {
+ box-shadow: inherit;
+ text-shadow: inherit;
+ background: #16191C;
+ border: #16191C;
+ padding: 0 3px;
+ }
+ '';
+ };
+
+ nmt.script = ''
+ assertPathNotExists home-files/.config/waybar/config
+ assertFileContent \
+ home-files/.config/waybar/style.css \
+ ${./styling-expected.css}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/waybar/systemd-with-graphical-session-target.nix b/home-manager/tests/modules/programs/waybar/systemd-with-graphical-session-target.nix
new file mode 100644
index 00000000000..e751d804dab
--- /dev/null
+++ b/home-manager/tests/modules/programs/waybar/systemd-with-graphical-session-target.nix
@@ -0,0 +1,24 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ package = pkgs.writeScriptBin "dummy-waybar" "" // { outPath = "@waybar@"; };
+in {
+ config = {
+ programs.waybar = {
+ inherit package;
+ enable = true;
+ systemd.enable = true;
+ };
+
+ nmt.script = ''
+ assertPathNotExists home-files/.config/waybar/config
+ assertPathNotExists home-files/.config/waybar/style.css
+
+ assertFileContent \
+ home-files/.config/systemd/user/waybar.service \
+ ${./systemd-with-graphical-session-target.service}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/waybar/systemd-with-graphical-session-target.service b/home-manager/tests/modules/programs/waybar/systemd-with-graphical-session-target.service
new file mode 100644
index 00000000000..7d4c65214e8
--- /dev/null
+++ b/home-manager/tests/modules/programs/waybar/systemd-with-graphical-session-target.service
@@ -0,0 +1,16 @@
+[Install]
+WantedBy=graphical-session.target
+
+[Service]
+BusName=fr.arouillard.waybar
+ExecStart=@waybar@/bin/waybar
+Restart=always
+RestartSec=1sec
+Type=dbus
+
+[Unit]
+After=dbus.service
+Description=Highly customizable Wayland bar for Sway and Wlroots based compositors.
+Documentation=https://github.com/Alexays/Waybar/wiki
+PartOf=graphical-session.target
+Requisite=dbus.service
diff --git a/home-manager/tests/modules/programs/zplug/default.nix b/home-manager/tests/modules/programs/zplug/default.nix
new file mode 100644
index 00000000000..172f7cd5981
--- /dev/null
+++ b/home-manager/tests/modules/programs/zplug/default.nix
@@ -0,0 +1 @@
+{ zplug-modules = ./modules.nix; }
diff --git a/home-manager/tests/modules/programs/zplug/modules.nix b/home-manager/tests/modules/programs/zplug/modules.nix
new file mode 100644
index 00000000000..704c5c5e2ef
--- /dev/null
+++ b/home-manager/tests/modules/programs/zplug/modules.nix
@@ -0,0 +1,50 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.zsh = {
+ enable = true;
+ zplug = {
+ enable = true;
+ plugins = [
+ {
+ name = "plugins/git";
+ tags = [ "from:oh-my-zsh" ];
+ }
+ {
+ name = "lib/clipboard";
+ tags = [ "from:oh-my-zsh" ''if:"[[ $OSTYPE == *darwin* ]]"'' ];
+ }
+ ];
+ };
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ zsh = pkgs.writeScriptBin "dummy-zsh" "";
+ zplug = pkgs.writeScriptBin "dummy-zplug" "";
+ })
+ ];
+
+ nmt.script = ''
+ assertFileRegex home-files/.zshrc \
+ '^source ${builtins.storeDir}/.*zplug.*/init\.zsh$'
+
+ assertFileContains home-files/.zshrc \
+ 'zplug "plugins/git", from:oh-my-zsh'
+
+ assertFileContains home-files/.zshrc \
+ 'zplug "lib/clipboard", from:oh-my-zsh, if:"[[ $OSTYPE == *darwin* ]]"'
+
+ assertFileContains home-files/.zshrc \
+ 'if ! zplug check; then
+ zplug install
+ fi'
+
+ assertFileRegex home-files/.zshrc \
+ '^zplug load$'
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/zsh/default.nix b/home-manager/tests/modules/programs/zsh/default.nix
new file mode 100644
index 00000000000..37339598e35
--- /dev/null
+++ b/home-manager/tests/modules/programs/zsh/default.nix
@@ -0,0 +1,7 @@
+{
+ zsh-session-variables = ./session-variables.nix;
+ zsh-history-path-new-default = ./history-path-new-default.nix;
+ zsh-history-path-new-custom = ./history-path-new-custom.nix;
+ zsh-history-path-old-default = ./history-path-old-default.nix;
+ zsh-history-path-old-custom = ./history-path-old-custom.nix;
+}
diff --git a/home-manager/tests/modules/programs/zsh/history-path-new-custom.nix b/home-manager/tests/modules/programs/zsh/history-path-new-custom.nix
new file mode 100644
index 00000000000..0c052d6949e
--- /dev/null
+++ b/home-manager/tests/modules/programs/zsh/history-path-new-custom.nix
@@ -0,0 +1,20 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ home.stateVersion = "20.03";
+ programs.zsh = {
+ enable = true;
+ history.path = "$HOME/some/directory/zsh_history";
+ };
+
+ nixpkgs.overlays =
+ [ (self: super: { zsh = pkgs.writeScriptBin "dummy-zsh" ""; }) ];
+
+ nmt.script = ''
+ assertFileRegex home-files/.zshrc '^HISTFILE="$HOME/some/directory/zsh_history"$'
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/zsh/history-path-new-default.nix b/home-manager/tests/modules/programs/zsh/history-path-new-default.nix
new file mode 100644
index 00000000000..6d1f58a29dc
--- /dev/null
+++ b/home-manager/tests/modules/programs/zsh/history-path-new-default.nix
@@ -0,0 +1,17 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ home.stateVersion = "20.03";
+ programs.zsh.enable = true;
+
+ nixpkgs.overlays =
+ [ (self: super: { zsh = pkgs.writeScriptBin "dummy-zsh" ""; }) ];
+
+ nmt.script = ''
+ assertFileRegex home-files/.zshrc '^HISTFILE="$HOME/.zsh_history"$'
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/zsh/history-path-old-custom.nix b/home-manager/tests/modules/programs/zsh/history-path-old-custom.nix
new file mode 100644
index 00000000000..f5b178b5e97
--- /dev/null
+++ b/home-manager/tests/modules/programs/zsh/history-path-old-custom.nix
@@ -0,0 +1,20 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ home.stateVersion = "19.09";
+ programs.zsh = {
+ enable = true;
+ history.path = "some/directory/zsh_history";
+ };
+
+ nixpkgs.overlays =
+ [ (self: super: { zsh = pkgs.writeScriptBin "dummy-zsh" ""; }) ];
+
+ nmt.script = ''
+ assertFileRegex home-files/.zshrc '^HISTFILE="$HOME/some/directory/zsh_history"$'
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/zsh/history-path-old-default.nix b/home-manager/tests/modules/programs/zsh/history-path-old-default.nix
new file mode 100644
index 00000000000..d880d966454
--- /dev/null
+++ b/home-manager/tests/modules/programs/zsh/history-path-old-default.nix
@@ -0,0 +1,17 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ home.stateVersion = "19.03";
+ programs.zsh.enable = true;
+
+ nixpkgs.overlays =
+ [ (self: super: { zsh = pkgs.writeScriptBin "dummy-zsh" ""; }) ];
+
+ nmt.script = ''
+ assertFileRegex home-files/.zshrc '^HISTFILE="$HOME/.zsh_history"$'
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/programs/zsh/session-variables.nix b/home-manager/tests/modules/programs/zsh/session-variables.nix
new file mode 100644
index 00000000000..ca903619d68
--- /dev/null
+++ b/home-manager/tests/modules/programs/zsh/session-variables.nix
@@ -0,0 +1,28 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ programs.zsh = {
+ enable = true;
+
+ sessionVariables = {
+ V1 = "v1";
+ V2 = "v2-${config.programs.zsh.sessionVariables.V1}";
+ };
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ zsh = pkgs.writeScriptBin "dummy-zsh" "";
+ })
+ ];
+
+ nmt.script = ''
+ assertFileExists home-files/.zshrc
+ assertFileRegex home-files/.zshrc 'export V1="v1"'
+ assertFileRegex home-files/.zshrc 'export V2="v2-v1"'
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/services/dropbox/basic-configuration.nix b/home-manager/tests/modules/services/dropbox/basic-configuration.nix
new file mode 100644
index 00000000000..96a17cd7384
--- /dev/null
+++ b/home-manager/tests/modules/services/dropbox/basic-configuration.nix
@@ -0,0 +1,25 @@
+{ config, pkgs, ... }:
+
+{
+ config = {
+ services.dropbox = {
+ enable = true;
+ path = "${config.home.homeDirectory}/dropbox";
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ dropbox-cli = pkgs.writeScriptBin "dummy-dropbox-cli" "" // {
+ outPath = "@dropbox-cli@";
+ };
+ })
+ ];
+
+ nmt.script = ''
+ serviceFile=home-files/.config/systemd/user/dropbox.service
+
+ assertFileExists $serviceFile
+ '';
+
+ };
+}
diff --git a/home-manager/tests/modules/services/dropbox/default.nix b/home-manager/tests/modules/services/dropbox/default.nix
new file mode 100644
index 00000000000..ad519790355
--- /dev/null
+++ b/home-manager/tests/modules/services/dropbox/default.nix
@@ -0,0 +1 @@
+{ dropbox-basic-configuration = ./basic-configuration.nix; }
diff --git a/home-manager/tests/modules/services/emacs/default.nix b/home-manager/tests/modules/services/emacs/default.nix
new file mode 100644
index 00000000000..af27538d99d
--- /dev/null
+++ b/home-manager/tests/modules/services/emacs/default.nix
@@ -0,0 +1,5 @@
+{
+ emacs-service = ./emacs-service.nix;
+ emacs-socket-26 = ./emacs-socket-26.nix;
+ emacs-socket-27 = ./emacs-socket-27.nix;
+}
diff --git a/home-manager/tests/modules/services/emacs/emacs-emacsclient.desktop b/home-manager/tests/modules/services/emacs/emacs-emacsclient.desktop
new file mode 100644
index 00000000000..ab9849bb6b9
--- /dev/null
+++ b/home-manager/tests/modules/services/emacs/emacs-emacsclient.desktop
@@ -0,0 +1,12 @@
+[Desktop Entry]
+Type=Application
+Exec=@emacs@/bin/emacsclient -c %F
+Terminal=false
+Name=Emacs Client
+Icon=emacs
+Comment=Edit text
+GenericName=Text Editor
+MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;
+Categories=Utility;TextEditor;
+StartupWMClass=Emacs
+
diff --git a/home-manager/tests/modules/services/emacs/emacs-service-emacs.service b/home-manager/tests/modules/services/emacs/emacs-service-emacs.service
new file mode 100644
index 00000000000..d8a618a2671
--- /dev/null
+++ b/home-manager/tests/modules/services/emacs/emacs-service-emacs.service
@@ -0,0 +1,12 @@
+[Install]
+WantedBy=default.target
+
+[Service]
+ExecStart=@runtimeShell@ -l -c "@emacs@/bin/emacs --fg-daemon"
+ExecStop=@emacs@/bin/emacsclient --eval '(kill-emacs 0)'
+Restart=on-failure
+
+[Unit]
+Description=Emacs: the extensible, self-documenting text editor
+Documentation=info:emacs man:emacs(1) https://gnu.org/software/emacs/
+X-RestartIfChanged=false
diff --git a/home-manager/tests/modules/services/emacs/emacs-service.nix b/home-manager/tests/modules/services/emacs/emacs-service.nix
new file mode 100644
index 00000000000..be27e9ab33d
--- /dev/null
+++ b/home-manager/tests/modules/services/emacs/emacs-service.nix
@@ -0,0 +1,37 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ nixpkgs.overlays = [
+ (self: super: rec {
+ emacs = pkgs.writeShellScriptBin "dummy-emacs" "" // {
+ outPath = "@emacs@";
+ };
+ emacsPackagesFor = _:
+ makeScope super.newScope (_: { emacsWithPackages = _: emacs; });
+ })
+ ];
+
+ programs.emacs.enable = true;
+ services.emacs.enable = true;
+ services.emacs.client.enable = true;
+
+ nmt.script = ''
+ assertPathNotExists home-files/.config/systemd/user/emacs.socket
+ assertFileExists home-files/.config/systemd/user/emacs.service
+ assertFileExists home-path/share/applications/emacsclient.desktop
+
+ assertFileContent home-files/.config/systemd/user/emacs.service \
+ ${
+ pkgs.substituteAll {
+ inherit (pkgs) runtimeShell;
+ src = ./emacs-service-emacs.service;
+ }
+ }
+ assertFileContent home-path/share/applications/emacsclient.desktop \
+ ${./emacs-emacsclient.desktop}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/services/emacs/emacs-socket-26-emacs.service b/home-manager/tests/modules/services/emacs/emacs-socket-26-emacs.service
new file mode 100644
index 00000000000..2d731c7ee1a
--- /dev/null
+++ b/home-manager/tests/modules/services/emacs/emacs-socket-26-emacs.service
@@ -0,0 +1,9 @@
+[Service]
+ExecStart=@runtimeShell@ -l -c "@emacs@/bin/emacs --fg-daemon='%T/emacs%U/server'"
+ExecStop=@emacs@/bin/emacsclient --eval '(kill-emacs 0)'
+Restart=on-failure
+
+[Unit]
+Description=Emacs: the extensible, self-documenting text editor
+Documentation=info:emacs man:emacs(1) https://gnu.org/software/emacs/
+X-RestartIfChanged=false
diff --git a/home-manager/tests/modules/services/emacs/emacs-socket-26-emacs.socket b/home-manager/tests/modules/services/emacs/emacs-socket-26-emacs.socket
new file mode 100644
index 00000000000..d2fa78e2265
--- /dev/null
+++ b/home-manager/tests/modules/services/emacs/emacs-socket-26-emacs.socket
@@ -0,0 +1,12 @@
+[Install]
+WantedBy=sockets.target
+
+[Socket]
+DirectoryMode=0700
+FileDescriptorName=server
+ListenStream=%T/emacs%U/server
+SocketMode=0600
+
+[Unit]
+Description=Emacs: the extensible, self-documenting text editor
+Documentation=info:emacs man:emacs(1) https://gnu.org/software/emacs/
diff --git a/home-manager/tests/modules/services/emacs/emacs-socket-26.nix b/home-manager/tests/modules/services/emacs/emacs-socket-26.nix
new file mode 100644
index 00000000000..65f06159e4c
--- /dev/null
+++ b/home-manager/tests/modules/services/emacs/emacs-socket-26.nix
@@ -0,0 +1,40 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ nixpkgs.overlays = [
+ (self: super: rec {
+ emacs = pkgs.writeShellScriptBin "dummy-emacs-26.3" "" // {
+ outPath = "@emacs@";
+ };
+ emacsPackagesFor = _:
+ makeScope super.newScope (_: { emacsWithPackages = _: emacs; });
+ })
+ ];
+
+ programs.emacs.enable = true;
+ services.emacs.enable = true;
+ services.emacs.client.enable = true;
+ services.emacs.socketActivation.enable = true;
+
+ nmt.script = ''
+ assertFileExists home-files/.config/systemd/user/emacs.socket
+ assertFileExists home-files/.config/systemd/user/emacs.service
+ assertFileExists home-path/share/applications/emacsclient.desktop
+
+ assertFileContent home-files/.config/systemd/user/emacs.socket \
+ ${./emacs-socket-26-emacs.socket}
+ assertFileContent home-files/.config/systemd/user/emacs.service \
+ ${
+ pkgs.substituteAll {
+ inherit (pkgs) runtimeShell;
+ src = ./emacs-socket-26-emacs.service;
+ }
+ }
+ assertFileContent home-path/share/applications/emacsclient.desktop \
+ ${./emacs-emacsclient.desktop}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/services/emacs/emacs-socket-27-emacs.service b/home-manager/tests/modules/services/emacs/emacs-socket-27-emacs.service
new file mode 100644
index 00000000000..408a5d24b5c
--- /dev/null
+++ b/home-manager/tests/modules/services/emacs/emacs-socket-27-emacs.service
@@ -0,0 +1,9 @@
+[Service]
+ExecStart=@runtimeShell@ -l -c "@emacs@/bin/emacs --fg-daemon='%t/emacs/server'"
+ExecStop=@emacs@/bin/emacsclient --eval '(kill-emacs 0)'
+Restart=on-failure
+
+[Unit]
+Description=Emacs: the extensible, self-documenting text editor
+Documentation=info:emacs man:emacs(1) https://gnu.org/software/emacs/
+X-RestartIfChanged=false
diff --git a/home-manager/tests/modules/services/emacs/emacs-socket-27-emacs.socket b/home-manager/tests/modules/services/emacs/emacs-socket-27-emacs.socket
new file mode 100644
index 00000000000..8fa68bf5911
--- /dev/null
+++ b/home-manager/tests/modules/services/emacs/emacs-socket-27-emacs.socket
@@ -0,0 +1,12 @@
+[Install]
+WantedBy=sockets.target
+
+[Socket]
+DirectoryMode=0700
+FileDescriptorName=server
+ListenStream=%t/emacs/server
+SocketMode=0600
+
+[Unit]
+Description=Emacs: the extensible, self-documenting text editor
+Documentation=info:emacs man:emacs(1) https://gnu.org/software/emacs/
diff --git a/home-manager/tests/modules/services/emacs/emacs-socket-27.nix b/home-manager/tests/modules/services/emacs/emacs-socket-27.nix
new file mode 100644
index 00000000000..213dedca51c
--- /dev/null
+++ b/home-manager/tests/modules/services/emacs/emacs-socket-27.nix
@@ -0,0 +1,42 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+in {
+ config = {
+ nixpkgs.overlays = [
+ (self: super: rec {
+ emacs = pkgs.writeShellScriptBin "dummy-emacs-27.0.91" "" // {
+ outPath = "@emacs@";
+ };
+ emacsPackagesFor = _:
+ makeScope super.newScope (_: { emacsWithPackages = _: emacs; });
+ })
+ ];
+
+ programs.emacs.enable = true;
+ services.emacs.enable = true;
+ services.emacs.client.enable = true;
+ services.emacs.socketActivation.enable = true;
+
+ nmt.script = ''
+ assertFileExists home-files/.config/systemd/user/emacs.socket
+ assertFileExists home-files/.config/systemd/user/emacs.service
+ assertFileExists home-path/share/applications/emacsclient.desktop
+
+ assertFileContent home-files/.config/systemd/user/emacs.socket \
+ ${./emacs-socket-27-emacs.socket}
+ assertFileContent home-files/.config/systemd/user/emacs.service \
+ ${
+ pkgs.substituteAll {
+ inherit (pkgs) runtimeShell;
+ src = ./emacs-socket-27-emacs.service;
+ }
+ }
+ assertFileContent home-path/share/applications/emacsclient.desktop \
+ ${./emacs-emacsclient.desktop}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/services/fluidsynth/default.nix b/home-manager/tests/modules/services/fluidsynth/default.nix
new file mode 100644
index 00000000000..58e9c5dcc33
--- /dev/null
+++ b/home-manager/tests/modules/services/fluidsynth/default.nix
@@ -0,0 +1 @@
+{ fluidsynth = import ./service.nix; }
diff --git a/home-manager/tests/modules/services/fluidsynth/service.nix b/home-manager/tests/modules/services/fluidsynth/service.nix
new file mode 100644
index 00000000000..8d53e75c032
--- /dev/null
+++ b/home-manager/tests/modules/services/fluidsynth/service.nix
@@ -0,0 +1,24 @@
+{ config, pkgs, ... }: {
+ config = {
+ services.fluidsynth.enable = true;
+ services.fluidsynth.soundFont = "/path/to/soundFont";
+ services.fluidsynth.extraOptions = [ "--sample-rate 96000" ];
+
+ nixpkgs.overlays = [
+ (self: super: {
+ fluidsynth = pkgs.writeScriptBin "dummy-fluidsynth" "" // {
+ outPath = "@fluidsynth@";
+ };
+ })
+ ];
+
+ nmt.script = ''
+ serviceFile=home-files/.config/systemd/user/fluidsynth.service
+
+ assertFileExists $serviceFile
+
+ assertFileContains $serviceFile \
+ 'ExecStart=@fluidsynth@/bin/fluidsynth -a pulseaudio -si --sample-rate 96000 /path/to/soundFont'
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/services/kanshi/basic-configuration.conf b/home-manager/tests/modules/services/kanshi/basic-configuration.conf
new file mode 100644
index 00000000000..9d6442b985b
--- /dev/null
+++ b/home-manager/tests/modules/services/kanshi/basic-configuration.conf
@@ -0,0 +1,15 @@
+profile desktop {
+ output "eDP-1" disable
+ output "Iiyama North America PLE2483H-DP" enable position 0,0
+ output "Iiyama North America PLE2483H-DP 1158765348486" enable mode 1920x1080 position 1920,0 scale 2.100000 transform flipped-270
+ exec echo "1 two 3"
+}
+
+profile nomad {
+ output "eDP-1" enable
+}
+
+profile test {
+ output "*" enable
+}
+
diff --git a/home-manager/tests/modules/services/kanshi/basic-configuration.nix b/home-manager/tests/modules/services/kanshi/basic-configuration.nix
new file mode 100644
index 00000000000..15fbbb9ceb1
--- /dev/null
+++ b/home-manager/tests/modules/services/kanshi/basic-configuration.nix
@@ -0,0 +1,52 @@
+{ config, pkgs, ... }: {
+ config = {
+ services.kanshi = {
+ enable = true;
+ package = pkgs.writeScriptBin "dummy-kanshi" "";
+ profiles = {
+ nomad = {
+ outputs = [{
+ criteria = "eDP-1";
+ status = "enable";
+ }];
+ };
+ desktop = {
+ exec = ''echo "1 two 3"'';
+ outputs = [
+ {
+ criteria = "eDP-1";
+ status = "disable";
+ }
+ {
+ criteria = "Iiyama North America PLE2483H-DP";
+ status = "enable";
+ position = "0,0";
+ }
+ {
+ criteria = "Iiyama North America PLE2483H-DP 1158765348486";
+ status = "enable";
+ position = "1920,0";
+ scale = 2.1;
+ mode = "1920x1080";
+ transform = "flipped-270";
+ }
+ ];
+ };
+ };
+ extraConfig = ''
+ profile test {
+ output "*" enable
+ }
+ '';
+ };
+
+ nmt.script = ''
+ serviceFile=home-files/.config/systemd/user/kanshi.service
+ assertFileExists $serviceFile
+
+ assertFileExists home-files/.config/kanshi/config
+ assertFileContent home-files/.config/kanshi/config \
+ ${./basic-configuration.conf}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/services/kanshi/default.nix b/home-manager/tests/modules/services/kanshi/default.nix
new file mode 100644
index 00000000000..cb6b2a6b79f
--- /dev/null
+++ b/home-manager/tests/modules/services/kanshi/default.nix
@@ -0,0 +1 @@
+{ kanshi-basic-configuration = ./basic-configuration.nix; }
diff --git a/home-manager/tests/modules/services/lieer/default.nix b/home-manager/tests/modules/services/lieer/default.nix
new file mode 100644
index 00000000000..1d6b435a1ca
--- /dev/null
+++ b/home-manager/tests/modules/services/lieer/default.nix
@@ -0,0 +1 @@
+{ lieer-service = ./lieer-service.nix; }
diff --git a/home-manager/tests/modules/services/lieer/lieer-service-expected.service b/home-manager/tests/modules/services/lieer/lieer-service-expected.service
new file mode 100644
index 00000000000..1110e85c475
--- /dev/null
+++ b/home-manager/tests/modules/services/lieer/lieer-service-expected.service
@@ -0,0 +1,8 @@
+[Service]
+ExecStart=@lieer@/bin/gmi sync
+Type=oneshot
+WorkingDirectory=/home/hm-user/Mail/hm@example.com
+
+[Unit]
+ConditionPathExists=/home/hm-user/Mail/hm@example.com/.gmailieer.json
+Description=lieer Gmail synchronization for hm@example.com
diff --git a/home-manager/tests/modules/services/lieer/lieer-service-expected.timer b/home-manager/tests/modules/services/lieer/lieer-service-expected.timer
new file mode 100644
index 00000000000..cb059ea47c4
--- /dev/null
+++ b/home-manager/tests/modules/services/lieer/lieer-service-expected.timer
@@ -0,0 +1,9 @@
+[Install]
+WantedBy=timers.target
+
+[Timer]
+OnCalendar=*:0/5
+RandomizedDelaySec=30
+
+[Unit]
+Description=lieer Gmail synchronization for hm@example.com
diff --git a/home-manager/tests/modules/services/lieer/lieer-service.nix b/home-manager/tests/modules/services/lieer/lieer-service.nix
new file mode 100644
index 00000000000..03dcdc749b1
--- /dev/null
+++ b/home-manager/tests/modules/services/lieer/lieer-service.nix
@@ -0,0 +1,34 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ imports = [ ../../accounts/email-test-accounts.nix ];
+
+ config = {
+ services.lieer.enable = true;
+
+ accounts.email.accounts = {
+ "hm@example.com".lieer.enable = true;
+ "hm@example.com".lieer.sync.enable = true;
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ gmailieer = pkgs.writeScriptBin "dummy-gmailieer" "" // {
+ outPath = "@lieer@";
+ };
+ })
+ ];
+
+ nmt.script = ''
+ assertFileExists home-files/.config/systemd/user/lieer-hm-example-com.service
+ assertFileExists home-files/.config/systemd/user/lieer-hm-example-com.timer
+
+ assertFileContent home-files/.config/systemd/user/lieer-hm-example-com.service \
+ ${./lieer-service-expected.service}
+ assertFileContent home-files/.config/systemd/user/lieer-hm-example-com.timer \
+ ${./lieer-service-expected.timer}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/services/polybar/basic-configuration.conf b/home-manager/tests/modules/services/polybar/basic-configuration.conf
new file mode 100644
index 00000000000..54448a705fc
--- /dev/null
+++ b/home-manager/tests/modules/services/polybar/basic-configuration.conf
@@ -0,0 +1,21 @@
+[bar/top]
+height=3%
+modules-center=date
+monitor=${env:MONITOR:eDP1}
+radius=0
+width=100%
+
+[module/date]
+date=%d.%m.%y
+internal=5
+label=%time% %date%
+time=%H:%M
+type=internal/date
+
+[module/date]
+type = internal/date
+interval = 5
+date = "%d.%m.%y"
+time = %H:%M
+format-prefix-foreground = ${colors.foreground-alt}
+label = %time% %date%
diff --git a/home-manager/tests/modules/services/polybar/basic-configuration.nix b/home-manager/tests/modules/services/polybar/basic-configuration.nix
new file mode 100644
index 00000000000..a8886dab6d5
--- /dev/null
+++ b/home-manager/tests/modules/services/polybar/basic-configuration.nix
@@ -0,0 +1,48 @@
+{ config, pkgs, ... }:
+
+{
+ config = {
+ services.polybar = {
+ enable = true;
+ package = pkgs.writeScriptBin "dummy-polybar" "";
+ script = "polybar bar &";
+ config = {
+ "bar/top" = {
+ monitor = "\${env:MONITOR:eDP1}";
+ width = "100%";
+ height = "3%";
+ radius = 0;
+ modules-center = "date";
+ };
+ "module/date" = {
+ type = "internal/date";
+ internal = 5;
+ date = "%d.%m.%y";
+ time = "%H:%M";
+ label = "%time% %date%";
+ };
+ };
+ extraConfig = ''
+ [module/date]
+ type = internal/date
+ interval = 5
+ date = "%d.%m.%y"
+ time = %H:%M
+ format-prefix-foreground = ''${colors.foreground-alt}
+ label = %time% %date%
+ '';
+ };
+
+ nmt.script = ''
+ serviceFile=home-files/.config/systemd/user/polybar.service
+
+ assertFileExists $serviceFile
+ assertFileRegex $serviceFile 'X-Restart-Triggers=.*polybar\.conf'
+ assertFileRegex $serviceFile 'ExecStart=.*/bin/polybar-start'
+
+ assertFileExists home-files/.config/polybar/config
+ assertFileContent home-files/.config/polybar/config \
+ ${./basic-configuration.conf}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/services/polybar/default.nix b/home-manager/tests/modules/services/polybar/default.nix
new file mode 100644
index 00000000000..94d5d3cde20
--- /dev/null
+++ b/home-manager/tests/modules/services/polybar/default.nix
@@ -0,0 +1 @@
+{ polybar-basic-configuration = ./basic-configuration.nix; }
diff --git a/home-manager/tests/modules/services/sxhkd/configuration.nix b/home-manager/tests/modules/services/sxhkd/configuration.nix
new file mode 100644
index 00000000000..03206a8d52b
--- /dev/null
+++ b/home-manager/tests/modules/services/sxhkd/configuration.nix
@@ -0,0 +1,33 @@
+{ config, pkgs, ... }: {
+ config = {
+ services.sxhkd = {
+ enable = true;
+
+ keybindings = {
+ "super + a" = "run command a";
+ "super + b" = null;
+ "super + Shift + b" = "run command b";
+ };
+
+ extraConfig = ''
+ super + c
+ call command c
+
+ # comment
+ super + d
+ call command d
+ '';
+ };
+
+ nixpkgs.overlays =
+ [ (self: super: { sxhkd = pkgs.writeScriptBin "dummy-sxhkd" ""; }) ];
+
+ nmt.script = ''
+ sxhkdrc=home-files/.config/sxhkd/sxhkdrc
+
+ assertFileExists $sxhkdrc
+
+ assertFileContent $sxhkdrc ${./sxhkdrc}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/services/sxhkd/default.nix b/home-manager/tests/modules/services/sxhkd/default.nix
new file mode 100644
index 00000000000..ec25252cee0
--- /dev/null
+++ b/home-manager/tests/modules/services/sxhkd/default.nix
@@ -0,0 +1,4 @@
+{
+ sxhkd-configuration = ./configuration.nix;
+ sxhkd-service = ./service.nix;
+}
diff --git a/home-manager/tests/modules/services/sxhkd/service.nix b/home-manager/tests/modules/services/sxhkd/service.nix
new file mode 100644
index 00000000000..9b4fd70cc55
--- /dev/null
+++ b/home-manager/tests/modules/services/sxhkd/service.nix
@@ -0,0 +1,20 @@
+{ config, ... }:
+{
+ config = {
+ services.sxhkd = {
+ enable = true;
+ extraPath = "/home/the-user/bin:/extra/path/bin";
+ };
+
+ nmt.script = ''
+ serviceFile=home-files/.config/systemd/user/sxhkd.service
+
+ assertFileExists $serviceFile
+
+ assertFileRegex $serviceFile 'ExecStart=.*/bin/sxhkd'
+
+ assertFileRegex $serviceFile \
+ 'Environment=PATH=.*\.nix-profile/bin:/home/the-user/bin:/extra/path/bin'
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/services/sxhkd/sxhkdrc b/home-manager/tests/modules/services/sxhkd/sxhkdrc
new file mode 100644
index 00000000000..c8883464b29
--- /dev/null
+++ b/home-manager/tests/modules/services/sxhkd/sxhkdrc
@@ -0,0 +1,13 @@
+super + Shift + b
+ run command b
+
+super + a
+ run command a
+
+
+super + c
+ call command c
+
+# comment
+super + d
+ call command d
diff --git a/home-manager/tests/modules/services/window-managers/i3/default.nix b/home-manager/tests/modules/services/window-managers/i3/default.nix
new file mode 100644
index 00000000000..c523dfcd04b
--- /dev/null
+++ b/home-manager/tests/modules/services/window-managers/i3/default.nix
@@ -0,0 +1,4 @@
+{
+ i3-followmouse = ./i3-followmouse.nix;
+ i3-keybindings = ./i3-keybindings.nix;
+}
diff --git a/home-manager/tests/modules/services/window-managers/i3/i3-followmouse-expected.conf b/home-manager/tests/modules/services/window-managers/i3/i3-followmouse-expected.conf
new file mode 100644
index 00000000000..729605be469
--- /dev/null
+++ b/home-manager/tests/modules/services/window-managers/i3/i3-followmouse-expected.conf
@@ -0,0 +1,105 @@
+font pango:monospace 8
+floating_modifier Mod1
+new_window normal 2
+new_float normal 2
+hide_edge_borders none
+force_focus_wrapping no
+focus_follows_mouse no
+focus_on_window_activation smart
+mouse_warping output
+workspace_layout default
+workspace_auto_back_and_forth no
+
+client.focused #4c7899 #285577 #ffffff #2e9ef4 #285577
+client.focused_inactive #333333 #5f676a #ffffff #484e50 #5f676a
+client.unfocused #333333 #222222 #888888 #292d2e #222222
+client.urgent #2f343a #900000 #ffffff #900000 #900000
+client.placeholder #000000 #0c0c0c #ffffff #000000 #0c0c0c
+client.background #ffffff
+
+bindsym Mod1+0 workspace number 10
+bindsym Mod1+1 workspace number 1
+bindsym Mod1+2 workspace number 2
+bindsym Mod1+3 workspace number 3
+bindsym Mod1+4 workspace number 4
+bindsym Mod1+5 workspace number 5
+bindsym Mod1+6 workspace number 6
+bindsym Mod1+7 workspace number 7
+bindsym Mod1+8 workspace number 8
+bindsym Mod1+9 workspace number 9
+bindsym Mod1+Down focus down
+bindsym Mod1+Left focus left
+bindsym Mod1+Return exec i3-sensible-terminal
+bindsym Mod1+Right focus right
+bindsym Mod1+Shift+0 move container to workspace number 10
+bindsym Mod1+Shift+1 move container to workspace number 1
+bindsym Mod1+Shift+2 move container to workspace number 2
+bindsym Mod1+Shift+3 move container to workspace number 3
+bindsym Mod1+Shift+4 move container to workspace number 4
+bindsym Mod1+Shift+5 move container to workspace number 5
+bindsym Mod1+Shift+6 move container to workspace number 6
+bindsym Mod1+Shift+7 move container to workspace number 7
+bindsym Mod1+Shift+8 move container to workspace number 8
+bindsym Mod1+Shift+9 move container to workspace number 9
+bindsym Mod1+Shift+Down move down
+bindsym Mod1+Shift+Left move left
+bindsym Mod1+Shift+Right move right
+bindsym Mod1+Shift+Up move up
+bindsym Mod1+Shift+c reload
+bindsym Mod1+Shift+e exec i3-nagbar -t warning -m 'Do you want to exit i3?' -b 'Yes' 'i3-msg exit'
+bindsym Mod1+Shift+minus move scratchpad
+bindsym Mod1+Shift+q kill
+bindsym Mod1+Shift+r restart
+bindsym Mod1+Shift+space floating toggle
+bindsym Mod1+Up focus up
+bindsym Mod1+a focus parent
+bindsym Mod1+d exec @dmenu@/bin/dmenu_run
+bindsym Mod1+e layout toggle split
+bindsym Mod1+f fullscreen toggle
+bindsym Mod1+h split h
+bindsym Mod1+minus scratchpad show
+bindsym Mod1+r mode resize
+bindsym Mod1+s layout stacking
+bindsym Mod1+space focus mode_toggle
+bindsym Mod1+v split v
+bindsym Mod1+w layout tabbed
+
+mode "resize" {
+bindsym Down resize grow height 10 px or 10 ppt
+bindsym Escape mode default
+bindsym Left resize shrink width 10 px or 10 ppt
+bindsym Return mode default
+bindsym Right resize grow width 10 px or 10 ppt
+bindsym Up resize shrink height 10 px or 10 ppt
+}
+
+
+bar {
+
+ font pango:monospace 8
+ mode dock
+ hidden_state hide
+ position bottom
+ status_command @i3status@/bin/i3status
+ i3bar_command @i3@/bin/i3bar
+ workspace_buttons yes
+ strip_workspace_numbers no
+ tray_output primary
+ colors {
+ background #000000
+ statusline #ffffff
+ separator #666666
+ focused_workspace #4c7899 #285577 #ffffff
+ active_workspace #333333 #5f676a #ffffff
+ inactive_workspace #333333 #222222 #888888
+ urgent_workspace #2f343a #900000 #ffffff
+ binding_mode #2f343a #900000 #ffffff
+ }
+
+}
+
+
+
+
+
+
diff --git a/home-manager/tests/modules/services/window-managers/i3/i3-followmouse.nix b/home-manager/tests/modules/services/window-managers/i3/i3-followmouse.nix
new file mode 100644
index 00000000000..8d51e348877
--- /dev/null
+++ b/home-manager/tests/modules/services/window-managers/i3/i3-followmouse.nix
@@ -0,0 +1,29 @@
+{ config, lib, ... }:
+
+with lib;
+
+{
+ config = {
+ xsession.windowManager.i3 = {
+ enable = true;
+
+ config.focus.followMouse = false;
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ dmenu = super.dmenu // { outPath = "@dmenu@"; };
+
+ i3 = super.i3 // { outPath = "@i3@"; };
+
+ i3status = super.i3status // { outPath = "@i3status@"; };
+ })
+ ];
+
+ nmt.script = ''
+ assertFileExists home-files/.config/i3/config
+ assertFileContent home-files/.config/i3/config \
+ ${./i3-followmouse-expected.conf}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/services/window-managers/i3/i3-keybindings-expected.conf b/home-manager/tests/modules/services/window-managers/i3/i3-keybindings-expected.conf
new file mode 100644
index 00000000000..1e385e8c734
--- /dev/null
+++ b/home-manager/tests/modules/services/window-managers/i3/i3-keybindings-expected.conf
@@ -0,0 +1,106 @@
+font pango:monospace 8
+floating_modifier Mod1
+new_window normal 2
+new_float normal 2
+hide_edge_borders none
+force_focus_wrapping no
+focus_follows_mouse yes
+focus_on_window_activation smart
+mouse_warping output
+workspace_layout default
+workspace_auto_back_and_forth no
+
+client.focused #4c7899 #285577 #ffffff #2e9ef4 #285577
+client.focused_inactive #333333 #5f676a #ffffff #484e50 #5f676a
+client.unfocused #333333 #222222 #888888 #292d2e #222222
+client.urgent #2f343a #900000 #ffffff #900000 #900000
+client.placeholder #000000 #0c0c0c #ffffff #000000 #0c0c0c
+client.background #ffffff
+
+bindsym Mod1+0 workspace number 10
+bindsym Mod1+1 workspace number 1
+bindsym Mod1+2 workspace number 2
+bindsym Mod1+3 workspace number 3
+bindsym Mod1+4 workspace number 4
+bindsym Mod1+5 workspace number 5
+bindsym Mod1+6 workspace number 6
+bindsym Mod1+7 workspace number 7
+bindsym Mod1+8 workspace number 8
+bindsym Mod1+9 workspace number 9
+bindsym Mod1+Down focus down
+bindsym Mod1+Invented invented-key-command
+bindsym Mod1+Left overridden-command
+bindsym Mod1+Return exec i3-sensible-terminal
+
+bindsym Mod1+Shift+0 move container to workspace number 10
+bindsym Mod1+Shift+1 move container to workspace number 1
+bindsym Mod1+Shift+2 move container to workspace number 2
+bindsym Mod1+Shift+3 move container to workspace number 3
+bindsym Mod1+Shift+4 move container to workspace number 4
+bindsym Mod1+Shift+5 move container to workspace number 5
+bindsym Mod1+Shift+6 move container to workspace number 6
+bindsym Mod1+Shift+7 move container to workspace number 7
+bindsym Mod1+Shift+8 move container to workspace number 8
+bindsym Mod1+Shift+9 move container to workspace number 9
+bindsym Mod1+Shift+Down move down
+bindsym Mod1+Shift+Left move left
+bindsym Mod1+Shift+Right move right
+bindsym Mod1+Shift+Up move up
+bindsym Mod1+Shift+c reload
+bindsym Mod1+Shift+e exec i3-nagbar -t warning -m 'Do you want to exit i3?' -b 'Yes' 'i3-msg exit'
+bindsym Mod1+Shift+minus move scratchpad
+bindsym Mod1+Shift+q kill
+bindsym Mod1+Shift+r restart
+bindsym Mod1+Shift+space floating toggle
+bindsym Mod1+Up focus up
+bindsym Mod1+a focus parent
+bindsym Mod1+d exec @dmenu@/bin/dmenu_run
+bindsym Mod1+e layout toggle split
+bindsym Mod1+f fullscreen toggle
+bindsym Mod1+h split h
+bindsym Mod1+minus scratchpad show
+bindsym Mod1+r mode resize
+bindsym Mod1+s layout stacking
+bindsym Mod1+space focus mode_toggle
+bindsym Mod1+v split v
+bindsym Mod1+w layout tabbed
+
+mode "resize" {
+bindsym Down resize grow height 10 px or 10 ppt
+bindsym Escape mode default
+bindsym Left resize shrink width 10 px or 10 ppt
+bindsym Return mode default
+bindsym Right resize grow width 10 px or 10 ppt
+bindsym Up resize shrink height 10 px or 10 ppt
+}
+
+
+bar {
+
+ font pango:monospace 8
+ mode dock
+ hidden_state hide
+ position bottom
+ status_command @i3status@/bin/i3status
+ i3bar_command @i3@/bin/i3bar
+ workspace_buttons yes
+ strip_workspace_numbers no
+ tray_output primary
+ colors {
+ background #000000
+ statusline #ffffff
+ separator #666666
+ focused_workspace #4c7899 #285577 #ffffff
+ active_workspace #333333 #5f676a #ffffff
+ inactive_workspace #333333 #222222 #888888
+ urgent_workspace #2f343a #900000 #ffffff
+ binding_mode #2f343a #900000 #ffffff
+ }
+
+}
+
+
+
+
+
+
diff --git a/home-manager/tests/modules/services/window-managers/i3/i3-keybindings.nix b/home-manager/tests/modules/services/window-managers/i3/i3-keybindings.nix
new file mode 100644
index 00000000000..4f8515e61ff
--- /dev/null
+++ b/home-manager/tests/modules/services/window-managers/i3/i3-keybindings.nix
@@ -0,0 +1,35 @@
+{ config, lib, ... }:
+
+with lib;
+
+{
+ config = {
+ xsession.windowManager.i3 = {
+ enable = true;
+
+ config.keybindings =
+ let modifier = config.xsession.windowManager.i3.config.modifier;
+ in lib.mkOptionDefault {
+ "${modifier}+Left" = "overridden-command";
+ "${modifier}+Right" = null;
+ "${modifier}+Invented" = "invented-key-command";
+ };
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ dmenu = super.dmenu // { outPath = "@dmenu@"; };
+
+ i3 = super.i3 // { outPath = "@i3@"; };
+
+ i3status = super.i3status // { outPath = "@i3status@"; };
+ })
+ ];
+
+ nmt.script = ''
+ assertFileExists home-files/.config/i3/config
+ assertFileContent home-files/.config/i3/config \
+ ${./i3-keybindings-expected.conf}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/services/window-managers/sway/default.nix b/home-manager/tests/modules/services/window-managers/sway/default.nix
new file mode 100644
index 00000000000..b9c0ab5e099
--- /dev/null
+++ b/home-manager/tests/modules/services/window-managers/sway/default.nix
@@ -0,0 +1,6 @@
+{
+ sway-default = ./sway-default.nix;
+ sway-post-2003 = ./sway-post-2003.nix;
+ sway-followmouse = ./sway-followmouse.nix;
+ sway-followmouse-legacy = ./sway-followmouse-legacy.nix;
+}
diff --git a/home-manager/tests/modules/services/window-managers/sway/sway-default.conf b/home-manager/tests/modules/services/window-managers/sway/sway-default.conf
new file mode 100644
index 00000000000..da5b1f47eef
--- /dev/null
+++ b/home-manager/tests/modules/services/window-managers/sway/sway-default.conf
@@ -0,0 +1,117 @@
+font pango:monospace 8
+floating_modifier Mod1
+default_border pixel 2
+default_floating_border pixel 2
+hide_edge_borders none
+focus_wrapping no
+focus_follows_mouse yes
+focus_on_window_activation smart
+mouse_warping output
+workspace_layout default
+workspace_auto_back_and_forth no
+
+client.focused #4c7899 #285577 #ffffff #2e9ef4 #285577
+client.focused_inactive #333333 #5f676a #ffffff #484e50 #5f676a
+client.unfocused #333333 #222222 #888888 #292d2e #222222
+client.urgent #2f343a #900000 #ffffff #900000 #900000
+client.placeholder #000000 #0c0c0c #ffffff #000000 #0c0c0c
+client.background #ffffff
+
+bindsym Mod1+1 workspace number 1
+bindsym Mod1+2 workspace number 2
+bindsym Mod1+3 workspace number 3
+bindsym Mod1+4 workspace number 4
+bindsym Mod1+5 workspace number 5
+bindsym Mod1+6 workspace number 6
+bindsym Mod1+7 workspace number 7
+bindsym Mod1+8 workspace number 8
+bindsym Mod1+9 workspace number 9
+bindsym Mod1+Down focus down
+bindsym Mod1+Left focus left
+bindsym Mod1+Return exec @rxvt-unicode-unwrapped@/bin/urxvt
+bindsym Mod1+Right focus right
+bindsym Mod1+Shift+1 move container to workspace number 1
+bindsym Mod1+Shift+2 move container to workspace number 2
+bindsym Mod1+Shift+3 move container to workspace number 3
+bindsym Mod1+Shift+4 move container to workspace number 4
+bindsym Mod1+Shift+5 move container to workspace number 5
+bindsym Mod1+Shift+6 move container to workspace number 6
+bindsym Mod1+Shift+7 move container to workspace number 7
+bindsym Mod1+Shift+8 move container to workspace number 8
+bindsym Mod1+Shift+9 move container to workspace number 9
+bindsym Mod1+Shift+Down move down
+bindsym Mod1+Shift+Left move left
+bindsym Mod1+Shift+Right move right
+bindsym Mod1+Shift+Up move up
+bindsym Mod1+Shift+c reload
+bindsym Mod1+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'
+bindsym Mod1+Shift+h move left
+bindsym Mod1+Shift+j move down
+bindsym Mod1+Shift+k move up
+bindsym Mod1+Shift+l move right
+bindsym Mod1+Shift+minus move scratchpad
+bindsym Mod1+Shift+q kill
+bindsym Mod1+Shift+space floating toggle
+bindsym Mod1+Up focus up
+bindsym Mod1+a focus parent
+bindsym Mod1+b splith
+bindsym Mod1+d exec @dmenu@/bin/dmenu_run
+bindsym Mod1+e layout toggle split
+bindsym Mod1+f fullscreen toggle
+bindsym Mod1+h focus left
+bindsym Mod1+j focus down
+bindsym Mod1+k focus up
+bindsym Mod1+l focus right
+bindsym Mod1+minus scratchpad show
+bindsym Mod1+r mode resize
+bindsym Mod1+s layout stacking
+bindsym Mod1+space focus mode_toggle
+bindsym Mod1+v splitv
+bindsym Mod1+w layout tabbed
+
+
+
+mode "resize" {
+bindsym Down resize grow height 10 px
+bindsym Escape mode default
+bindsym Left resize shrink width 10 px
+bindsym Return mode default
+bindsym Right resize grow width 10 px
+bindsym Up resize shrink height 10 px
+bindsym h resize shrink width 10 px
+bindsym j resize grow height 10 px
+bindsym k resize shrink height 10 px
+bindsym l resize grow width 10 px
+}
+
+
+bar {
+
+ font pango:monospace 8
+ mode dock
+ hidden_state hide
+ position bottom
+ status_command @i3status@/bin/i3status
+ swaybar_command @sway/bin/swaybar
+ workspace_buttons yes
+ strip_workspace_numbers no
+ tray_output primary
+ colors {
+ background #000000
+ statusline #ffffff
+ separator #666666
+ focused_workspace #4c7899 #285577 #ffffff
+ active_workspace #333333 #5f676a #ffffff
+ inactive_workspace #333333 #222222 #888888
+ urgent_workspace #2f343a #900000 #ffffff
+ binding_mode #2f343a #900000 #ffffff
+ }
+
+}
+
+
+
+
+
+
+exec "systemctl --user import-environment; systemctl --user start sway-session.target"
diff --git a/home-manager/tests/modules/services/window-managers/sway/sway-default.nix b/home-manager/tests/modules/services/window-managers/sway/sway-default.nix
new file mode 100644
index 00000000000..09c388c1c51
--- /dev/null
+++ b/home-manager/tests/modules/services/window-managers/sway/sway-default.nix
@@ -0,0 +1,33 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ wayland.windowManager.sway = {
+ enable = true;
+ package = pkgs.runCommandLocal "dummy-package" { } "mkdir $out" // {
+ outPath = "@sway";
+ };
+ # overriding findutils causes issues
+ config.menu = "${pkgs.dmenu}/bin/dmenu_run";
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ dummy-package = super.runCommandLocal "dummy-package" { } "mkdir $out";
+ dmenu = self.dummy-package // { outPath = "@dmenu@"; };
+ rxvt-unicode-unwrapped = self.dummy-package // {
+ outPath = "@rxvt-unicode-unwrapped@";
+ };
+ i3status = self.dummy-package // { outPath = "@i3status@"; };
+ })
+ ];
+
+ nmt.script = ''
+ assertFileExists home-files/.config/sway/config
+ assertFileContent home-files/.config/sway/config \
+ ${./sway-default.conf}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/services/window-managers/sway/sway-followmouse-expected.conf b/home-manager/tests/modules/services/window-managers/sway/sway-followmouse-expected.conf
new file mode 100644
index 00000000000..198ce4bd37f
--- /dev/null
+++ b/home-manager/tests/modules/services/window-managers/sway/sway-followmouse-expected.conf
@@ -0,0 +1,94 @@
+font pango:monospace 8
+floating_modifier Mod1
+default_border pixel 2
+default_floating_border pixel 2
+hide_edge_borders none
+focus_wrapping no
+focus_follows_mouse always
+focus_on_window_activation smart
+mouse_warping output
+workspace_layout default
+workspace_auto_back_and_forth no
+
+client.focused #4c7899 #285577 #ffffff #2e9ef4 #285577
+client.focused_inactive #333333 #5f676a #ffffff #484e50 #5f676a
+client.unfocused #333333 #222222 #888888 #292d2e #222222
+client.urgent #2f343a #900000 #ffffff #900000 #900000
+client.placeholder #000000 #0c0c0c #ffffff #000000 #0c0c0c
+client.background #ffffff
+
+bindsym Mod1+1 workspace number 1
+bindsym Mod1+2 workspace number 2
+bindsym Mod1+3 workspace number 3
+bindsym Mod1+4 workspace number 4
+bindsym Mod1+5 workspace number 5
+bindsym Mod1+6 workspace number 6
+bindsym Mod1+7 workspace number 7
+bindsym Mod1+8 workspace number 8
+bindsym Mod1+9 workspace number 9
+bindsym Mod1+Down focus down
+bindsym Mod1+Left focus left
+bindsym Mod1+Return exec @rxvt-unicode-unwrapped@/bin/urxvt
+bindsym Mod1+Right focus right
+bindsym Mod1+Shift+1 move container to workspace number 1
+bindsym Mod1+Shift+2 move container to workspace number 2
+bindsym Mod1+Shift+3 move container to workspace number 3
+bindsym Mod1+Shift+4 move container to workspace number 4
+bindsym Mod1+Shift+5 move container to workspace number 5
+bindsym Mod1+Shift+6 move container to workspace number 6
+bindsym Mod1+Shift+7 move container to workspace number 7
+bindsym Mod1+Shift+8 move container to workspace number 8
+bindsym Mod1+Shift+9 move container to workspace number 9
+bindsym Mod1+Shift+Down move down
+bindsym Mod1+Shift+Left move left
+bindsym Mod1+Shift+Right move right
+bindsym Mod1+Shift+Up move up
+bindsym Mod1+Shift+c reload
+bindsym Mod1+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'
+bindsym Mod1+Shift+h move left
+bindsym Mod1+Shift+j move down
+bindsym Mod1+Shift+k move up
+bindsym Mod1+Shift+l move right
+bindsym Mod1+Shift+minus move scratchpad
+bindsym Mod1+Shift+q kill
+bindsym Mod1+Shift+space floating toggle
+bindsym Mod1+Up focus up
+bindsym Mod1+a focus parent
+bindsym Mod1+b splith
+bindsym Mod1+d exec @dmenu@/bin/dmenu_run
+bindsym Mod1+e layout toggle split
+bindsym Mod1+f fullscreen toggle
+bindsym Mod1+h focus left
+bindsym Mod1+j focus down
+bindsym Mod1+k focus up
+bindsym Mod1+l focus right
+bindsym Mod1+minus scratchpad show
+bindsym Mod1+r mode resize
+bindsym Mod1+s layout stacking
+bindsym Mod1+space focus mode_toggle
+bindsym Mod1+v splitv
+bindsym Mod1+w layout tabbed
+
+
+
+mode "resize" {
+bindsym Down resize grow height 10 px
+bindsym Escape mode default
+bindsym Left resize shrink width 10 px
+bindsym Return mode default
+bindsym Right resize grow width 10 px
+bindsym Up resize shrink height 10 px
+bindsym h resize shrink width 10 px
+bindsym j resize grow height 10 px
+bindsym k resize shrink height 10 px
+bindsym l resize grow width 10 px
+}
+
+
+
+
+
+
+
+
+exec "systemctl --user import-environment; systemctl --user start sway-session.target"
diff --git a/home-manager/tests/modules/services/window-managers/sway/sway-followmouse-legacy-expected.conf b/home-manager/tests/modules/services/window-managers/sway/sway-followmouse-legacy-expected.conf
new file mode 100644
index 00000000000..cbc55722a01
--- /dev/null
+++ b/home-manager/tests/modules/services/window-managers/sway/sway-followmouse-legacy-expected.conf
@@ -0,0 +1,94 @@
+font pango:monospace 8
+floating_modifier Mod1
+default_border pixel 2
+default_floating_border pixel 2
+hide_edge_borders none
+focus_wrapping no
+focus_follows_mouse no
+focus_on_window_activation smart
+mouse_warping output
+workspace_layout default
+workspace_auto_back_and_forth no
+
+client.focused #4c7899 #285577 #ffffff #2e9ef4 #285577
+client.focused_inactive #333333 #5f676a #ffffff #484e50 #5f676a
+client.unfocused #333333 #222222 #888888 #292d2e #222222
+client.urgent #2f343a #900000 #ffffff #900000 #900000
+client.placeholder #000000 #0c0c0c #ffffff #000000 #0c0c0c
+client.background #ffffff
+
+bindsym Mod1+1 workspace number 1
+bindsym Mod1+2 workspace number 2
+bindsym Mod1+3 workspace number 3
+bindsym Mod1+4 workspace number 4
+bindsym Mod1+5 workspace number 5
+bindsym Mod1+6 workspace number 6
+bindsym Mod1+7 workspace number 7
+bindsym Mod1+8 workspace number 8
+bindsym Mod1+9 workspace number 9
+bindsym Mod1+Down focus down
+bindsym Mod1+Left focus left
+bindsym Mod1+Return exec @rxvt-unicode-unwrapped@/bin/urxvt
+bindsym Mod1+Right focus right
+bindsym Mod1+Shift+1 move container to workspace number 1
+bindsym Mod1+Shift+2 move container to workspace number 2
+bindsym Mod1+Shift+3 move container to workspace number 3
+bindsym Mod1+Shift+4 move container to workspace number 4
+bindsym Mod1+Shift+5 move container to workspace number 5
+bindsym Mod1+Shift+6 move container to workspace number 6
+bindsym Mod1+Shift+7 move container to workspace number 7
+bindsym Mod1+Shift+8 move container to workspace number 8
+bindsym Mod1+Shift+9 move container to workspace number 9
+bindsym Mod1+Shift+Down move down
+bindsym Mod1+Shift+Left move left
+bindsym Mod1+Shift+Right move right
+bindsym Mod1+Shift+Up move up
+bindsym Mod1+Shift+c reload
+bindsym Mod1+Shift+e exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'
+bindsym Mod1+Shift+h move left
+bindsym Mod1+Shift+j move down
+bindsym Mod1+Shift+k move up
+bindsym Mod1+Shift+l move right
+bindsym Mod1+Shift+minus move scratchpad
+bindsym Mod1+Shift+q kill
+bindsym Mod1+Shift+space floating toggle
+bindsym Mod1+Up focus up
+bindsym Mod1+a focus parent
+bindsym Mod1+b splith
+bindsym Mod1+d exec @dmenu@/bin/dmenu_run
+bindsym Mod1+e layout toggle split
+bindsym Mod1+f fullscreen toggle
+bindsym Mod1+h focus left
+bindsym Mod1+j focus down
+bindsym Mod1+k focus up
+bindsym Mod1+l focus right
+bindsym Mod1+minus scratchpad show
+bindsym Mod1+r mode resize
+bindsym Mod1+s layout stacking
+bindsym Mod1+space focus mode_toggle
+bindsym Mod1+v splitv
+bindsym Mod1+w layout tabbed
+
+
+
+mode "resize" {
+bindsym Down resize grow height 10 px
+bindsym Escape mode default
+bindsym Left resize shrink width 10 px
+bindsym Return mode default
+bindsym Right resize grow width 10 px
+bindsym Up resize shrink height 10 px
+bindsym h resize shrink width 10 px
+bindsym j resize grow height 10 px
+bindsym k resize shrink height 10 px
+bindsym l resize grow width 10 px
+}
+
+
+
+
+
+
+
+
+exec "systemctl --user import-environment; systemctl --user start sway-session.target"
diff --git a/home-manager/tests/modules/services/window-managers/sway/sway-followmouse-legacy.nix b/home-manager/tests/modules/services/window-managers/sway/sway-followmouse-legacy.nix
new file mode 100644
index 00000000000..9b80a63bc59
--- /dev/null
+++ b/home-manager/tests/modules/services/window-managers/sway/sway-followmouse-legacy.nix
@@ -0,0 +1,37 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ wayland.windowManager.sway = {
+ enable = true;
+
+ config = {
+ focus.followMouse = false;
+ menu = "${pkgs.dmenu}/bin/dmenu_run";
+ bars = [ ];
+ };
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ dmenu = super.dmenu // { outPath = "@dmenu@"; };
+ rxvt-unicode-unwrapped = super.rxvt-unicode-unwrapped // {
+ outPath = "@rxvt-unicode-unwrapped@";
+ };
+ sway-unwrapped =
+ pkgs.runCommandLocal "dummy-sway-unwrapped" { version = "1"; }
+ "mkdir $out";
+ swaybg = pkgs.writeScriptBin "dummy-swaybg" "";
+ xwayland = pkgs.writeScriptBin "xwayland" "";
+ })
+ ];
+
+ nmt.script = ''
+ assertFileExists home-files/.config/sway/config
+ assertFileContent home-files/.config/sway/config \
+ ${./sway-followmouse-legacy-expected.conf}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/services/window-managers/sway/sway-followmouse.nix b/home-manager/tests/modules/services/window-managers/sway/sway-followmouse.nix
new file mode 100644
index 00000000000..e05b4e56fc9
--- /dev/null
+++ b/home-manager/tests/modules/services/window-managers/sway/sway-followmouse.nix
@@ -0,0 +1,37 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ wayland.windowManager.sway = {
+ enable = true;
+
+ config = {
+ focus.followMouse = "always";
+ menu = "${pkgs.dmenu}/bin/dmenu_run";
+ bars = [ ];
+ };
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ dmenu = super.dmenu // { outPath = "@dmenu@"; };
+ rxvt-unicode-unwrapped = super.rxvt-unicode-unwrapped // {
+ outPath = "@rxvt-unicode-unwrapped@";
+ };
+ sway-unwrapped =
+ pkgs.runCommandLocal "dummy-sway-unwrapped" { version = "1"; }
+ "mkdir $out";
+ swaybg = pkgs.writeScriptBin "dummy-swaybg" "";
+ xwayland = pkgs.writeScriptBin "xwayland" "";
+ })
+ ];
+
+ nmt.script = ''
+ assertFileExists home-files/.config/sway/config
+ assertFileContent home-files/.config/sway/config \
+ ${./sway-followmouse-expected.conf}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/services/window-managers/sway/sway-post-2003.nix b/home-manager/tests/modules/services/window-managers/sway/sway-post-2003.nix
new file mode 100644
index 00000000000..3eab6538e42
--- /dev/null
+++ b/home-manager/tests/modules/services/window-managers/sway/sway-post-2003.nix
@@ -0,0 +1,35 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ home.stateVersion = "20.09";
+
+ wayland.windowManager.sway = {
+ enable = true;
+ package = pkgs.runCommandLocal "dummy-package" { } "mkdir $out" // {
+ outPath = "@sway";
+ };
+ # overriding findutils causes issues
+ config.menu = "${pkgs.dmenu}/bin/dmenu_run";
+ };
+
+ nixpkgs.overlays = [
+ (self: super: {
+ dummy-package = super.runCommandLocal "dummy-package" { } "mkdir $out";
+ dmenu = self.dummy-package // { outPath = "@dmenu@"; };
+ rxvt-unicode-unwrapped = self.dummy-package // {
+ outPath = "@rxvt-unicode-unwrapped@";
+ };
+ i3status = self.dummy-package // { outPath = "@i3status@"; };
+ })
+ ];
+
+ nmt.script = ''
+ assertFileExists home-files/.config/sway/config
+ assertFileContent home-files/.config/sway/config \
+ ${./sway-default.conf}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/systemd/default.nix b/home-manager/tests/modules/systemd/default.nix
new file mode 100644
index 00000000000..c1779ac59fb
--- /dev/null
+++ b/home-manager/tests/modules/systemd/default.nix
@@ -0,0 +1,5 @@
+{
+ systemd-services = ./services.nix;
+ systemd-session-variables = ./session-variables.nix;
+ systemd-timers = ./timers.nix;
+}
diff --git a/home-manager/tests/modules/systemd/services-expected.conf b/home-manager/tests/modules/systemd/services-expected.conf
new file mode 100644
index 00000000000..34b9618d6d3
--- /dev/null
+++ b/home-manager/tests/modules/systemd/services-expected.conf
@@ -0,0 +1,5 @@
+[Service]
+ExecStart=/some/exec/start/command --with-arguments "%i"
+
+[Unit]
+Description=A basic test service
diff --git a/home-manager/tests/modules/systemd/services.nix b/home-manager/tests/modules/systemd/services.nix
new file mode 100644
index 00000000000..ea9b2b4fb87
--- /dev/null
+++ b/home-manager/tests/modules/systemd/services.nix
@@ -0,0 +1,23 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ systemd.user.services."test-service@" = {
+ Unit = {
+ Description = "A basic test service";
+ };
+
+ Service = {
+ ExecStart = ''/some/exec/start/command --with-arguments "%i"'';
+ };
+ };
+
+ nmt.script = ''
+ serviceFile=home-files/.config/systemd/user/test-service@.service
+ assertFileExists $serviceFile
+ assertFileContent $serviceFile ${./services-expected.conf}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/systemd/session-variables-expected.conf b/home-manager/tests/modules/systemd/session-variables-expected.conf
new file mode 100644
index 00000000000..5b6e80bc32b
--- /dev/null
+++ b/home-manager/tests/modules/systemd/session-variables-expected.conf
@@ -0,0 +1,2 @@
+V_int=1
+V_str=2
diff --git a/home-manager/tests/modules/systemd/session-variables.nix b/home-manager/tests/modules/systemd/session-variables.nix
new file mode 100644
index 00000000000..b725827ce69
--- /dev/null
+++ b/home-manager/tests/modules/systemd/session-variables.nix
@@ -0,0 +1,18 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ systemd.user.sessionVariables = {
+ V_int = 1;
+ V_str = "2";
+ };
+
+ nmt.script = ''
+ envFile=home-files/.config/environment.d/10-home-manager.conf
+ assertFileExists $envFile
+ assertFileContent $envFile ${./session-variables-expected.conf}
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/systemd/timers-expected.conf b/home-manager/tests/modules/systemd/timers-expected.conf
new file mode 100644
index 00000000000..b19f044cc0b
--- /dev/null
+++ b/home-manager/tests/modules/systemd/timers-expected.conf
@@ -0,0 +1,8 @@
+[Install]
+WantedBy=timers.target
+
+[Timer]
+OnUnitActiveSec=1h 30m
+
+[Unit]
+Description=A basic test timer
diff --git a/home-manager/tests/modules/systemd/timers.nix b/home-manager/tests/modules/systemd/timers.nix
new file mode 100644
index 00000000000..1c0e2722299
--- /dev/null
+++ b/home-manager/tests/modules/systemd/timers.nix
@@ -0,0 +1,25 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ systemd.user.timers.test-timer = {
+ Unit = { Description = "A basic test timer"; };
+
+ Timer = { OnUnitActiveSec = "1h 30m"; };
+
+ Install = { WantedBy = [ "timers.target" ]; };
+ };
+
+ nmt.script = ''
+ unitDir=home-files/.config/systemd/user
+ timerFile=$unitDir/test-timer.timer
+
+ assertFileExists $timerFile
+ assertFileContent $timerFile ${./timers-expected.conf}
+
+ assertFileExists $unitDir/timers.target.wants/test-timer.timer
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/targets-darwin/darwin.nix b/home-manager/tests/modules/targets-darwin/darwin.nix
new file mode 100644
index 00000000000..511ae87fd98
--- /dev/null
+++ b/home-manager/tests/modules/targets-darwin/darwin.nix
@@ -0,0 +1,20 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+ darwinTestApp = pkgs.runCommandLocal "target-darwin-example-app" { } ''
+ mkdir -p $out/Applications
+ touch $out/Applications/example-app
+ '';
+
+in {
+ config = {
+ home.packages = [ darwinTestApp ];
+
+ nmt.script = ''
+ assertFileExists 'home-files/Applications/Home Manager Apps/example-app'
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/targets-darwin/default.nix b/home-manager/tests/modules/targets-darwin/default.nix
new file mode 100644
index 00000000000..5c04854ff2e
--- /dev/null
+++ b/home-manager/tests/modules/targets-darwin/default.nix
@@ -0,0 +1,5 @@
+{
+ # Disabled for now due to conflicting behavior with nix-darwin. See
+ # https://github.com/rycee/home-manager/issues/1341#issuecomment-687286866
+ #targets-darwin = ./darwin.nix;
+}
diff --git a/home-manager/tests/modules/targets-linux/default.nix b/home-manager/tests/modules/targets-linux/default.nix
new file mode 100644
index 00000000000..e13617ccb74
--- /dev/null
+++ b/home-manager/tests/modules/targets-linux/default.nix
@@ -0,0 +1 @@
+{ targets-generic-linux = ./generic-linux.nix; }
diff --git a/home-manager/tests/modules/targets-linux/generic-linux.nix b/home-manager/tests/modules/targets-linux/generic-linux.nix
new file mode 100644
index 00000000000..10481b5e988
--- /dev/null
+++ b/home-manager/tests/modules/targets-linux/generic-linux.nix
@@ -0,0 +1,22 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ config = {
+ targets.genericLinux = {
+ enable = true;
+ extraXdgDataDirs = [ "/foo" ];
+ };
+
+ nmt.script = ''
+ assertFileExists home-path/etc/profile.d/hm-session-vars.sh
+ assertFileContains \
+ home-path/etc/profile.d/hm-session-vars.sh \
+ 'export XDG_DATA_DIRS="''${NIX_STATE_DIR:-/nix/var/nix}/profiles/default/share:/home/hm-user/.nix-profile/share:/foo''${XDG_DATA_DIRS:+:}$XDG_DATA_DIRS"'
+ assertFileContains \
+ home-path/etc/profile.d/hm-session-vars.sh \
+ '. "${pkgs.nix}/etc/profile.d/nix.sh"'
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/xresources/default.nix b/home-manager/tests/modules/xresources/default.nix
new file mode 100644
index 00000000000..70b3e6b4a9c
--- /dev/null
+++ b/home-manager/tests/modules/xresources/default.nix
@@ -0,0 +1,4 @@
+{
+ xresources = ./xresources.nix;
+ xresources-empty-properties = ./empty.nix;
+}
diff --git a/home-manager/tests/modules/xresources/empty.nix b/home-manager/tests/modules/xresources/empty.nix
new file mode 100644
index 00000000000..9dd80176ff3
--- /dev/null
+++ b/home-manager/tests/modules/xresources/empty.nix
@@ -0,0 +1,13 @@
+{ config, lib, ... }:
+
+with lib;
+
+{
+ config = {
+ xresources.properties = { };
+
+ nmt.script = ''
+ assertPathNotExists home-files/.Xresources
+ '';
+ };
+}
diff --git a/home-manager/tests/modules/xresources/xresources-expected.conf b/home-manager/tests/modules/xresources/xresources-expected.conf
new file mode 100644
index 00000000000..20b47e5080b
--- /dev/null
+++ b/home-manager/tests/modules/xresources/xresources-expected.conf
@@ -0,0 +1,5 @@
+Test*boolean1: true
+Test*boolean2: false
+Test*int: 10
+Test*list: list-str, true, false, 10
+Test*string: test-string
diff --git a/home-manager/tests/modules/xresources/xresources.nix b/home-manager/tests/modules/xresources/xresources.nix
new file mode 100644
index 00000000000..f73e326f31e
--- /dev/null
+++ b/home-manager/tests/modules/xresources/xresources.nix
@@ -0,0 +1,22 @@
+{ config, lib, ... }:
+
+with lib;
+
+{
+ config = {
+ xresources = {
+ properties = {
+ "Test*string" = "test-string";
+ "Test*boolean1" = true;
+ "Test*boolean2" = false;
+ "Test*int" = 10;
+ "Test*list" = [ "list-str" true false 10 ];
+ };
+ };
+
+ nmt.script = ''
+ assertFileExists home-files/.Xresources
+ assertFileContent home-files/.Xresources ${./xresources-expected.conf}
+ '';
+ };
+}