{ pkgs, lib }:

let

  testedSystems = lib.filterAttrs (name: value: let
    platform = lib.systems.elaborate value;
  in platform.isLinux || platform.isWindows
  ) lib.systems.examples;

  getExecutable = pkgs: pkgFun: exec:
    "${pkgFun pkgs}${exec}${pkgs.hostPlatform.extensions.executable}";

  compareTest = { emulator, pkgFun, hostPkgs, crossPkgs, exec, args ? [] }: let
    pkgName = (pkgFun hostPkgs).name;
    args' = lib.concatStringsSep " " args;
  in pkgs.runCommand "test-${pkgName}-${crossPkgs.hostPlatform.config}" {
    nativeBuildInputs = [ pkgs.dos2unix ];
  } ''
    # Just in case we are using wine, get rid of that annoying extra
    # stuff.
    export WINEDEBUG=-all

    HOME=$(pwd)
    mkdir -p $out

    # We need to remove whitespace, unfortunately
    # Windows programs use \r but Unix programs use \n

    echo Running native-built program natively

    # find expected value natively
    ${getExecutable hostPkgs pkgFun exec} ${args'} \
      | dos2unix > $out/expected

    echo Running cross-built program in emulator

    # run emulator to get actual value
    ${emulator} ${getExecutable crossPkgs pkgFun exec} ${args'} \
      | dos2unix > $out/actual

    echo Comparing results...

    if [ "$(cat $out/actual)" != "$(cat $out/expected)" ]; then
      echo "${pkgName} did not output expected value:"
      cat $out/expected
      echo "instead it output:"
      cat $out/actual
      exit 1
    else
      echo "${pkgName} test passed"
      echo "both produced output:"
      cat $out/actual
    fi
  '';

  mapMultiPlatformTest = crossSystemFun: test: lib.mapAttrs (name: system: test rec {
    crossPkgs = import pkgs.path {
      localSystem = { inherit (pkgs.hostPlatform) config; };
      crossSystem = crossSystemFun system;
    };

    emulator = crossPkgs.hostPlatform.emulator pkgs;

    # Apply some transformation on windows to get dlls in the right
    # place. Unfortunately mingw doesn’t seem to be able to do linking
    # properly.
    platformFun = pkg: if crossPkgs.hostPlatform.isWindows then
      pkgs.buildEnv {
        name = "${pkg.name}-winlinks";
        paths = [pkg] ++ pkg.buildInputs;
      } else pkg;
  }) testedSystems;

  tests = {

    file = {platformFun, crossPkgs, emulator}: compareTest {
      inherit emulator crossPkgs;
      hostPkgs = pkgs;
      exec = "/bin/file";
      args = [
        "${pkgs.file}/share/man/man1/file.1.gz"
        "${pkgs.dejavu_fonts}/share/fonts/truetype/DejaVuMathTeXGyre.ttf"
      ];
      pkgFun = pkgs: platformFun pkgs.file;
    };

    hello = {platformFun, crossPkgs, emulator}: compareTest {
      inherit emulator crossPkgs;
      hostPkgs = pkgs;
      exec = "/bin/hello";
      pkgFun = pkgs: pkgs.hello;
    };

  };

in {
  gcc = (lib.mapAttrs (_: mapMultiPlatformTest (system: system // {useLLVM = false;})) tests);
  llvm = (lib.mapAttrs (_: mapMultiPlatformTest (system: system // {useLLVM = true;})) tests);
}