633 lines
18 KiB
Nix
633 lines
18 KiB
Nix
# Tests in nix-unit format
|
|
# Run with:
|
|
# nix-unit --flake .#tests
|
|
# or:
|
|
# nix build .#checks.x86_64-linux.nix-unit
|
|
#
|
|
# NOTE: Derivation comparison
|
|
# nix-unit deeply forces both `expr` and `expected` (via forceValueDeep) before
|
|
# comparing. The attrsets returned by `derivation` are self-referential, so
|
|
# this causes stack overflow. We compare `.drvPath` instead where needed, like
|
|
# `==` does when `.type == "derivation"`.
|
|
|
|
{ flake-parts }:
|
|
let
|
|
nixpkgs = flake-parts.inputs.nixpkgs;
|
|
f-p-lib = flake-parts.lib;
|
|
inherit (f-p-lib) mkFlake;
|
|
inherit (flake-parts.inputs.nixpkgs-lib) lib;
|
|
|
|
pkg = system: name:
|
|
derivation
|
|
{
|
|
name = name;
|
|
builder = "no-builder";
|
|
system = system;
|
|
}
|
|
// {
|
|
meta = {
|
|
mainProgram = name;
|
|
};
|
|
};
|
|
|
|
# Replace derivations with a simple attrset so nix-unit can compare without
|
|
# hitting stack overflow on self-referential derivation attrsets.
|
|
# See NOTE: Derivation comparison
|
|
canon = v:
|
|
if v.type or null == "derivation" then { type = "derivation"; inherit (v) drvPath outPath name system; }
|
|
else if builtins.isAttrs v then builtins.mapAttrs (_: canon) v
|
|
else v;
|
|
|
|
empty = mkFlake
|
|
{ inputs.self = { }; }
|
|
{
|
|
systems = [ ];
|
|
};
|
|
|
|
emptyExposeArgs = mkFlake
|
|
{ inputs.self = { outPath = "the self outpath"; }; }
|
|
({ config, moduleLocation, ... }: {
|
|
flake = {
|
|
inherit moduleLocation;
|
|
};
|
|
});
|
|
|
|
# Originally tested errorLocation (removed in c8c8e56). Repurposed to test
|
|
# that mkFlake can produce standard outputs without forcing self.
|
|
emptyExposeArgsNoSelf = mkFlake
|
|
{ inputs.self = throw "self won't be available in case of some errors"; }
|
|
{
|
|
systems = [ ];
|
|
};
|
|
|
|
example1 = mkFlake
|
|
{ inputs.self = { }; }
|
|
{
|
|
systems = [ "a" "b" ];
|
|
perSystem = { config, system, ... }: {
|
|
packages.hello = pkg system "hello";
|
|
apps.hello.program = config.packages.hello;
|
|
};
|
|
};
|
|
|
|
packagesNonStrictInDevShells = mkFlake
|
|
{ inputs.self = packagesNonStrictInDevShells; /* approximation */ }
|
|
{
|
|
systems = [ "a" "b" ];
|
|
perSystem = { system, self', ... }: {
|
|
packages.hello = pkg system "hello";
|
|
packages.default = self'.packages.hello;
|
|
devShells = throw "can't be strict in perSystem.devShells!";
|
|
};
|
|
flake.devShells = throw "can't be strict in devShells!";
|
|
};
|
|
|
|
easyOverlay = mkFlake
|
|
{ inputs.self = { }; }
|
|
{
|
|
imports = [ flake-parts.flakeModules.easyOverlay ];
|
|
systems = [ "a" "aarch64-linux" ];
|
|
perSystem = { system, config, final, pkgs, ... }: {
|
|
packages.default = config.packages.hello;
|
|
packages.hello = pkg system "hello";
|
|
packages.hello_new = final.hello;
|
|
overlayAttrs = {
|
|
hello = config.packages.hello;
|
|
hello_old = pkgs.hello;
|
|
hello_new = config.packages.hello_new;
|
|
};
|
|
};
|
|
};
|
|
|
|
bundlersExample = mkFlake
|
|
{ inputs.self = { }; }
|
|
{
|
|
imports = [ flake-parts.flakeModules.bundlers ];
|
|
systems = [ "a" "b" ];
|
|
perSystem = { system, ... }: {
|
|
packages.hello = pkg system "hello";
|
|
bundlers.toTarball = drv: pkg system "tarball-${drv.name}";
|
|
bundlers.toAppImage = drv: pkg system "appimage-${drv.name}";
|
|
};
|
|
};
|
|
|
|
modulesFlake =
|
|
mkFlake
|
|
{
|
|
inputs.self = { };
|
|
moduleLocation = "modulesFlake";
|
|
}
|
|
{
|
|
imports = [ flake-parts.flakeModules.modules ];
|
|
options = {
|
|
# Test option that uses plain types.submodule
|
|
flake.fooConfiguration = lib.mkOption {
|
|
type = lib.types.submoduleWith {
|
|
# Just Like types.submodule;
|
|
shorthandOnlyDefinesConfig = true;
|
|
class = "foo";
|
|
modules = [ ];
|
|
};
|
|
};
|
|
};
|
|
config = {
|
|
systems = [ ];
|
|
flake = {
|
|
modules.generic.example =
|
|
{ lib, ... }:
|
|
{
|
|
options.generic.example = lib.mkOption { default = "works in any module system application"; };
|
|
};
|
|
modules.foo.example =
|
|
{ lib, ... }:
|
|
{
|
|
options.foo.example = lib.mkOption { default = "works in foo application"; };
|
|
};
|
|
fooConfiguration = modulesFlake.modules.foo.example;
|
|
};
|
|
};
|
|
};
|
|
|
|
flakeModulesDeclare = mkFlake
|
|
{ inputs.self = { outPath = ./.; }; }
|
|
({ config, ... }: {
|
|
imports = [ flake-parts.flakeModules.flakeModules ];
|
|
systems = [ ];
|
|
flake.flakeModules.default = { lib, ... }: {
|
|
options.flake.test123 = lib.mkOption { default = "option123"; };
|
|
imports = [ config.flake.flakeModules.extra ];
|
|
};
|
|
flake.flakeModules.extra = {
|
|
flake.test123 = "123test";
|
|
};
|
|
});
|
|
|
|
flakeModulesImport = mkFlake
|
|
{ inputs.self = { }; }
|
|
{
|
|
imports = [ flakeModulesDeclare.flakeModules.default ];
|
|
};
|
|
|
|
flakeModulesDisable = mkFlake
|
|
{ inputs.self = { }; }
|
|
{
|
|
imports = [ flakeModulesDeclare.flakeModules.default ];
|
|
disabledModules = [ flakeModulesDeclare.flakeModules.extra ];
|
|
};
|
|
|
|
nixpkgsWithoutEasyOverlay = import nixpkgs {
|
|
system = "x86_64-linux";
|
|
overlays = [ ];
|
|
config = { };
|
|
};
|
|
|
|
nixpkgsWithEasyOverlay = import nixpkgs {
|
|
# non-memoized
|
|
system = "x86_64-linux";
|
|
overlays = [ easyOverlay.overlays.default ];
|
|
config = { };
|
|
};
|
|
|
|
nixpkgsWithEasyOverlayMemoized = import nixpkgs {
|
|
# memoized
|
|
system = "aarch64-linux";
|
|
overlays = [ easyOverlay.overlays.default ];
|
|
config = { };
|
|
};
|
|
|
|
specialArgFlake = mkFlake
|
|
{
|
|
inputs.self = { };
|
|
specialArgs.soSpecial = true;
|
|
}
|
|
({ soSpecial, ... }: {
|
|
imports = assert soSpecial; [ ];
|
|
flake.foo = true;
|
|
});
|
|
|
|
partitionWithoutExtraInputsFlake = mkFlake
|
|
{
|
|
inputs.self = { };
|
|
}
|
|
({ config, ... }: {
|
|
imports = [ flake-parts.flakeModules.partitions ];
|
|
systems = [ "x86_64-linux" ];
|
|
partitions.dev.module = { inputs, ... }: builtins.seq inputs { };
|
|
partitionedAttrs.devShells = "dev";
|
|
});
|
|
|
|
nixosModulesFlake = mkFlake
|
|
{
|
|
inputs.self = { outPath = "/test/path"; };
|
|
}
|
|
{
|
|
systems = [ ];
|
|
flake.nixosModules.example = { lib, ... }: {
|
|
options.test.option = lib.mkOption { default = "nixos-test"; };
|
|
};
|
|
};
|
|
|
|
dogfoodProvider = mkFlake
|
|
{ inputs.self = { }; }
|
|
({ flake-parts-lib, ... }: {
|
|
imports = [
|
|
(flake-parts-lib.importAndPublish "dogfood" { flake.marker = "dogfood"; })
|
|
];
|
|
});
|
|
|
|
dogfoodConsumer = mkFlake
|
|
{ inputs.self = { }; }
|
|
({ flake-parts-lib, ... }: {
|
|
imports = [
|
|
dogfoodProvider.modules.flake.dogfood
|
|
];
|
|
});
|
|
|
|
withSystemFlake = mkFlake
|
|
{ inputs.self = { }; }
|
|
({ withSystem, ... }: {
|
|
systems = [ "a" "b" ];
|
|
perSystem = { system, ... }: {
|
|
packages.hello = pkg system "hello";
|
|
};
|
|
flake.withSystem = withSystem;
|
|
});
|
|
|
|
in
|
|
{
|
|
"test: mkFlake does not force self" = {
|
|
expr = emptyExposeArgsNoSelf;
|
|
expected = {
|
|
apps = { };
|
|
checks = { };
|
|
devShells = { };
|
|
formatter = { };
|
|
legacyPackages = { };
|
|
nixosConfigurations = { };
|
|
nixosModules = { };
|
|
overlays = { };
|
|
packages = { };
|
|
};
|
|
};
|
|
|
|
withSystem = {
|
|
"test: withSystem provides the right system for undeclared system" = {
|
|
expr = withSystemFlake.withSystem "foo" ({ system, ... }: system);
|
|
expected = "foo";
|
|
};
|
|
"test: withSystem provides perSystem config for undeclared system" = {
|
|
expr = withSystemFlake.withSystem "foo" ({ config, ... }: config.packages.hello);
|
|
expected = pkg "foo" "hello";
|
|
};
|
|
"test: withSystem provides the right system for declared system" = {
|
|
expr = withSystemFlake.withSystem "a" ({ system, ... }: system);
|
|
expected = "a";
|
|
};
|
|
"test: withSystem provides perSystem config for declared system" = {
|
|
expr = withSystemFlake.withSystem "a" ({ config, ... }: config.packages.hello);
|
|
expected = pkg "a" "hello";
|
|
};
|
|
};
|
|
empty = {
|
|
"test: empty flake outputs" = {
|
|
expr = empty;
|
|
expected = {
|
|
apps = { };
|
|
checks = { };
|
|
devShells = { };
|
|
formatter = { };
|
|
legacyPackages = { };
|
|
nixosConfigurations = { };
|
|
nixosModules = { };
|
|
overlays = { };
|
|
packages = { };
|
|
};
|
|
};
|
|
};
|
|
|
|
example1 = {
|
|
"test: full flake output with two systems" = {
|
|
expr = example1;
|
|
expected = {
|
|
apps = {
|
|
a = {
|
|
hello = {
|
|
program = "${pkg "a" "hello"}/bin/hello";
|
|
type = "app";
|
|
meta = { };
|
|
};
|
|
};
|
|
b = {
|
|
hello = {
|
|
program = "${pkg "b" "hello"}/bin/hello";
|
|
type = "app";
|
|
meta = { };
|
|
};
|
|
};
|
|
};
|
|
checks = { a = { }; b = { }; };
|
|
devShells = { a = { }; b = { }; };
|
|
formatter = { };
|
|
legacyPackages = { a = { }; b = { }; };
|
|
nixosConfigurations = { };
|
|
nixosModules = { };
|
|
overlays = { };
|
|
packages = {
|
|
a = { hello = pkg "a" "hello"; };
|
|
b = { hello = pkg "b" "hello"; };
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
bundlers = {
|
|
"test: toTarball bundler" = {
|
|
expr = bundlersExample.bundlers.a.toTarball (pkg "a" "hello");
|
|
expected = pkg "a" "tarball-hello";
|
|
};
|
|
"test: toAppImage bundler" = {
|
|
expr = bundlersExample.bundlers.b.toAppImage (pkg "b" "hello");
|
|
expected = pkg "b" "appimage-hello";
|
|
};
|
|
};
|
|
|
|
easyOverlay = {
|
|
"test: exported package in overlay, perSystem invoked for non-memoized system" = {
|
|
expr = nixpkgsWithEasyOverlay.hello;
|
|
expected = pkg "x86_64-linux" "hello";
|
|
};
|
|
|
|
"test: exported package in overlay, perSystem invoked for memoized system" = {
|
|
expr = nixpkgsWithEasyOverlayMemoized.hello;
|
|
expected = pkg "aarch64-linux" "hello";
|
|
};
|
|
|
|
"test: non-exported package not in overlay" = {
|
|
expr = nixpkgsWithEasyOverlay.default or null != pkg "x86_64-linux" "hello";
|
|
expected = true;
|
|
};
|
|
|
|
"test: hello_old comes from super" = {
|
|
expr = nixpkgsWithEasyOverlay.hello_old.drvPath;
|
|
# See NOTE: Derivation comparison
|
|
expected = nixpkgsWithoutEasyOverlay.hello.drvPath;
|
|
};
|
|
|
|
"test: hello_new uses final wiring" = {
|
|
expr = nixpkgsWithEasyOverlay.hello_new.drvPath;
|
|
# See NOTE: Derivation comparison
|
|
expected = nixpkgsWithEasyOverlay.hello.drvPath;
|
|
};
|
|
};
|
|
|
|
flakeModules = {
|
|
"test: import flakeModule" = {
|
|
expr = flakeModulesImport.test123;
|
|
expected = "123test";
|
|
};
|
|
|
|
"test: disable flakeModule" = {
|
|
expr = flakeModulesDisable.test123;
|
|
expected = "option123";
|
|
};
|
|
};
|
|
|
|
"test: packages not strict in devShells" = {
|
|
expr = packagesNonStrictInDevShells.packages.a.default;
|
|
expected = pkg "a" "hello";
|
|
};
|
|
|
|
"test: moduleLocation from self outPath" = {
|
|
expr = emptyExposeArgs.moduleLocation;
|
|
expected = "the self outpath/flake.nix";
|
|
};
|
|
|
|
modules = {
|
|
"test: generic module in arbitrary class" = {
|
|
expr = (lib.evalModules {
|
|
class = "barrr";
|
|
modules = [
|
|
modulesFlake.modules.generic.example
|
|
];
|
|
}).config.generic.example;
|
|
expected = "works in any module system application";
|
|
};
|
|
|
|
"test: foo module in foo class" = {
|
|
expr = (lib.evalModules {
|
|
class = "foo";
|
|
modules = [
|
|
modulesFlake.modules.foo.example
|
|
];
|
|
}).config.foo.example;
|
|
expected = "works in foo application";
|
|
};
|
|
|
|
"test: modules in submodule with shorthandOnlyDefinesConfig" = {
|
|
expr = modulesFlake.fooConfiguration.foo.example;
|
|
expected = "works in foo application";
|
|
};
|
|
};
|
|
|
|
"test: specialArgs passed to module" = {
|
|
expr = specialArgFlake.foo;
|
|
expected = true;
|
|
};
|
|
|
|
"test: partition without extra inputs" = {
|
|
expr = builtins.isAttrs partitionWithoutExtraInputsFlake.devShells.x86_64-linux;
|
|
expected = true;
|
|
};
|
|
|
|
nixosModules = {
|
|
"test: nixosModule has _class nixos" = {
|
|
expr = nixosModulesFlake.nixosModules.example._class;
|
|
expected = "nixos";
|
|
};
|
|
|
|
"test: nixosModule has correct _file" = {
|
|
expr = nixosModulesFlake.nixosModules.example._file;
|
|
expected = "/test/path/flake.nix#nixosModules.example";
|
|
};
|
|
|
|
"test: nixosModule evaluates correctly" = {
|
|
expr = (lib.evalModules {
|
|
class = "nixos";
|
|
modules = [
|
|
nixosModulesFlake.nixosModules.example
|
|
];
|
|
}).config.test.option;
|
|
expected = "nixos-test";
|
|
};
|
|
};
|
|
|
|
dogfood = {
|
|
"test: importAndPublish provider" = {
|
|
expr = dogfoodProvider.marker;
|
|
expected = "dogfood";
|
|
};
|
|
|
|
"test: importAndPublish consumer" = {
|
|
expr = dogfoodConsumer.marker;
|
|
expected = "dogfood";
|
|
};
|
|
};
|
|
|
|
touchup = {
|
|
"test: any filter keeps only matching attrs" = {
|
|
expr =
|
|
let
|
|
result = mkFlake { inputs.self = { }; } {
|
|
imports = [ flake-parts.flakeModules.touchup ];
|
|
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
|
touchup.any = { attrName, ... }: { enable = attrName == "overlays"; };
|
|
perSystem = { ... }: {
|
|
packages.default = throw "packages.default should not be evaluated";
|
|
packages.hello = throw "packages.hello should not be evaluated";
|
|
};
|
|
};
|
|
in
|
|
result;
|
|
expected = {
|
|
overlays = { };
|
|
};
|
|
};
|
|
|
|
"test: any with mkDefault, attr override" = {
|
|
expr =
|
|
let
|
|
result = mkFlake { inputs.self = { }; } {
|
|
imports = [ flake-parts.flakeModules.touchup ];
|
|
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
|
touchup.any = { ... }: { enable = lib.mkDefault false; };
|
|
touchup.attr.overlays = { enable = true; };
|
|
perSystem = { ... }: {
|
|
packages.default = throw "packages.default should not be evaluated";
|
|
packages.hello = throw "packages.hello should not be evaluated";
|
|
};
|
|
};
|
|
in
|
|
result;
|
|
expected = {
|
|
overlays = { };
|
|
};
|
|
};
|
|
|
|
"test: nested attr filtering per system" = {
|
|
expr =
|
|
let
|
|
result = mkFlake { inputs.self = { }; } {
|
|
imports = [ flake-parts.flakeModules.touchup ];
|
|
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
|
touchup.attr.packages.attr.aarch64-darwin.attr.bar.enable = false;
|
|
perSystem = { system, ... }: {
|
|
packages.foo = pkg system "foo";
|
|
# This assertion proves the filtered value is never evaluated for darwin
|
|
packages.bar = assert system == "x86_64-linux"; pkg system "bar";
|
|
};
|
|
};
|
|
in
|
|
canon result.packages;
|
|
expected = canon {
|
|
aarch64-darwin = { foo = pkg "aarch64-darwin" "foo"; };
|
|
x86_64-linux = { foo = pkg "x86_64-linux" "foo"; bar = pkg "x86_64-linux" "bar"; };
|
|
};
|
|
};
|
|
|
|
"test: finish and attr composition" = {
|
|
expr =
|
|
mkFlake { inputs.self = { }; } {
|
|
imports = [ flake-parts.flakeModules.touchup ];
|
|
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
|
touchup.any = { ... }: { enable = lib.mkDefault false; };
|
|
touchup.attr.overlays = { enable = true; finish = x: "hoi"; };
|
|
touchup.finish = x: x // { foo = "bar"; };
|
|
};
|
|
expected = {
|
|
overlays = "hoi";
|
|
foo = "bar";
|
|
};
|
|
};
|
|
|
|
# TODO: assert that the error context ("while touching up attribute 'broken'")
|
|
# appears in the trace. nix-unit's expectedError.msg only matches the thrown
|
|
# message, not addErrorContext frames.
|
|
"test: error context when enabled attr throws" = {
|
|
expr =
|
|
let
|
|
result = mkFlake { inputs.self = { }; } {
|
|
imports = [ flake-parts.flakeModules.touchup ];
|
|
systems = [ "x86_64-linux" ];
|
|
flake.broken = throw "the value is broken";
|
|
};
|
|
in
|
|
result.broken;
|
|
expectedError.type = "ThrownError";
|
|
expectedError.msg = "the value is broken";
|
|
};
|
|
};
|
|
|
|
formatter = {
|
|
"test: conditional null throws helpful error" = {
|
|
expr =
|
|
let
|
|
result = mkFlake { inputs.self = { }; } {
|
|
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
|
perSystem = { system, ... }: {
|
|
formatter =
|
|
if system == "x86_64-linux" then
|
|
derivation { name = "fmt"; builder = "x"; system = system; }
|
|
else null;
|
|
};
|
|
};
|
|
in
|
|
result.formatter.aarch64-darwin;
|
|
expectedError.type = "ThrownError";
|
|
expectedError.msg = "could not determine statically(.|\n)*disabledModules(.|\n)*inputs\\.flake-parts\\.modules\\.formatter";
|
|
};
|
|
|
|
"test: empty when never defined" = {
|
|
expr =
|
|
let
|
|
result = mkFlake { inputs.self = { }; } {
|
|
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
|
perSystem = { ... }: { };
|
|
};
|
|
in
|
|
result.formatter == { };
|
|
expected = true;
|
|
};
|
|
|
|
"test: present for all systems" = {
|
|
expr =
|
|
let
|
|
result = mkFlake { inputs.self = { }; } {
|
|
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
|
perSystem = { system, ... }: {
|
|
formatter = derivation { name = "fmt"; builder = "x"; inherit system; };
|
|
};
|
|
};
|
|
in
|
|
result ? formatter && result.formatter ? x86_64-linux && result.formatter ? aarch64-darwin;
|
|
expected = true;
|
|
};
|
|
|
|
"test: lazy per-system" = {
|
|
expr =
|
|
let
|
|
result = mkFlake { inputs.self = { }; } {
|
|
systems = [ "x86_64-linux" "aarch64-darwin" ];
|
|
perSystem = { system, ... }: {
|
|
formatter =
|
|
if system == "x86_64-linux" then
|
|
derivation { name = "fmt"; builder = "x"; system = system; }
|
|
else
|
|
throw "should not evaluate aarch64-darwin formatter";
|
|
};
|
|
};
|
|
in
|
|
result.formatter.x86_64-linux.name;
|
|
expected = "fmt";
|
|
};
|
|
};
|
|
}
|