from pytest import mark, raises
from bottle import template

@mark.parametrize('expected, params', [
    ("""<optgroup label="Group">
  <option value="val-to-backend"  selected="true">val-displayed</option>
</optgroup>""", {
    "optgroup": "Group", "options": [
    {
        "value": "val-to-backend",
        "selected": True,
        "display": "val-displayed",
    }, ] }),
    ("""<optgroup label="Group">
  <option value="val-to-backend" disabled="true" >val-to-backend</option>
</optgroup>""", { "optgroup": "Group", "options": [
    {
        "value": "val-to-backend",
        "disabled": True,
    }, ] }),
    ("""<optgroup label="Group">
  <option value="val1-to-backend"  >val1</option>
  <option value="val2-to-backend" disabled="true" >val2-to-backend</option>
</optgroup>""", { "optgroup": "Group", "options": [
    {
        "value": "val1-to-backend",
        "display": "val1",
    },
    {
        "value": "val2-to-backend",
        "disabled": True,
    }, ] }),
])
def test_optgroup_render_exact(expected, params):
    assert template('options', **params) == expected


@mark.parametrize('name', [
    '',
    None,
    'Group',
])
@mark.parametrize('value', [
    *[ { "value": v } for v in ("", "val-to-backend", "!val-to-backend", None)],
    ({}, NameError, "name 'value' is not defined"),
])
@mark.parametrize('display', [
    *[ { "display": v } for v in ("", "val-displayed", None)],
    {},
])
@mark.parametrize('disabled', [
    *[ { "disabled": v } for v in (True, False, None)],
    {},
])
@mark.parametrize('selected', [
    *[ { "selected": v } for v in (True, False, None)],
    {},
])
def test_optgroup_render_includes(name, value, selected, disabled, display):
    options = dict()
    exp_exceptions = []
    for part, ex, msg in map(
        lambda x: x if isinstance(x, tuple) else (x, None, None),
        (value, selected, disabled, display)):
        options.update(part)
        if ex is not None:
            exp_exceptions.append(ex)

    if not exp_exceptions:
        assert template('options', optgroup=name, options=[ options, ]) is not None
        assert template('options', optgroup=name, options=[ options, options ]) is not None
        return

    with raises(tuple(exp_exceptions)):
        template('options', optgroup=name, options=[ options, ]) is not None
    
    with raises(tuple(exp_exceptions)):
        template('options', optgroup=name, options=[ options, options ]) is not None
    
    return

@mark.parametrize('name', [
    {},
    *[ { "optgroup": v } for v in ("", "group", None)],
])
@mark.parametrize('options', [
    ({}, NameError, "name 'options' is not defined"),
    { "options": [{ "value": "anything" },] },
    { "options": [{ "value": "opt1" }, { "value": "opt2" }] },
])
def test_optgroup_render(name, options):
    params = dict()
    exp_exceptions = []
    for part, ex, msg in map(
        lambda x: x if isinstance(x, tuple) else (x, None, None),
        (name, options)):
        params.update(part)
        if ex is not None:
            exp_exceptions.append(ex)

    if not exp_exceptions:
        assert template('options', **params) is not None
        return

    with raises(tuple(exp_exceptions)):
        assert template('options', **params) is not None

    return
