from functional2.testlib.fixtures import Nix import pytest from typing import NamedTuple from textwrap import dedent class ShouldError(NamedTuple): expr: str attr: str error: str ERR_CASES: list[ShouldError] = [ # FIXME(jade): expect-test system for pytest that allows for updating these easily ShouldError('{}', '"x', """error: missing closing quote in selection path '"x'"""), ShouldError( '[]', 'x', """error: the value being indexed in the selection path 'x' at '' should be a set but is a list: [ ]""" ), ShouldError( '{}', '1', """error: the expression selected by the selection path '1' should be a list but is a set: { }""" ), ShouldError('{}', '.', """error: empty attribute name in selection path '.'"""), ShouldError('{ x."" = 2; }', 'x.""', """error: empty attribute name in selection path 'x.""'"""), ShouldError('{ x."".y = 2; }', 'x."".y', """error: empty attribute name in selection path 'x."".y'"""), ShouldError( '[]', '1', """error: list index 1 in selection path '1' is out of range for list [ ]""" ), ShouldError( '{ x.y = { z = 2; a = 3; }; }', 'x.y.c', dedent("""\ error: attribute 'c' in selection path 'x.y.c' not found inside path 'x.y', whose contents are: { a = 3; z = 2; } Did you mean one of a or z?""") ), ] # I do not know why it does this, but I guess it makes sense as allowing a tool # to pass -A unconditionally and then allow a blank attribute to mean the whole # thing def test_attrpath_accepts_empty_attr_as_no_attr(nix: Nix): assert nix.nix_instantiate(['--eval', '--expr', '{}', '-A', '']).run().ok().stdout_plain == '{ }' @pytest.mark.parametrize(['expr', 'attr', 'error'], ERR_CASES) def test_attrpath_error(nix: Nix, expr: str, attr: str, error: str): res = nix.nix_instantiate(['--eval', '--expr', expr, '-A', attr]).run() assert res.expect(1).stderr_plain == error