From ec2aace4923de034cc1301eeaa9bebb7587a6155 Mon Sep 17 00:00:00 2001 From: luto Date: Sun, 28 Apr 2024 18:17:29 +0200 Subject: [PATCH] make $ without user behavior consistent --- docs/syntax.md | 9 ++++- src/shellinspector/parser.py | 10 +++++ tests/data/test_error.ispec | 2 +- tests/test_parser.py | 77 ++++++++++++++++++------------------ 4 files changed, 57 insertions(+), 41 deletions(-) diff --git a/docs/syntax.md b/docs/syntax.md index 52260a9..b88f63b 100644 --- a/docs/syntax.md +++ b/docs/syntax.md @@ -133,8 +133,8 @@ a ## Target user & machine By default commands run inside the uberspace8 VM as the specified user (`%` for -root, `$` for the newest user). To override this, expand the lines to look like -a shell prompt: +root, `$` for the user last specified). To override this, expand the lines to +look like a shell prompt: ``` # run on the local dev/ci machine @@ -143,8 +143,13 @@ luto-portable # run as a different user on uberspace8 VM [usr1@remote]$ whoami usr1 +# run as the user last specified, in this case usr1 +$ whoam +usr1 ``` +Using `$` without a specified user as the first `$`-command will cause an error. + ## Sessions You can connect to the test host more than once by adding `:session_name` to the diff --git a/src/shellinspector/parser.py b/src/shellinspector/parser.py index a32ca34..0974a33 100644 --- a/src/shellinspector/parser.py +++ b/src/shellinspector/parser.py @@ -294,6 +294,16 @@ def parse(path: str, lines: list[str]) -> Specfile: line, ) ) + + if not user and execution_mode == ExecutionMode.USER: + specfile.errors.append( + Error( + path, + line_no, + line, + "syntax error: command (and all before it) do not have a user specified", + ) + ) else: # add output line to last command specfile.commands[-1].expected += line + "\n" diff --git a/tests/data/test_error.ispec b/tests/data/test_error.ispec index 3940230..9a1ee68 100644 --- a/tests/data/test_error.ispec +++ b/tests/data/test_error.ispec @@ -1,3 +1,3 @@ a -$ ls2 +% ls2 b diff --git a/tests/test_parser.py b/tests/test_parser.py index aab4401..837903c 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -12,9 +12,11 @@ def test_parse(): specfile = parse( "/dev/null", [ - "$ echo a", + "[usr@]$ echo a", "# ignored", "a", + "$ echo b", + "b", "% ls", "file", "dir", @@ -26,38 +28,48 @@ def test_parse(): ) commands, errors = (specfile.commands, specfile.errors) - assert len(errors) == 0 - assert len(commands) == 4 + assert len(errors) == 0, errors + assert len(commands) == 5 assert commands[0].execution_mode == ExecutionMode.USER + assert commands[0].user == "usr" assert commands[0].command == "echo a" assert commands[0].assert_mode == AssertMode.LITERAL assert commands[0].expected == "a\n" assert commands[0].source_file == Path("/dev/null") assert commands[0].source_line_no == 1 - assert commands[1].execution_mode == ExecutionMode.ROOT - assert commands[1].command == "ls" + assert commands[1].execution_mode == ExecutionMode.USER + assert commands[1].user == "usr" + assert commands[1].command == "echo b" assert commands[1].assert_mode == AssertMode.LITERAL - assert commands[1].expected == "file\ndir\notherfile\n" + assert commands[1].expected == "b\n" assert commands[1].source_file == Path("/dev/null") assert commands[1].source_line_no == 4 assert commands[2].execution_mode == ExecutionMode.ROOT - assert commands[2].command == "ls dir" - assert commands[2].assert_mode == AssertMode.REGEX + assert commands[2].user == "root" + assert commands[2].command == "ls" + assert commands[2].assert_mode == AssertMode.LITERAL + assert commands[2].expected == "file\ndir\notherfile\n" assert commands[2].source_file == Path("/dev/null") - assert commands[2].source_line_no == 8 - assert commands[3].execution_mode == ExecutionMode.PYTHON - assert commands[3].command == "func()" - assert commands[3].assert_mode == AssertMode.LITERAL + assert commands[2].source_line_no == 6 + assert commands[3].execution_mode == ExecutionMode.ROOT + assert commands[3].user == "root" + assert commands[3].command == "ls dir" + assert commands[3].assert_mode == AssertMode.REGEX assert commands[3].source_file == Path("/dev/null") assert commands[3].source_line_no == 10 + assert commands[4].execution_mode == ExecutionMode.PYTHON + assert commands[4].command == "func()" + assert commands[4].assert_mode == AssertMode.LITERAL + assert commands[4].source_file == Path("/dev/null") + assert commands[4].source_line_no == 12 def test_parse_whitespace_literal(): specfile = parse( "/dev/null", [ - "$ echo ab", + "% echo ab", "a", "b", ], @@ -91,6 +103,20 @@ def test_parse_whitespace_regex(): ) +def test_parse_error_no_user(): + specfile = parse( + "/dev/null", + [ + "$ echo a", + "a", + ], + ) + _, errors = (specfile.commands, specfile.errors) + + assert len(errors) == 1 + assert "not have a user specified" in errors[0].message + + def test_parse_error(): path = Path(__file__).parent / "virtual.ispec" specfile = parse( @@ -205,18 +231,6 @@ def test_empty(): "%_ ls", {"execution_mode": ExecutionMode.ROOT, "assert_mode": AssertMode.IGNORE}, ), - ( - "$ ls", - {"execution_mode": ExecutionMode.USER, "assert_mode": AssertMode.LITERAL}, - ), - ( - "$~ ls", - {"execution_mode": ExecutionMode.USER, "assert_mode": AssertMode.REGEX}, - ), - ( - "$_ ls", - {"execution_mode": ExecutionMode.USER, "assert_mode": AssertMode.IGNORE}, - ), ( "[someuser@somehost]$ ls", { @@ -242,19 +256,6 @@ def test_empty(): "session_name": "sess1", }, ), - ( - "[@local]$ ls", - {"execution_mode": ExecutionMode.USER, "user": None, "host": "local"}, - ), - ( - "[:sess1@local]$ ls", - { - "execution_mode": ExecutionMode.USER, - "user": None, - "host": "local", - "session_name": "sess1", - }, - ), ( "[someuser@local]% ls", {"execution_mode": ExecutionMode.ROOT, "user": "root", "host": "local"},