diff options
Diffstat (limited to 'tests/test_parsing.py')
-rw-r--r-- | tests/test_parsing.py | 183 |
1 files changed, 154 insertions, 29 deletions
diff --git a/tests/test_parsing.py b/tests/test_parsing.py index 19237f6e..7b361b7e 100644 --- a/tests/test_parsing.py +++ b/tests/test_parsing.py @@ -16,7 +16,7 @@ from cmd2 import utils def parser(): parser = StatementParser( allow_redirection=True, - terminators=[';'], + terminators=[';', '&'], multiline_commands=['multiline'], aliases={'helpalias': 'help', '42': 'theanswer', @@ -38,7 +38,13 @@ def test_parse_empty_string(parser): ('command /* with some comment */ arg', ['command', 'arg']), ('command arg1 arg2 # comment at the end', ['command', 'arg1', 'arg2']), ('42 arg1 arg2', ['theanswer', 'arg1', 'arg2']), - ('l', ['shell', 'ls', '-al']) + ('l', ['shell', 'ls', '-al']), + ('termbare ; > /tmp/output', ['termbare', ';', '>', '/tmp/output']), + ('termbare; > /tmp/output', ['termbare', ';', '>', '/tmp/output']), + ('termbare & > /tmp/output', ['termbare', '&', '>', '/tmp/output']), + ('termbare& > /tmp/output', ['termbare', '&', '>', '/tmp/output']), + ('help|less', ['help', '|', 'less']), + ('l|less', ['shell', 'ls', '-al', '|', 'less']), ]) def test_tokenize(parser, line, tokens): tokens_to_test = parser.tokenize(line) @@ -46,7 +52,7 @@ def test_tokenize(parser, line, tokens): def test_tokenize_unclosed_quotes(parser): with pytest.raises(ValueError): - tokens = parser.tokenize('command with "unclosed quotes') + _ = parser.tokenize('command with "unclosed quotes') @pytest.mark.parametrize('tokens,command,args', [ ([], None, None), @@ -69,18 +75,28 @@ def test_parse_single_word(parser, line): assert not statement.args assert statement.argv == [utils.strip_quotes(line)] -def test_parse_word_plus_terminator(parser): - line = 'termbare;' +@pytest.mark.parametrize('line,terminator', [ + ('termbare;', ';'), + ('termbare ;', ';'), + ('termbare&', '&'), + ('termbare &', '&'), +]) +def test_parse_word_plus_terminator(parser, line, terminator): statement = parser.parse(line) assert statement.command == 'termbare' - assert statement.terminator == ';' + assert statement.terminator == terminator assert statement.argv == ['termbare'] -def test_parse_suffix_after_terminator(parser): - line = 'termbare; suffx' +@pytest.mark.parametrize('line,terminator', [ + ('termbare; suffx', ';'), + ('termbare ;suffx', ';'), + ('termbare& suffx', '&'), + ('termbare &suffx', '&'), +]) +def test_parse_suffix_after_terminator(parser, line, terminator): statement = parser.parse(line) assert statement.command == 'termbare' - assert statement.terminator == ';' + assert statement.terminator == terminator assert statement.suffix == 'suffx' assert statement.argv == ['termbare'] @@ -134,12 +150,16 @@ def test_parse_what_if_quoted_strings_seem_to_start_comments(parser): assert not statement.pipe_to assert statement.argv == ['what', 'if', 'quoted strings /* seem to ', 'start', 'comments?'] -def test_parse_simple_piped(parser): - statement = parser.parse('simple | piped') +@pytest.mark.parametrize('line',[ + 'simple | piped', + 'simple|piped', +]) +def test_parse_simple_pipe(parser, line): + statement = parser.parse(line) assert statement.command == 'simple' assert not statement.args assert statement.argv == ['simple'] - assert statement.pipe_to == 'piped' + assert statement.pipe_to == ['piped'] def test_parse_double_pipe_is_not_a_pipe(parser): line = 'double-pipe || is not a pipe' @@ -150,16 +170,29 @@ def test_parse_double_pipe_is_not_a_pipe(parser): assert not statement.pipe_to def test_parse_complex_pipe(parser): - line = 'command with args, terminator;sufx | piped' + line = 'command with args, terminator&sufx | piped' statement = parser.parse(line) assert statement.command == 'command' assert statement.args == "with args, terminator" assert statement.argv == ['command', 'with', 'args,', 'terminator'] - assert statement.terminator == ';' + assert statement.terminator == '&' assert statement.suffix == 'sufx' - assert statement.pipe_to == 'piped' + assert statement.pipe_to == ['piped'] + +@pytest.mark.parametrize('line,output', [ + ('help > out.txt', '>'), + ('help>out.txt', '>'), + ('help >> out.txt', '>>'), + ('help>>out.txt', '>>'), +]) +def test_parse_redirect(parser,line, output): + statement = parser.parse(line) + assert statement.command == 'help' + assert not statement.args + assert statement.output == output + assert statement.output_to == 'out.txt' -def test_parse_output_redirect(parser): +def test_parse_redirect_with_args(parser): line = 'output into > afile.txt' statement = parser.parse(line) assert statement.command == 'output' @@ -168,7 +201,7 @@ def test_parse_output_redirect(parser): assert statement.output == '>' assert statement.output_to == 'afile.txt' -def test_parse_output_redirect_with_dash_in_path(parser): +def test_parse_redirect_with_dash_in_path(parser): line = 'output into > python-cmd2/afile.txt' statement = parser.parse(line) assert statement.command == 'output' @@ -177,7 +210,7 @@ def test_parse_output_redirect_with_dash_in_path(parser): assert statement.output == '>' assert statement.output_to == 'python-cmd2/afile.txt' -def test_parse_output_redirect_append(parser): +def test_parse_redirect_append(parser): line = 'output appended to >> /tmp/afile.txt' statement = parser.parse(line) assert statement.command == 'output' @@ -194,9 +227,9 @@ def test_parse_pipe_and_redirect(parser): assert statement.argv == ['output', 'into'] assert statement.terminator == ';' assert statement.suffix == 'sufx' - assert statement.pipe_to == 'pipethrume plz' - assert statement.output == '>' - assert statement.output_to == 'afile.txt' + assert statement.pipe_to == ['pipethrume', 'plz', '>', 'afile.txt'] + assert not statement.output + assert not statement.output_to def test_parse_output_to_paste_buffer(parser): line = 'output to paste buffer >> ' @@ -207,8 +240,9 @@ def test_parse_output_to_paste_buffer(parser): assert statement.output == '>>' def test_parse_redirect_inside_terminator(parser): - """The terminator designates the end of the commmand/arguments portion. If a redirector - occurs before a terminator, then it will be treated as part of the arguments and not as a redirector.""" + """The terminator designates the end of the commmand/arguments portion. + If a redirector occurs before a terminator, then it will be treated as + part of the arguments and not as a redirector.""" line = 'has > inside;' statement = parser.parse(line) assert statement.command == 'has' @@ -216,6 +250,23 @@ def test_parse_redirect_inside_terminator(parser): assert statement.argv == ['has', '>', 'inside'] assert statement.terminator == ';' +@pytest.mark.parametrize('line,terminator',[ + ('multiline with | inside;', ';'), + ('multiline with | inside ;', ';'), + ('multiline with | inside;;;', ';'), + ('multiline with | inside;; ;;', ';'), + ('multiline with | inside&', '&'), + ('multiline with | inside &;', '&'), + ('multiline with | inside&&;', '&'), + ('multiline with | inside &; &;', '&'), +]) +def test_parse_multiple_terminators(parser, line, terminator): + statement = parser.parse(line) + assert statement.multiline_command == 'multiline' + assert statement.args == 'with | inside' + assert statement.argv == ['multiline', 'with', '|', 'inside'] + assert statement.terminator == terminator + def test_parse_unfinished_multiliine_command(parser): line = 'multiline has > inside an unfinished command' statement = parser.parse(line) @@ -225,13 +276,19 @@ def test_parse_unfinished_multiliine_command(parser): assert statement.argv == ['multiline', 'has', '>', 'inside', 'an', 'unfinished', 'command'] assert not statement.terminator -def test_parse_multiline_command_ignores_redirectors_within_it(parser): - line = 'multiline has > inside;' +@pytest.mark.parametrize('line,terminator',[ + ('multiline has > inside;', ';'), + ('multiline has > inside;;;', ';'), + ('multiline has > inside;; ;;', ';'), + ('multiline has > inside &', '&'), + ('multiline has > inside & &', '&'), +]) +def test_parse_multiline_command_ignores_redirectors_within_it(parser, line, terminator): statement = parser.parse(line) assert statement.multiline_command == 'multiline' assert statement.args == 'has > inside' assert statement.argv == ['multiline', 'has', '>', 'inside'] - assert statement.terminator == ';' + assert statement.terminator == terminator def test_parse_multiline_with_incomplete_comment(parser): """A terminator within a comment will be ignored and won't terminate a multiline command. @@ -296,7 +353,7 @@ def test_parse_redirect_to_unicode_filename(parser): def test_parse_unclosed_quotes(parser): with pytest.raises(ValueError): - tokens = parser.tokenize("command with 'unclosed quotes") + _ = parser.tokenize("command with 'unclosed quotes") def test_empty_statement_raises_exception(): app = cmd2.Cmd() @@ -315,12 +372,12 @@ def test_empty_statement_raises_exception(): ('!ls -al /tmp', 'shell', 'ls -al /tmp'), ('l', 'shell', 'ls -al') ]) -def test_alias_and_shortcut_expansion(parser, line, command, args): +def test_parse_alias_and_shortcut_expansion(parser, line, command, args): statement = parser.parse(line) assert statement.command == command assert statement.args == args -def test_alias_on_multiline_command(parser): +def test_parse_alias_on_multiline_command(parser): line = 'anothermultiline has > inside an unfinished command' statement = parser.parse(line) assert statement.multiline_command == 'multiline' @@ -328,6 +385,43 @@ def test_alias_on_multiline_command(parser): assert statement.args == 'has > inside an unfinished command' assert not statement.terminator +@pytest.mark.parametrize('line,output', [ + ('helpalias > out.txt', '>'), + ('helpalias>out.txt', '>'), + ('helpalias >> out.txt', '>>'), + ('helpalias>>out.txt', '>>'), +]) +def test_parse_alias_redirection(parser, line, output): + statement = parser.parse(line) + assert statement.command == 'help' + assert not statement.args + assert statement.output == output + assert statement.output_to == 'out.txt' + +@pytest.mark.parametrize('line', [ + 'helpalias | less', + 'helpalias|less', +]) +def test_parse_alias_pipe(parser, line): + statement = parser.parse(line) + assert statement.command == 'help' + assert not statement.args + assert statement.pipe_to == ['less'] + +@pytest.mark.parametrize('line', [ + 'helpalias;', + 'helpalias;;', + 'helpalias;; ;', + 'helpalias ;', + 'helpalias ; ;', + 'helpalias ;; ;', +]) +def test_parse_alias_terminator_no_whitespace(parser, line): + statement = parser.parse(line) + assert statement.command == 'help' + assert not statement.args + assert statement.terminator == ';' + def test_parse_command_only_command_and_args(parser): line = 'help history' statement = parser.parse_command_only(line) @@ -373,3 +467,34 @@ def test_parse_command_only_quoted_args(parser): assert statement.command == 'shell' assert statement.args == 'ls -al "/tmp/directory with spaces/doit.sh"' assert statement.command_and_args == line.replace('l', 'shell ls -al') + +@pytest.mark.parametrize('line', [ + 'helpalias > out.txt', + 'helpalias>out.txt', + 'helpalias >> out.txt', + 'helpalias>>out.txt', + 'help|less', + 'helpalias;', + 'help ;;', + 'help; ;;', +]) +def test_parse_command_only_specialchars(parser, line): + statement = parser.parse_command_only(line) + assert statement.command == 'help' + +@pytest.mark.parametrize('line', [ + ';', + ';;', + ';; ;', + '&', + '& &', + ' && &', + '>', + "'", + '"', + '|', +]) +def test_parse_command_only_none(parser, line): + statement = parser.parse_command_only(line) + assert statement.command == None + assert statement.args == None |