File: test_argument_parser.py

package info (click to toggle)
ros2-colcon-core 0.20.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,156 kB
  • sloc: python: 10,333; makefile: 7
file content (133 lines) | stat: -rw-r--r-- 4,653 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# Copyright 2016-2018 Dirk Thomas
# Licensed under the Apache License, Version 2.0

from argparse import ArgumentParser
from unittest.mock import Mock
from unittest.mock import patch

from colcon_core.argument_parser import ArgumentParserDecorator
from colcon_core.argument_parser import ArgumentParserDecoratorExtensionPoint
from colcon_core.argument_parser import decorate_argument_parser
from colcon_core.argument_parser import get_argument_parser_extensions
import pytest

from .extension_point_context import ExtensionPointContext


class Extension1(ArgumentParserDecoratorExtensionPoint):
    PRIORITY = 80


class Extension2(ArgumentParserDecoratorExtensionPoint):
    pass


def test_get_argument_parser_extensions():
    with ExtensionPointContext(extension1=Extension1, extension2=Extension2):
        extensions = get_argument_parser_extensions()
        assert ['extension2', 'extension1'] == \
            list(extensions.keys())


def decorate_argument_parser_mock(*, parser):
    class Decorator():

        def __init__(self, parser):
            self.parser = parser

        def add_argument(self, *args, **kwargs):
            pass  # pragma: no cover
    return Decorator(parser)


def test_decorate_argument_parser():
    parser = ArgumentParser()
    with ExtensionPointContext(extension1=Extension1, extension2=Extension2):
        extensions = get_argument_parser_extensions()

        # one invalid return value, one not implemented
        extensions['extension1'].decorate_argument_parser = Mock(
            return_value=None)
        with patch('colcon_core.argument_parser.logger.error') as error:
            decorated_parser = decorate_argument_parser(parser)
        assert decorated_parser == parser
        # the raised exceptions are catched and result in error messages
        assert error.call_count == 2
        assert len(error.call_args_list[0][0]) == 1
        assert error.call_args_list[0][0][0].startswith(
            "Exception in argument parser decorator extension 'extension2': "
            '\n')
        assert error.call_args_list[0][0][0].endswith(
            '\nNotImplementedError\n')
        assert len(error.call_args_list[1][0]) == 1
        assert error.call_args_list[1][0][0].startswith(
            "Exception in argument parser decorator extension 'extension1': "
            'decorate_argument_parser() should return a parser like object\n')

        # one exception, one valid decorator
        extensions['extension2'].decorate_argument_parser = Mock(
            side_effect=RuntimeError('custom exception'))
        extensions['extension1'].decorate_argument_parser = Mock(
            side_effect=decorate_argument_parser_mock)
        with patch('colcon_core.argument_parser.logger.error') as error:
            decorated_parser = decorate_argument_parser(parser)
        assert decorated_parser.parser == parser
        # the raised exception is catched and results in an error message
        assert error.call_count == 1
        assert len(error.call_args[0]) == 1
        assert error.call_args[0][0].startswith(
            "Exception in argument parser decorator extension 'extension2': "
            'custom exception\n')


class Decorator(ArgumentParserDecorator):

    def __init__(self, parser, **kwargs):
        self.foo = 'foo'
        super().__init__(parser, **kwargs)


def test_argument_parser_decorator():
    parser = ArgumentParser()

    # __getattr__
    decorator = ArgumentParserDecorator(parser)
    assert decorator.format_help == parser.format_help

    del decorator.__dict__['_decoree']
    with pytest.raises(AttributeError):
        decorator.format_help

    # __setattr__
    decorator = Decorator(parser)
    decorator.foo = 'bar'
    assert 'foo' in decorator.__dict__
    assert decorator.__dict__['foo'] == 'bar'

    decorator.add_argument = True
    assert parser.add_argument is True

    assert 'bar' not in decorator.__dict__
    del decorator.__dict__['_decoree']
    decorator.bar = 'baz'
    assert 'bar' in decorator.__dict__
    assert decorator.__dict__['bar'] == 'baz'

    # nesting
    parser = ArgumentParser()
    decorator = Decorator(parser)
    group = decorator.add_argument_group()
    group.add_argument('arg1')

    group = decorator.add_mutually_exclusive_group()
    group.add_argument('--arg2', action='store_true')

    group = decorator.add_subparsers(dest='verb')
    group = group.add_parser('do')
    group.add_argument('arg3')

    args = parser.parse_args(['ARG1', '--arg2', 'do', 'ARG3'])
    assert args.arg1 == 'ARG1'
    assert args.arg2 is True
    assert args.verb == 'do'
    assert args.arg3 == 'ARG3'