This CL can be used to compare the style of nixpkgs-fmt against other formatters (nixpkgs, alejandra). Change-Id: I87c6abff6bcb546b02ead15ad0405f81e01b6d9e Reviewed-on: https://cl.tvl.fyi/c/depot/+/4397 Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org> Reviewed-by: lukegb <lukegb@tvl.fyi> Reviewed-by: wpcarro <wpcarro@gmail.com> Reviewed-by: Profpatsch <mail@profpatsch.de> Reviewed-by: kanepyork <rikingcoding@gmail.com> Reviewed-by: tazjin <tazjin@tvl.su> Reviewed-by: cynthia <cynthia@tvl.fyi> Reviewed-by: edef <edef@edef.eu> Reviewed-by: eta <tvl@eta.st> Reviewed-by: grfn <grfn@gws.fyi>
		
			
				
	
	
		
			199 lines
		
	
	
	
		
			5.1 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
	
		
			5.1 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
{ lib, pkgs, depot, ... }:
 | 
						||
 | 
						||
# Run a nix testsuite.
 | 
						||
#
 | 
						||
# The tests are simple assertions on the nix level,
 | 
						||
# and can use derivation outputs if IfD is enabled.
 | 
						||
#
 | 
						||
# You build a testsuite by bundling assertions into
 | 
						||
# “it”s and then bundling the “it”s into a testsuite.
 | 
						||
#
 | 
						||
# Running the testsuite will abort evaluation if
 | 
						||
# any assertion fails.
 | 
						||
#
 | 
						||
# Example:
 | 
						||
#
 | 
						||
#   runTestsuite "myFancyTestsuite" [
 | 
						||
#     (it "does an assertion" [
 | 
						||
#       (assertEq "42 is equal to 42" "42" "42")
 | 
						||
#       (assertEq "also 23" 23 23)
 | 
						||
#     ])
 | 
						||
#     (it "frmbls the brlbr" [
 | 
						||
#       (assertEq true false)
 | 
						||
#     ])
 | 
						||
#   ]
 | 
						||
#
 | 
						||
# will fail the second it group because true is not false.
 | 
						||
 | 
						||
let
 | 
						||
  inherit (depot.nix.yants)
 | 
						||
    sum
 | 
						||
    struct
 | 
						||
    string
 | 
						||
    any
 | 
						||
    defun
 | 
						||
    list
 | 
						||
    drv
 | 
						||
    bool
 | 
						||
    ;
 | 
						||
 | 
						||
  bins = depot.nix.getBins pkgs.coreutils [ "printf" ]
 | 
						||
    // depot.nix.getBins pkgs.s6-portable-utils [ "s6-touch" "s6-false" "s6-cat" ];
 | 
						||
 | 
						||
  # Returns true if the given expression throws when `deepSeq`-ed
 | 
						||
  throws = expr:
 | 
						||
    !(builtins.tryEval (builtins.deepSeq expr { })).success;
 | 
						||
 | 
						||
  # rewrite the builtins.partition result
 | 
						||
  # to use `ok` and `err` instead of `right` and `wrong`.
 | 
						||
  partitionTests = pred: xs:
 | 
						||
    let res = builtins.partition pred xs;
 | 
						||
    in {
 | 
						||
      ok = res.right;
 | 
						||
      err = res.wrong;
 | 
						||
    };
 | 
						||
 | 
						||
  AssertErrorContext =
 | 
						||
    sum "AssertErrorContext" {
 | 
						||
      not-equal = struct "not-equal" {
 | 
						||
        left = any;
 | 
						||
        right = any;
 | 
						||
      };
 | 
						||
      should-throw = struct "should-throw" {
 | 
						||
        expr = any;
 | 
						||
      };
 | 
						||
      unexpected-throw = struct "unexpected-throw" { };
 | 
						||
    };
 | 
						||
 | 
						||
  # The result of an assert,
 | 
						||
  # either it’s true (yep) or false (nope).
 | 
						||
  # If it's nope we return an additional context
 | 
						||
  # attribute which gives details on the failure
 | 
						||
  # depending on the type of assert performed.
 | 
						||
  AssertResult =
 | 
						||
    sum "AssertResult" {
 | 
						||
      yep = struct "yep" {
 | 
						||
        test = string;
 | 
						||
      };
 | 
						||
      nope = struct "nope" {
 | 
						||
        test = string;
 | 
						||
        context = AssertErrorContext;
 | 
						||
      };
 | 
						||
    };
 | 
						||
 | 
						||
  # Result of an it. An it is a bunch of asserts
 | 
						||
  # bundled up with a good description of what is tested.
 | 
						||
  ItResult =
 | 
						||
    struct "ItResult" {
 | 
						||
      it-desc = string;
 | 
						||
      asserts = list AssertResult;
 | 
						||
    };
 | 
						||
 | 
						||
  # If the given boolean is true return a positive AssertResult.
 | 
						||
  # If the given boolean is false return a negative AssertResult
 | 
						||
  # with the provided AssertErrorContext describing the failure.
 | 
						||
  #
 | 
						||
  # This function is intended as a generic assert to implement
 | 
						||
  # more assert types and is not exposed to the user.
 | 
						||
  assertBoolContext = defun [ AssertErrorContext string bool AssertResult ]
 | 
						||
    (context: desc: res:
 | 
						||
      if res
 | 
						||
      then { yep = { test = desc; }; }
 | 
						||
      else {
 | 
						||
        nope = {
 | 
						||
          test = desc;
 | 
						||
          inherit context;
 | 
						||
        };
 | 
						||
      });
 | 
						||
 | 
						||
  # assert that left and right values are equal
 | 
						||
  assertEq = defun [ string any any AssertResult ]
 | 
						||
    (desc: left: right:
 | 
						||
      let
 | 
						||
        context = { not-equal = { inherit left right; }; };
 | 
						||
      in
 | 
						||
      assertBoolContext context desc (left == right));
 | 
						||
 | 
						||
  # assert that the expression throws when `deepSeq`-ed
 | 
						||
  assertThrows = defun [ string any AssertResult ]
 | 
						||
    (desc: expr:
 | 
						||
      let
 | 
						||
        context = { should-throw = { inherit expr; }; };
 | 
						||
      in
 | 
						||
      assertBoolContext context desc (throws expr));
 | 
						||
 | 
						||
  # assert that the expression does not throw when `deepSeq`-ed
 | 
						||
  assertDoesNotThrow = defun [ string any AssertResult ]
 | 
						||
    (desc: expr:
 | 
						||
      assertBoolContext { unexpected-throw = { }; } desc (!(throws expr)));
 | 
						||
 | 
						||
  # Annotate a bunch of asserts with a descriptive name
 | 
						||
  it = desc: asserts: {
 | 
						||
    it-desc = desc;
 | 
						||
    inherit asserts;
 | 
						||
  };
 | 
						||
 | 
						||
  # Run a bunch of its and check whether all asserts are yep.
 | 
						||
  # If not, abort evaluation with `throw`
 | 
						||
  # and print the result of the test suite.
 | 
						||
  #
 | 
						||
  # Takes a test suite name as first argument.
 | 
						||
  runTestsuite = defun [ string (list ItResult) drv ]
 | 
						||
    (name: itResults:
 | 
						||
      let
 | 
						||
        goodAss = ass: AssertResult.match ass {
 | 
						||
          yep = _: true;
 | 
						||
          nope = _: false;
 | 
						||
        };
 | 
						||
        res = partitionTests
 | 
						||
          (it:
 | 
						||
            (partitionTests goodAss it.asserts).err == [ ]
 | 
						||
          )
 | 
						||
          itResults;
 | 
						||
        prettyRes = lib.generators.toPretty { } res;
 | 
						||
      in
 | 
						||
      if res.err == [ ]
 | 
						||
      then
 | 
						||
        depot.nix.runExecline.local "testsuite-${name}-successful" { } [
 | 
						||
          "importas"
 | 
						||
          "out"
 | 
						||
          "out"
 | 
						||
          # force derivation to rebuild if test case list changes
 | 
						||
          "ifelse"
 | 
						||
          [ bins.s6-false ]
 | 
						||
          [
 | 
						||
            bins.printf
 | 
						||
            ""
 | 
						||
            (builtins.hashString "sha512" prettyRes)
 | 
						||
          ]
 | 
						||
          "if"
 | 
						||
          [ bins.printf "%s\n" "testsuite ${name} successful!" ]
 | 
						||
          bins.s6-touch
 | 
						||
          "$out"
 | 
						||
        ]
 | 
						||
      else
 | 
						||
        depot.nix.runExecline.local "testsuite-${name}-failed"
 | 
						||
          {
 | 
						||
            stdin = prettyRes + "\n";
 | 
						||
          } [
 | 
						||
          "importas"
 | 
						||
          "out"
 | 
						||
          "out"
 | 
						||
          "if"
 | 
						||
          [ bins.printf "%s\n" "testsuite ${name} failed!" ]
 | 
						||
          "if"
 | 
						||
          [ bins.s6-cat ]
 | 
						||
          "exit"
 | 
						||
          "1"
 | 
						||
        ]);
 | 
						||
 | 
						||
in
 | 
						||
{
 | 
						||
  inherit
 | 
						||
    assertEq
 | 
						||
    assertThrows
 | 
						||
    assertDoesNotThrow
 | 
						||
    it
 | 
						||
    runTestsuite
 | 
						||
    ;
 | 
						||
}
 |