# [nixpkgs]$ nix-build -A nixosTests.nixpkgs --show-trace

{ evalMinimalConfig, pkgs, lib, stdenv }:
let
  eval = mod: evalMinimalConfig {
    imports = [ ../nixpkgs.nix mod ];
  };
  withHost = eval {
    nixpkgs.hostPlatform = "aarch64-linux";
  };
  withHostAndBuild = eval {
    nixpkgs.hostPlatform = "aarch64-linux";
    nixpkgs.buildPlatform = "aarch64-darwin";
  };
  withSameHostAndBuild = eval {
    nixpkgs.hostPlatform = "aarch64-linux";
    nixpkgs.buildPlatform = "aarch64-linux";
  };
  externalPkgsWithConfig = {
    _file = "ext-pkgs-config.nix";
    nixpkgs.pkgs = pkgs;
    nixpkgs.config.allowUnfree = true;
  };
  ambiguous = {
    _file = "ambiguous.nix";
    nixpkgs.hostPlatform = "aarch64-linux";
    nixpkgs.buildPlatform = "aarch64-darwin";
    nixpkgs.system = "x86_64-linux";
    nixpkgs.localSystem.system = "x86_64-darwin";
    nixpkgs.crossSystem.system = "i686-linux";
    imports = [
      { _file = "repeat.nix";
        nixpkgs.hostPlatform = "aarch64-linux";
      }
    ];
  };
  getErrors = module:
    let
      uncheckedEval = lib.evalModules { modules = [ ../nixpkgs.nix module ]; };
    in map (ass: ass.message) (lib.filter (ass: !ass.assertion) uncheckedEval.config.assertions);

  readOnlyUndefined = evalMinimalConfig {
    imports = [ ./read-only.nix ];
  };

  readOnlyBad = evalMinimalConfig {
    imports = [ ./read-only.nix ];
    nixpkgs.pkgs = { };
  };

  readOnly = evalMinimalConfig {
    imports = [ ./read-only.nix ];
    nixpkgs.pkgs = pkgs;
  };

  readOnlyBadConfig = evalMinimalConfig {
    imports = [ ./read-only.nix ];
    nixpkgs.pkgs = pkgs;
    nixpkgs.config.allowUnfree = true; # do in pkgs instead!
  };

  readOnlyBadOverlays = evalMinimalConfig {
    imports = [ ./read-only.nix ];
    nixpkgs.pkgs = pkgs;
    nixpkgs.overlays = [ (_: _: {}) ]; # do in pkgs instead!
  };

  readOnlyBadHostPlatform = evalMinimalConfig {
    imports = [ ./read-only.nix ];
    nixpkgs.pkgs = pkgs;
    nixpkgs.hostPlatform = "foo-linux"; # do in pkgs instead!
  };

  readOnlyBadBuildPlatform = evalMinimalConfig {
    imports = [ ./read-only.nix ];
    nixpkgs.pkgs = pkgs;
    nixpkgs.buildPlatform = "foo-linux"; # do in pkgs instead!
  };

  throws = x: ! (builtins.tryEval x).success;

in
lib.recurseIntoAttrs {
  invokeNixpkgsSimple =
    (eval {
      nixpkgs.system = stdenv.hostPlatform.system;
    })._module.args.pkgs.hello;
  assertions =
    assert withHost._module.args.pkgs.stdenv.hostPlatform.system == "aarch64-linux";
    assert withHost._module.args.pkgs.stdenv.buildPlatform.system == "aarch64-linux";
    assert withHostAndBuild._module.args.pkgs.stdenv.hostPlatform.system == "aarch64-linux";
    assert withHostAndBuild._module.args.pkgs.stdenv.buildPlatform.system == "aarch64-darwin";
    assert withSameHostAndBuild.config.nixpkgs.buildPlatform == withSameHostAndBuild.config.nixpkgs.hostPlatform;
    assert withSameHostAndBuild._module.args.pkgs.stdenv.buildPlatform == withSameHostAndBuild._module.args.pkgs.stdenv.hostPlatform;
    assert builtins.trace (lib.head (getErrors ambiguous))
      getErrors ambiguous ==
        [''
          Your system configures nixpkgs with the platform parameters:
          nixpkgs.hostPlatform, with values defined in:
            - repeat.nix
            - ambiguous.nix
          nixpkgs.buildPlatform, with values defined in:
            - ambiguous.nix

          However, it also defines the legacy options:
          nixpkgs.system, with values defined in:
            - ambiguous.nix
          nixpkgs.localSystem, with values defined in:
            - ambiguous.nix
          nixpkgs.crossSystem, with values defined in:
            - ambiguous.nix

          For a future proof system configuration, we recommend to remove
          the legacy definitions.
        ''];
    assert builtins.trace (lib.head (getErrors externalPkgsWithConfig))
      getErrors externalPkgsWithConfig ==
        [''
          Your system configures nixpkgs with an externally created instance.
          `nixpkgs.config` options should be passed when creating the instance instead.

          Current value:
          {
            allowUnfree = true;
          }

          Defined in:
            - ext-pkgs-config.nix
        ''];
    assert getErrors {
        nixpkgs.localSystem = pkgs.stdenv.hostPlatform;
        nixpkgs.hostPlatform = pkgs.stdenv.hostPlatform;
        nixpkgs.pkgs = pkgs;
      } == [];


    # Tests for the read-only.nix module
    assert readOnly._module.args.pkgs.stdenv.hostPlatform.system == pkgs.stdenv.hostPlatform.system;
    assert throws readOnlyBad._module.args.pkgs.stdenv;
    assert throws readOnlyUndefined._module.args.pkgs.stdenv;
    assert throws readOnlyBadConfig._module.args.pkgs.stdenv;
    assert throws readOnlyBadOverlays._module.args.pkgs.stdenv;
    assert throws readOnlyBadHostPlatform._module.args.pkgs.stdenv;
    assert throws readOnlyBadBuildPlatform._module.args.pkgs.stdenv;
    # read-only.nix does not provide legacy options, for the sake of simplicity
    # If you're bothered by this, upgrade your configs to use the new *Platform
    # options.
    assert !readOnly.options.nixpkgs?system;
    assert !readOnly.options.nixpkgs?localSystem;
    assert !readOnly.options.nixpkgs?crossSystem;

    pkgs.emptyFile;
}
