-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
499 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
`test_autoparse` | ||
================ | ||
|
||
It turns out that autoparse is somewhat difficult to purely unit test, because a lot of the functionality is orthogonal (typing, type deduction, argument-vs-option, flag letter assignment), but the orthogonal parts are difficult to isolate implementation and API-wise. Therefore, rather than unit-test each component with mocking so on, even though we test each orthogonal unit of functionality more or less in separate files, we understand that something failing in, say, flag letter assignment could cause a failure in type deduction tests. | ||
|
||
In the grand scheme of things, autoparse really isn't that complicated, so hopefully a cascading test failure can be easily tracked down no matter what. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import pytest | ||
from inspect import signature | ||
from autocommand.autoparse import make_parser | ||
|
||
|
||
@pytest.fixture(scope='session') | ||
def check_parse(): | ||
def check_parse_impl(function, *args, add_nos=False, **kwargs): | ||
parser = make_parser( | ||
func_sig=signature(function), | ||
description=None, | ||
epilog=None, | ||
add_nos=add_nos) | ||
|
||
parsed_args = parser.parse_args(args) | ||
for key, value in kwargs.items(): | ||
assert getattr(parsed_args, key) == value | ||
|
||
return check_parse_impl | ||
|
||
|
||
# This is ostensibly session scope, but I don't know how capsys works | ||
@pytest.fixture | ||
def check_help_text(capsys): | ||
def check_help_text_impl(func, *texts): | ||
with pytest.raises(SystemExit): | ||
func() | ||
|
||
out, err = capsys.readouterr() | ||
|
||
# TODO: be wary of argparse's text formatting | ||
for text in texts: | ||
assert text in out or text in err | ||
return check_help_text_impl |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import pytest | ||
from autocommand.autoparse import AnnotationError | ||
|
||
|
||
def test_all_annotation_types(check_parse, check_help_text): | ||
def func( | ||
int_arg: int, | ||
note_arg: "note_arg description", | ||
note_int: ("note_int description", int), | ||
int_note: (int, "int_note description")): pass | ||
|
||
check_help_text( | ||
lambda: check_parse(func, '-h'), | ||
"note_arg description", | ||
"note_int description", | ||
"int_note description") | ||
|
||
check_parse( | ||
func, | ||
"1", "2", "3", "4", | ||
int_arg=1, note_arg="2", note_int=3, int_note=4) | ||
|
||
|
||
@pytest.mark.parametrize('bad_annotation', [ | ||
1000, # An int? What? | ||
{'foo': 'bar'}, # A dict isn't any better | ||
[int, 'fooo'], # For implementation ease we do ask for a tuple | ||
(), # Though the tuple should have things in it | ||
(int,), # More things | ||
(int, 'hello', 'world'), # TOO MANY THINGS | ||
(int, int), # The wrong kinds of things | ||
("hello", "world"), # Nope this is bad too | ||
]) | ||
def test_bad_annotation(bad_annotation, check_parse): | ||
def func(arg: bad_annotation): pass | ||
|
||
with pytest.raises(AnnotationError): | ||
check_parse(func) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
from inspect import signature, Signature, Parameter | ||
import pytest | ||
from autocommand.autoparse import KWArgError, PositionalArgError, make_parser | ||
|
||
|
||
def test_kwargs(check_parse): | ||
def func(**kwargs): pass | ||
|
||
with pytest.raises(KWArgError): | ||
make_parser(signature(func), "", "", False) | ||
|
||
|
||
def test_positional(check_parse): | ||
# We have to fake this one, because it isn't possible to create a | ||
# positional-only parameter in pure python | ||
|
||
with pytest.raises(PositionalArgError): | ||
make_parser( | ||
Signature([Parameter('arg', Parameter.POSITIONAL_ONLY)]), | ||
"", "", False) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import pytest | ||
|
||
|
||
def test_basic_positional(check_parse): | ||
def func(arg): pass | ||
|
||
check_parse( | ||
func, | ||
"foo", | ||
arg="foo") | ||
|
||
|
||
@pytest.mark.parametrize('cli_args', [ | ||
[], | ||
['value'], | ||
['value1', 'value2'] | ||
]) | ||
def test_variadic_positional(check_parse, cli_args): | ||
check_parse( | ||
lambda arg1, *args: None, | ||
'arg1_value', *cli_args, | ||
arg1='arg1_value', args=cli_args) | ||
|
||
|
||
def test_optional_default(check_parse): | ||
check_parse( | ||
lambda arg="default_value": None, | ||
arg="default_value") | ||
|
||
|
||
@pytest.mark.parametrize('flags, result', [ | ||
([], False), | ||
(['-f'], True), | ||
(['--no-flag'], False), | ||
(['--no-flag', '-f'], True), | ||
(['--flag', '--no-flag'], False) | ||
]) | ||
def test_add_nos(check_parse, flags, result): | ||
def func(flag: bool): pass | ||
|
||
check_parse( | ||
func, | ||
*flags, | ||
add_nos=True, | ||
flag=result) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
from unittest.mock import patch | ||
from argparse import ArgumentParser | ||
import pytest | ||
from autocommand.autoparse import autoparse | ||
|
||
|
||
def test_basic_invocation(): | ||
@autoparse | ||
def func(arg1, arg2: int, opt1=None, opt2=2, opt3='default', flag=False): | ||
return arg1, arg2, opt1, opt2, opt3, flag | ||
|
||
arg1, arg2, opt1, opt2, opt3, flag = func( | ||
['value1', '1', '-o', 'hello', '--opt2', '10', '-f']) | ||
|
||
assert arg1 == 'value1' | ||
assert arg2 == 1 | ||
assert opt1 == 'hello' | ||
assert opt2 == 10 | ||
assert opt3 == 'default' | ||
assert flag is True | ||
|
||
|
||
def test_invocation_from_argv(): | ||
@autoparse | ||
def func(arg1, arg2: int): | ||
return arg1, arg2 | ||
|
||
with patch('sys.argv', ['command', '1', '2']): | ||
arg1, arg2 = func() | ||
assert arg1 == "1" | ||
assert arg2 == 2 | ||
|
||
|
||
def test_description_epilog_help(check_help_text): | ||
@autoparse( | ||
description='this is a description', | ||
epilog='this is an epilog') | ||
def func(arg: 'this is help text'): | ||
pass | ||
|
||
check_help_text( | ||
lambda: func(['-h']), | ||
'this is a description', | ||
'this is an epilog', | ||
'this is help text') | ||
|
||
|
||
def test_docstring_description(check_help_text): | ||
@autoparse | ||
def func(arg): | ||
'''This is a docstring description''' | ||
pass | ||
|
||
check_help_text( | ||
lambda: func(['-h']), | ||
'This is a docstring description') | ||
|
||
|
||
def test_custom_parser(): | ||
parser = ArgumentParser() | ||
|
||
parser.add_argument('arg', nargs='?') | ||
group = parser.add_mutually_exclusive_group() | ||
group.add_argument('-v', '--verbose', action='store_true') | ||
group.add_argument('-q', '--quiet', action='store_true') | ||
|
||
@autoparse(parser=parser) | ||
def main(arg, verbose, quiet): | ||
return arg, verbose, quiet | ||
|
||
assert main([]) == (None, False, False) | ||
assert main(['thing']) == ('thing', False, False) | ||
assert main(['-v']) == (None, True, False) | ||
assert main(['-q']) == (None, False, True) | ||
assert main(['-v', 'thing']) == ('thing', True, False) | ||
|
||
with pytest.raises(SystemExit): | ||
main(['-v', '-q']) |
Oops, something went wrong.