from io import StringIO
from contextlib import redirect_stdout, redirect_stderr


from tiramisu_cmdline_parser import TiramisuCmdlineParser
from tiramisu import IntOption, StrOption, BoolOption, ChoiceOption, \
                     SymLinkOption, OptionDescription, Config


def get_config():
    choiceoption = ChoiceOption('cmd',
                                'choice the sub argument',
                                ('str', 'list', 'int'),
                                properties=('mandatory',
                                            'positional'))
    booloption = BoolOption('verbosity',
                            'increase output verbosity',
                            default=False)
    short_booloption = SymLinkOption('v', booloption)
    str_ = StrOption('str',
                     'string option',
                     properties=('mandatory',),
                     requires=[{'option': choiceoption,
                                'expected': 'str',
                                'action': 'disabled',
                                'inverse': True}])
    list_ = StrOption('list',
                      'list string option',
                      multi=True,
                      properties=('mandatory',),
                      requires=[{'option': choiceoption,
                                 'expected': 'list',
                                 'action': 'disabled',
                                 'inverse': True}])
    int_ = IntOption('int',
                     'int option',
                     properties=('mandatory',),
                     requires=[{'option': choiceoption,
                                'expected': 'int',
                                'action': 'disabled',
                                'inverse': True}])
    return Config(OptionDescription('root',
                                    'root',
                                    [choiceoption,
                                     booloption,
                                     short_booloption,
                                     str_,
                                     list_,
                                     int_
                                     ]))

def test_readme_help():
    output = """usage: prog.py [-h] [-v] --str STR --list LIST [LIST ...] --int INT
               {str,list,int}

positional arguments:
  {str,list,int}        choice the sub argument

optional arguments:
  -h, --help            show this help message and exit
  -v, --verbosity       increase output verbosity
  --str STR             string option
  --list LIST [LIST ...]
                        list string option
  --int INT             int option
"""
    parser = TiramisuCmdlineParser('prog.py')
    parser.add_arguments(get_config())
    f = StringIO()
    with redirect_stdout(f):
        parser.print_help()
    assert f.getvalue() == output


def test_readme_positional_mandatory():
    output = """usage: prog.py [-h] [-v] --str STR --list LIST [LIST ...] --int INT
               {str,list,int}
prog.py: error: the following arguments are required: cmd
"""
    parser = TiramisuCmdlineParser('prog.py')
    parser.add_arguments(get_config())
    f = StringIO()
    with redirect_stderr(f):
        try:
            parser.parse_args([])
        except SystemExit as err:
            assert str(err) == "2"
        else:
            raise Exception('must raises')
    assert f.getvalue() == output


def test_readme_mandatory():
    output = """usage: prog.py [-h] [-v] --str STR --list LIST [LIST ...] --int INT
               {str,list,int}
prog.py: error: the following arguments are required: --str
"""
    parser = TiramisuCmdlineParser('prog.py')
    parser.add_arguments(get_config())
    f = StringIO()
    with redirect_stderr(f):
        try:
            parser.parse_args(['str'])
        except SystemExit as err:
            assert str(err) == "2"
        else:
            raise Exception('must raises')
    assert f.getvalue() == output


def test_readme_cross():
    output = """usage: prog.py [-h] [-v] --str STR --list LIST [LIST ...] --int INT
               {str,list,int}
prog.py: error: unrecognized arguments: --int
"""
    parser = TiramisuCmdlineParser('prog.py')
    parser.add_arguments(get_config())
    f = StringIO()
    with redirect_stderr(f):
        try:
            parser.parse_args(['str', '--int', '3'])
        except SystemExit as err:
            assert str(err) == "2"
        else:
            raise Exception('must raises')
    assert f.getvalue() == output


def test_readme_int():
    output = {'cmd': 'int',
              'int': 3,
              'verbosity': False,
              'v': False}
    config = get_config()
    parser = TiramisuCmdlineParser('prog.py')
    parser.add_arguments(config)
    parser.parse_args(['int', '--int', '3'])
    assert config.value.dict() == output


def test_readme_int_verbosity():
    output = {'cmd': 'int',
              'int': 3,
              'verbosity': True,
              'v': True}
    config = get_config()
    parser = TiramisuCmdlineParser('prog.py')
    parser.add_arguments(config)
    parser.parse_args(['int', '--int', '3', '--verbosity'])
    assert config.value.dict() == output


def test_readme_int_verbosity_short():
    output = {'cmd': 'int',
              'int': 3,
              'verbosity': True,
              'v': True}
    config = get_config()
    parser = TiramisuCmdlineParser('prog.py')
    parser.add_arguments(config)
    parser.parse_args(['int', '--int', '3', '-v'])
    assert config.value.dict() == output


def test_readme_str():
    output = {'cmd': 'str',
              'str': 'value',
              'verbosity': False,
              'v': False}
    config = get_config()
    parser = TiramisuCmdlineParser('prog.py')
    parser.add_arguments(config)
    parser.parse_args(['str', '--str', 'value'])
    assert config.value.dict() == output


def test_readme_str_int():
    output = {'cmd': 'str',
              'str': '3',
              'verbosity': False,
              'v': False}
    config = get_config()
    parser = TiramisuCmdlineParser('prog.py')
    parser.add_arguments(config)
    parser.parse_args(['str', '--str', '3'])
    assert config.value.dict() == output


def test_readme_list():
    output = {'cmd': 'list',
              'list': ['a', 'b', 'c'],
              'verbosity': False,
              'v': False}
    config = get_config()
    parser = TiramisuCmdlineParser('prog.py')
    parser.add_arguments(config)
    parser.parse_args(['list', '--list', 'a', 'b', 'c'])
    assert config.value.dict() == output


def test_readme_list_uniq():
    output = {'cmd': 'list',
              'list': ['a'],
              'verbosity': False,
              'v': False}
    config = get_config()
    parser = TiramisuCmdlineParser('prog.py')
    parser.add_arguments(config)
    parser.parse_args(['list', '--list', 'a'])
    assert config.value.dict() == output