{
  lib,
  pkgs,
  config,
  ...
}:
{
  users.users = {
    alice = {
      isNormalUser = true;
      description = "Alice Foobar";
      password = "foobar";
      uid = 1000;
    };
    untrusted = {
      isNormalUser = true;
      description = "Untrusted user";
      password = "foobar";
      uid = 1001;

      # For deny unmapped uid test:
      packages = [ config.environment.hakurei.package ];
    };
  };

  home-manager.users.alice.home.stateVersion = "24.11";

  # Automatically login on tty1 as a normal user:
  services.getty.autologinUser = "alice";

  security.pam.loginLimits = [
    {
      domain = "@users";
      item = "rtprio";
      type = "-";
      value = 1;
    }
  ];

  environment = {
    systemPackages = with pkgs; [
      # For D-Bus tests:
      mako
      libnotify
    ];

    variables = {
      SWAYSOCK = "/tmp/sway-ipc.sock";
      WLR_RENDERER = "pixman";
    };

    # To help with OCR:
    etc."xdg/foot/foot.ini".text = lib.generators.toINI { } {
      main = {
        font = "inconsolata:size=14";
      };
      colors = rec {
        foreground = "000000";
        background = "ffffff";
        regular2 = foreground;
      };
    };
  };

  fonts.packages = [ pkgs.inconsolata ];

  # Automatically configure and start Sway when logging in on tty1:
  programs.bash.loginShellInit = ''
    if [ "$(tty)" = "/dev/tty1" ]; then
      set -e

      mkdir -p ~/.config/sway
      (sed s/Mod4/Mod1/ /etc/sway/config &&
      echo 'output * bg ${pkgs.nixos-artwork.wallpapers.simple-light-gray.gnomeFilePath} fill' &&
      echo 'output Virtual-1 res 1680x1050') > ~/.config/sway/config

      sway --validate
      systemd-cat --identifier=session sway && touch /tmp/sway-exit-ok
    fi
  '';

  programs.sway.enable = true;

  # For PulseAudio tests:
  security.rtkit.enable = true;
  services.pipewire = {
    enable = true;
    alsa.enable = true;
    alsa.support32Bit = true;
    pulse.enable = true;
    jack.enable = true;
  };

  virtualisation = {
    # Hopefully reduces spurious test failures:
    memorySize = if pkgs.stdenv.hostPlatform.is32bit then 2046 else 8192;

    qemu.options = [
      # Need to switch to a different GPU driver than the default one (-vga std) so that Sway can launch:
      "-vga none -device virtio-gpu-pci"

      # Increase Go test compiler performance:
      "-smp 16"
    ];
  };

  # Disk image is too small for some tests:
  boot.tmp.useTmpfs = true;

  environment.hakurei = {
    enable = true;
    stateDir = "/var/lib/hakurei";
    users.alice = 0;

    extraHomeConfig =
      { config, ... }:
      {
        # To test merge deduplication:
        options._hakurei.stateVersion = lib.mkOption { type = lib.types.str; };

        config = {
          home = { inherit (config._hakurei) stateVersion; };
          _hakurei.stateVersion = "23.05";
        };
      };

    commonPaths = [
      {
        type = "bind";
        src = "/var/tmp";
        write = true;
      }
    ];

    apps = {
      "cat.gensokyo.extern.bash.linger-timeout" = {
        name = "hakurei-check-linger-timeout";
        identity = 9999;
        share = pkgs.bash;
        packages = [ pkgs.bash ];
        command = ''
          sleep infinity & disown
          exit
        '';
        wait_delay = 1;
        enablements = {
          wayland = false;
          pipewire = false;
        };
      };

      "cat.gensokyo.extern.foot.noEnablements" = {
        name = "ne-foot";
        identity = 1;
        shareUid = true;
        verbose = true;
        share = pkgs.foot;
        packages = with pkgs; [
          foot

          # For wayland-info:
          wayland-utils
        ];
        command = "foot";
        enablements = {
          dbus = false;
          pipewire = false;
        };
      };

      "cat.gensokyo.extern.foot.noEnablements.immediate" = {
        name = "ne-foot-immediate";
        identity = 1;
        shareUid = true;
        verbose = true;
        wait_delay = -1;
        share = pkgs.foot;
        packages = [ ];
        command = "foot";
        enablements = {
          dbus = false;
          pipewire = false;
        };
      };

      "cat.gensokyo.extern.foot.pulseaudio" = {
        name = "pa-foot";
        identity = 2;
        verbose = true;
        share = pkgs.foot;
        packages = [ pkgs.foot ];
        command = "foot";
        enablements.dbus = false;
      };

      "cat.gensokyo.extern.Alacritty.x11" = {
        name = "x11-alacritty";
        identity = 1;
        shareUid = true;
        verbose = true;
        share = pkgs.alacritty;
        packages = with pkgs; [
          # For X11 terminal emulator:
          alacritty

          # For glinfo:
          mesa-demos
        ];
        command = "alacritty";
        enablements = {
          wayland = false;
          x11 = true;
          dbus = false;
          pipewire = false;
        };
      };

      "cat.gensokyo.extern.foot.directWayland" = {
        name = "da-foot";
        identity = 4;
        verbose = true;
        insecureWayland = true;
        share = pkgs.foot;
        packages = with pkgs; [
          foot

          # For wayland-info:
          wayland-utils
        ];
        command = "foot";
        enablements = {
          dbus = false;
          pipewire = false;
        };
      };

      "cat.gensokyo.extern.strace.wantFail" = {
        name = "strace-failure";
        identity = 5;
        verbose = true;
        share = pkgs.strace;
        command = "strace true";
        enablements = {
          wayland = false;
          x11 = false;
          dbus = false;
          pipewire = false;
        };
      };
    };
  };
}
