See: cl/4840
When importing Python modules, we include `functional2` in the module
path, like this:
from functional2.testlib.fixtures.env import ManagedEnv
This means that python expects to see a file like
`functional2/testlib/fixtures/env.py`. We run `pytest` from `tests/` in
the `justfile` and have `tests/functional2/__init__.py` so `pytest` in
`meson` is able to find these imports.
However, language servers generally consider the `pyproject.toml` to be
the project root, so (e.g.) `pyright` is unable to follow any of the
`functional2` imports, leading to lots of spurious errors.
In cl/4840 I moved `tests/functional2/pyproject.toml` to
`tests/pyproject.toml`, which worked but was considered aesthetically
unappealing.
This diff is much larger but it's a more elegant solution.
Change-Id: I2983c7b87f88f59a4e3521451a9f5acd6a6a6964
145 lines
4.8 KiB
Python
145 lines
4.8 KiB
Python
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import pytest
|
|
|
|
from testlib.fixtures.file_helper import with_files, CopyFile, Symlink, File
|
|
from testlib.fixtures.nix import Nix
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def nix_command_feature(nix: Nix):
|
|
nix.settings.feature("nix-command")
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("stdin", "exp", "flags"),
|
|
[
|
|
(
|
|
b"""
|
|
{
|
|
bar = 3 + 1;
|
|
foo = 2 + 2;
|
|
}
|
|
""",
|
|
"{ bar = 4; foo = 4; }",
|
|
["-f", "-"],
|
|
)
|
|
],
|
|
)
|
|
@with_files({"eval.nix": CopyFile("assets/eval.nix")})
|
|
def test_valid_eval_stdin(nix: Nix, stdin: bytes, exp: Any, flags: list[str]):
|
|
cmd = nix.nix(["eval", *flags]).with_stdin(stdin)
|
|
res = cmd.run().ok()
|
|
assert res.stdout_plain == exp
|
|
|
|
|
|
@with_files({"eval.nix": CopyFile("assets/eval.nix")})
|
|
def test_valid_filename_stdin(nix: Nix, files: Path):
|
|
stdin = (files / "eval.nix").read_bytes()
|
|
res = nix.nix(["eval", "int", "-f", "-"]).with_stdin(stdin).run().ok()
|
|
assert res.stdout_plain == "123"
|
|
|
|
res = nix.nix_instantiate(["-A", "int", "--eval", "-"]).with_stdin(stdin).run().ok()
|
|
assert res.stdout_plain == "123"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("flags", "exp"),
|
|
[
|
|
(["int"], "123"),
|
|
(["str"], '"foo\\nbar"'),
|
|
(["str", "--raw"], "foo\nbar"),
|
|
(["attr"], '{ foo = "bar"; }'),
|
|
(["attr", "--json"], '{"foo":"bar"}'),
|
|
],
|
|
)
|
|
@with_files({"eval.nix": CopyFile("assets/eval.nix")})
|
|
def test_valid_eval_f(nix: Nix, flags: list[str], exp: str):
|
|
# nix3 cli
|
|
res = nix.nix(["eval", *flags, "-f", "./eval.nix"]).run().ok()
|
|
assert res.stdout_plain == exp
|
|
|
|
# legacy cli
|
|
res = nix.nix_instantiate(["-A", *flags, "--eval", "./eval.nix"]).run().ok()
|
|
assert res.stdout_plain == exp
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("expr", "exp"),
|
|
[("assert 1 + 2 == 3; true", "true"), ('{"assert"=1;bar=2;}', '{ "assert" = 1; bar = 2; }')],
|
|
)
|
|
@pytest.mark.parametrize("long", [False, True])
|
|
def test_valid_expr(nix: Nix, expr: str, exp: str, long: bool):
|
|
flag = "--expr" if long else "-E"
|
|
res = nix.nix(["eval", flag, expr]).run().ok()
|
|
assert res.stdout_plain == exp
|
|
|
|
res = nix.nix_instantiate(["--eval", flag, expr]).run().ok()
|
|
assert res.stdout_plain == exp
|
|
|
|
|
|
@with_files({"eval.nix": CopyFile("assets/eval.nix")})
|
|
def test_invalid_no_coercible_values(nix: Nix):
|
|
"""Non-coercible values throws errors under `--raw`"""
|
|
res = nix.nix(["eval", "int", "--raw", "-f", "./eval.nix"]).run().expect(1)
|
|
assert "error: cannot coerce an integer to a string: 123" in res.stderr_plain
|
|
|
|
res = nix.nix_instantiate(["-A", "int", "--raw", "./eval.nix"]).run().expect(1)
|
|
assert (
|
|
"error: expression was expected to be a derivation or collection of derivations, but instead was an integer"
|
|
in res.stderr_plain
|
|
)
|
|
|
|
|
|
def test_invalid_top_level_error(nix: Nix):
|
|
"""Top-level eval errors should be printed to stderr with a traceback."""
|
|
res = nix.nix(["eval", "--expr", 'throw "a sample throw message"']).run().expect(1)
|
|
assert "a sample throw message" in res.stderr_plain
|
|
assert "caused by explicit throw" in res.stderr_plain
|
|
|
|
|
|
def test_valid_nested_error(nix: Nix):
|
|
"""But errors inside something should print an elided version, and exit with 0."""
|
|
res = nix.nix(["eval", "--expr", '{ throws = throw "a sample throw message"; }']).run().ok()
|
|
assert res.stdout_plain == "{ throws = «error: a sample throw message»; }"
|
|
|
|
|
|
def test_valid_restricted_toFile(nix: Nix): # noqa: N802 # builtin name
|
|
"""Check if toFile can be utilized during restricted eval"""
|
|
res = (
|
|
nix.nix(["eval", "--restrict-eval", "--expr", 'import (builtins.toFile "source" "42")'])
|
|
.run()
|
|
.ok()
|
|
)
|
|
assert res.stdout_plain == "42"
|
|
|
|
|
|
@with_files({"cycle.nix": Symlink("cycle.nix")})
|
|
# timeout given in seconds
|
|
@pytest.mark.timeout(30)
|
|
def test_invalid_no_hang_symlink_cycle(nix: Nix):
|
|
"""Check that symlink cycles don't cause a hang."""
|
|
res = nix.nix(["eval", "--file", "cycle.nix"]).run().expect(1)
|
|
assert (
|
|
"error: too many symbolic links encountered while traversing the path" in res.stderr_plain
|
|
)
|
|
|
|
|
|
@with_files({"xyzzy": {"default.nix": File("123")}, "foo": {"bar": Symlink("../xyzzy")}})
|
|
def test_valid_symlink_resolution(nix: Nix):
|
|
"""Check that relative symlinks are resolved correctly."""
|
|
res = nix.nix(["eval", "--impure", "--expr", "import ./foo/bar"]).run().ok()
|
|
assert res.stdout_plain == "123"
|
|
|
|
|
|
def test_valid_warn_unknown_setting(nix: Nix):
|
|
"""Test that unknown settings are warned about"""
|
|
res = (
|
|
nix.nix(["eval", "--option", "foobar", "baz", "--expr", '"foxes are cute"', "--raw"])
|
|
.run()
|
|
.ok()
|
|
)
|
|
assert res.stdout_plain == "foxes are cute"
|
|
assert "warning: unknown setting 'foobar'" in res.stderr_plain
|