Adds new tests for foldl', intersectAttrs as well as fills in missing .exp files. New test cases we don't pass: - fromTOML timestamp capabilities - path antiquotation - replaceStrings is lazier on C++ Nix master The C++ Nix revision used is 7066d21a0ddb421967980094222c4bc1f5a0f45a. Change-Id: Ic619c96e2d41e6c5ea6fa93f9402b12e564af3c5 Reviewed-on: https://cl.tvl.fyi/c/depot/+/8778 Reviewed-by: tazjin <tazjin@tvl.su> Autosubmit: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
		
			
				
	
	
		
			214 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			214 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
# SPDX-License-Identifier: LGPL-2.1-only
 | 
						|
# SPDX-FileCopyrightText: © 2022 The TVL Contributors
 | 
						|
# SPDX-FileCopyrightText: © 2004-2022 The Nix Contributors
 | 
						|
#
 | 
						|
# Execute language tests found in tvix_tests and nix_tests
 | 
						|
# using the C++ Nix implementation. Based on NixOS/nix:tests/lang.sh.
 | 
						|
{ depot, pkgs, lib, ... }:
 | 
						|
 | 
						|
let
 | 
						|
  testRoot = ../eval/src/tests;
 | 
						|
 | 
						|
  inherit (pkgs.buildPackages) nix nix_latest;
 | 
						|
 | 
						|
  parseTest = dir: baseName:
 | 
						|
    let
 | 
						|
      tokens = builtins.match "(eval|parse)-(okay|fail).+\\.nix" baseName;
 | 
						|
    in
 | 
						|
    if tokens == null
 | 
						|
    then null
 | 
						|
    else {
 | 
						|
      type = builtins.elemAt tokens 0;
 | 
						|
      expectedSuccess = (builtins.elemAt tokens 1) == "okay";
 | 
						|
      fileName = "${dir}/${baseName}";
 | 
						|
    };
 | 
						|
 | 
						|
  allLangTests =
 | 
						|
    lib.concatMap
 | 
						|
      (
 | 
						|
        dir:
 | 
						|
        lib.pipe
 | 
						|
          (builtins.readDir (testRoot + "/${dir}"))
 | 
						|
          [
 | 
						|
            builtins.attrNames
 | 
						|
            (builtins.map (parseTest dir))
 | 
						|
            (builtins.filter (t: t != null))
 | 
						|
          ]
 | 
						|
      ) [ "nix_tests" "nix_tests/notyetpassing" "tvix_tests" "tvix_tests/notyetpassing" ];
 | 
						|
 | 
						|
  latestNixIs215 = lib.versionOlder nix_latest.version "2.16";
 | 
						|
 | 
						|
  skippedLangTests = {
 | 
						|
    # TODO(sterni): set up NIX_PATH in sandbox
 | 
						|
    "eval-okay-search-path.nix" = true;
 | 
						|
    # Floating point precision differs between tvix and Nix
 | 
						|
    "eval-okay-fromjson.nix" = true;
 | 
						|
    # C++ Nix can't TCO
 | 
						|
    "eval-okay-tail-call-1.nix" = true;
 | 
						|
    # Ordering change after 2.3
 | 
						|
    "eval-okay-xml.nix" = [ nix ];
 | 
						|
    # Missing builtins in Nix 2.3
 | 
						|
    "eval-okay-ceil.nix" = [ nix ];
 | 
						|
    "eval-okay-floor-ceil.nix" = [ nix ];
 | 
						|
    "eval-okay-floor.nix" = [ nix ];
 | 
						|
    "eval-okay-groupBy.nix" = [ nix ];
 | 
						|
    "eval-okay-zipAttrsWith.nix" = [ nix ];
 | 
						|
    # Comparable lists are not in Nix 2.3
 | 
						|
    "eval-okay-sort.nix" = [ nix ];
 | 
						|
    "eval-okay-compare-lists.nix" = [ nix ];
 | 
						|
    "eval-okay-value-pointer-compare.nix" = [ nix ];
 | 
						|
    "eval-okay-builtins-genericClosure-pointer-equality.nix" = [ nix ];
 | 
						|
    # getAttrPos gains support for functionArgs-returned sets after 2.3
 | 
						|
    "eval-okay-getattrpos-functionargs.nix" = [ nix ];
 | 
						|
    # groupBy appeared (long) after 2.3
 | 
						|
    "eval-okay-builtins-groupby-thunk.nix" = [ nix ];
 | 
						|
    # import is no longer considered a curried primop in Nix > 2.3
 | 
						|
    "eval-okay-import-display.nix" = [ nix ];
 | 
						|
    # Cycle detection and formatting changed sometime after Nix 2.3
 | 
						|
    "eval-okay-cycle-display-cpp-nix-2.13.nix" = [ nix ];
 | 
						|
    # builtins.replaceStrings becomes lazier in Nix 2.16
 | 
						|
    "eval-okay-replacestrings.nix" = [ nix (assert latestNixIs215; nix_latest) ];
 | 
						|
    # builtins.readFileType is added in Nix 2.15
 | 
						|
    "eval-okay-readFileType.nix" = [ nix ];
 | 
						|
    # builtins.fromTOML gains support for timestamps in Nix 2.16
 | 
						|
    "eval-okay-fromTOML-timestamps.nix" = [ nix (assert latestNixIs215; nix_latest) ];
 | 
						|
 | 
						|
    # TODO(sterni): support diffing working directory and home relative paths
 | 
						|
    # like C++ Nix test suite (using string replacement).
 | 
						|
    "eval-okay-path-antiquotation.nix" = true;
 | 
						|
  };
 | 
						|
 | 
						|
  runCppNixLangTests = cpp-nix:
 | 
						|
    let
 | 
						|
      testCommand = { fileName, type, expectedSuccess, ... }:
 | 
						|
        let
 | 
						|
          testBase = lib.removeSuffix ".nix" fileName;
 | 
						|
          expFile =
 | 
						|
            let
 | 
						|
              possibleFiles =
 | 
						|
                builtins.filter
 | 
						|
                  (path: builtins.pathExists (testRoot + "/${path}"))
 | 
						|
                  (builtins.map
 | 
						|
                    (ext: "${testBase}.${ext}")
 | 
						|
                    [ "exp" "exp.xml" ]);
 | 
						|
            in
 | 
						|
            if possibleFiles == [ ] then null else builtins.head possibleFiles;
 | 
						|
          outFile = "${testBase}.out";
 | 
						|
 | 
						|
          # Skip if skippedLangTests prescribes it (possibly just for the current nix)
 | 
						|
          # or if we are missing an exp file for an eval-okay test.
 | 
						|
          skip =
 | 
						|
            let
 | 
						|
              doSkip = skippedLangTests.${builtins.baseNameOf fileName} or false;
 | 
						|
            in
 | 
						|
            if type == "eval" && expectedSuccess && (expFile == null) then true
 | 
						|
            else if builtins.isBool doSkip then doSkip
 | 
						|
            else builtins.any (drv: cpp-nix == drv) doSkip;
 | 
						|
 | 
						|
          flagsFile = "${testBase}.flags";
 | 
						|
 | 
						|
          instantiateFlags =
 | 
						|
            lib.escapeShellArgs
 | 
						|
              (
 | 
						|
                [ "--${type}" fileName ]
 | 
						|
                ++ lib.optionals (type == "eval") [ "--strict" ]
 | 
						|
                ++ lib.optionals (expFile != null && lib.hasSuffix "xml" expFile)
 | 
						|
                  [
 | 
						|
                    "--no-location"
 | 
						|
                    "--xml"
 | 
						|
                  ]
 | 
						|
              )
 | 
						|
            + lib.optionalString (builtins.pathExists (testRoot + "/${flagsFile}"))
 | 
						|
              " $(cat '${flagsFile}')";
 | 
						|
        in
 | 
						|
 | 
						|
        if skip
 | 
						|
        then "echo \"SKIP ${type} ${fileName}\"\n"
 | 
						|
        else ''
 | 
						|
          thisTestPassed=true
 | 
						|
 | 
						|
          echo "RUN  ${type} ${fileName} ${
 | 
						|
            lib.optionalString (!expectedSuccess) "(expecting failure)"
 | 
						|
          }"
 | 
						|
 | 
						|
          if ! expect ${if expectedSuccess then "0" else "1"} \
 | 
						|
                 nix-instantiate ${instantiateFlags} \
 | 
						|
                 ${if expectedSuccess then "1" else "2"}> \
 | 
						|
                 ${if expFile != null then outFile else "/dev/null"};
 | 
						|
          then
 | 
						|
            echo -n "FAIL"
 | 
						|
            thisTestPassed=false
 | 
						|
          fi
 | 
						|
        '' + lib.optionalString (expFile != null) ''
 | 
						|
          if ! diff --color=always -u '${outFile}' '${expFile}'; then
 | 
						|
            thisTestPassed=false
 | 
						|
          fi
 | 
						|
        '' + ''
 | 
						|
          if $thisTestPassed; then
 | 
						|
            echo -n "PASS"
 | 
						|
          else
 | 
						|
            echo -n "FAIL"
 | 
						|
            passed=false
 | 
						|
          fi
 | 
						|
 | 
						|
          echo " ${type} ${fileName}"
 | 
						|
 | 
						|
          unset thisTestPassed
 | 
						|
        '';
 | 
						|
    in
 | 
						|
 | 
						|
    pkgs.stdenv.mkDerivation {
 | 
						|
      name = "cpp-${cpp-nix.name}-run-lang-tests";
 | 
						|
 | 
						|
      nativeBuildInputs = [ cpp-nix ];
 | 
						|
 | 
						|
      # Obtain tests via the unpackPhase
 | 
						|
      src = testRoot;
 | 
						|
      dontConfigure = true;
 | 
						|
 | 
						|
      # Environment expected by the test suite
 | 
						|
      TEST_VAR = "foo";
 | 
						|
 | 
						|
      buildPhase = ''
 | 
						|
        # Make nix-instantiate happy in the sandbox
 | 
						|
        export NIX_STORE_DIR="$(realpath "$(mktemp -d store.XXXXXXXXXX)")"
 | 
						|
        export NIX_STATE_DIR="$(realpath "$(mktemp -d state.XXXXXXXXXX)")"
 | 
						|
 | 
						|
        # Helper function to check expected exit code
 | 
						|
        expect() {
 | 
						|
          local expected res
 | 
						|
          expected="$1"
 | 
						|
          shift
 | 
						|
          set +e
 | 
						|
          "$@"
 | 
						|
          res="$?"
 | 
						|
          set -e
 | 
						|
          [[ $res -eq $expected ]]
 | 
						|
        }
 | 
						|
 | 
						|
        # Track test results so far
 | 
						|
        passed=true
 | 
						|
 | 
						|
        source "$testCommandsPath"
 | 
						|
      '';
 | 
						|
 | 
						|
      # Actually runs into the argv limit
 | 
						|
      passAsFile = [ "testCommands" ];
 | 
						|
      testCommands = lib.concatMapStrings testCommand allLangTests;
 | 
						|
 | 
						|
      installPhase = ''
 | 
						|
        if $passed; then
 | 
						|
          touch $out
 | 
						|
        else
 | 
						|
          echo "Some test(s) failed!"
 | 
						|
          exit 1
 | 
						|
        fi
 | 
						|
      '';
 | 
						|
    };
 | 
						|
 | 
						|
in
 | 
						|
 | 
						|
depot.nix.readTree.drvTargets {
 | 
						|
  "nix-2.3" = runCppNixLangTests nix;
 | 
						|
  "nix-${lib.versions.majorMinor nix_latest.version}" = runCppNixLangTests nix_latest;
 | 
						|
}
 |