# -*- coding: utf-8 -*-

import datetime
import sys
import shutil
import copy

from quixote import cleanup
from quixote.http_request import parse_query
import mechanize

import pytest

from wcs import publisher
from wcs.qommon import sessions
from wcs.qommon.form import *
from wcs.qommon.http_request import HTTPRequest

from utilities import create_temporary_pub

def setup_module(module):
    cleanup()
    global pub, req
    pub = create_temporary_pub()

    req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'})
    req.language = None
    pub._set_request(req)

def teardown_module(module):
    shutil.rmtree(pub.APP_DIR)

class MockHtmlForm(object):
    def __init__(self, widget):
        widget = copy.deepcopy(widget)
        form = Form(method='post', use_tokens=False, enctype='application/x-www-form-urlencoded')
        form.widgets.append(widget)
        self.as_html = str(form.render())
        response = mechanize._response.test_html_response(self.as_html, headers=[])
        factory = mechanize.Browser()
        factory.set_response(response)
        self.factory = factory
        self.form = list(factory.forms())[0]

    def set_form_value(self, name, value):
        self.form.set_value(value, name)

    def set_form_hidden_value(self, name, value):
        self.form.find_control(name).readonly = False
        self.form.set_value(value, name)

    def get_parsed_query(self):
        return parse_query(self.form._request_data()[1], 'utf-8')

def mock_form_submission(req, widget, html_vars={}, click=None, hidden_html_vars={}):
    form = MockHtmlForm(widget)
    for k, v in html_vars.items():
        form.set_form_value(k, v)
    for k, v in hidden_html_vars.items():
        form.set_form_hidden_value(k, v)
    if click is not None:
        request = form.form.click(click)
        req.form = parse_query(request.data, 'utf-8')
    else:
        req.form = form.get_parsed_query()

def test_stringwidget_values():
    widget = StringWidget('test')
    form = MockHtmlForm(widget)
    assert 'name="test"' in form.as_html
    req.form = {}
    assert widget.parse() is None

    widget = StringWidget('test', value='foo')
    req.form = {}
    assert widget.parse() == 'foo'

    widget = StringWidget('test', value='foo')
    mock_form_submission(req, widget, {'test': ''})
    assert widget.parse() is None

    widget = StringWidget('test', value='foo')
    mock_form_submission(req, widget, {'test': 'bar'})
    assert widget.parse() == 'bar'

def test_stringwidget_required():
    widget = StringWidget('test', value='foo', required=True)
    mock_form_submission(req, widget, {'test': ''})
    assert widget.has_error()

    widget = StringWidget('test', value='foo', required=True)
    mock_form_submission(req, widget, {'test': 'bar'})
    assert not widget.has_error()
    assert widget.parse() == 'bar'

def test_table_list_rows():
    widget = TableListRowsWidget('test', columns=['a', 'b', 'c'])
    form = MockHtmlForm(widget)
    req.form = {}
    for row in range(5):
        for col in range(3):
            assert 'test$element%d$col%d' % (row, col) in form.as_html

    widget = TableListRowsWidget('test', columns=['a', 'b', 'c'])
    form = MockHtmlForm(widget)
    mock_form_submission(req, widget, {'test$element0$col0': 'bar',
                                       'test$element1$col1': 'foo'})
    assert widget.parse() == [[u'bar', None, None], [None, u'foo', None]]

def test_table_list_rows_add_row():
    widget = TableListRowsWidget('test', columns=['a', 'b', 'c'])
    form = MockHtmlForm(widget)
    req.form = {}
    mock_form_submission(req, widget, click='test$add_element')
    widget = TableListRowsWidget('test', columns=['a', 'b', 'c'])
    form = MockHtmlForm(widget)
    for row in range(6): # one more row
        for col in range(3):
            assert 'test$element%d$col%d' % (row, col) in form.as_html

def test_table_list_rows_required():
    req.form = {}
    widget = TableListRowsWidget('test', columns=['a', 'b', 'c'], required=True)
    form = MockHtmlForm(widget)
    mock_form_submission(req, widget)
    widget = TableListRowsWidget('test', columns=['a', 'b', 'c'], required=True)
    assert widget.has_error()

    req.form = {}
    widget = TableListRowsWidget('test', columns=['a', 'b', 'c'], required=True)
    mock_form_submission(req, widget, click='test$add_element')
    widget = TableListRowsWidget('test', columns=['a', 'b', 'c'], required=True)
    assert not widget.has_error()

def test_table_list_rows_set_many_values():
    widget = TableListRowsWidget('test', columns=['a', 'b', 'c'])
    form = MockHtmlForm(widget)
    req.form = {}
    widget = TableListRowsWidget('test', columns=['a', 'b', 'c'])
    widget.set_value([(str(x), None, None) for x in range(10)])
    form = MockHtmlForm(widget)
    for row in range(10):
        for col in range(3):
            assert 'test$element%d$col%d' % (row, col) in form.as_html
    assert not 'test$element%d$col%d' % (10, 0) in form.as_html

    mock_form_submission(req, widget, click='test$add_element')
    widget = TableListRowsWidget('test', columns=['a', 'b', 'c'])
    form = MockHtmlForm(widget)
    assert 'test$element%d$col%d' % (10, 0) in form.as_html

def test_table_widget():
    req.form = {}
    widget = TableWidget('test', columns=['a', 'b', 'c'], rows=['A', 'B'])
    widget.set_value([['0'], ['1']])
    assert widget.get_widget('c-0-0').value == '0'
    assert widget.get_widget('c-0-1').value is None
    assert widget.get_widget('c-1-0').value == '1'
    assert widget.get_widget('c-1-1').value is None
    form = MockHtmlForm(widget)
    assert 'value="0"' in form.as_html
    assert 'value="1"' in form.as_html

    mock_form_submission(req, widget, {'test$c-0-0': 'X', 'test$c-0-1': 'Y'})
    assert widget.parse() == [[u'X', u'Y', None], [u'1', None, None]]

def test_passwordentry_widget_success():
    widget = PasswordEntryWidget('test')
    form = MockHtmlForm(widget)
    assert 'name="test$pwd1"' in form.as_html
    req.form = {}
    assert widget.parse() is None

    widget = PasswordEntryWidget('test', value={'cleartext': 'foo'}, formats=['cleartext'])
    req.form = {}
    assert widget.parse() == {'cleartext': 'foo'}

    widget = PasswordEntryWidget('test', formats=['cleartext'])
    req.form = {}
    mock_form_submission(req, widget, {'test$pwd1': ''})
    assert widget.parse() is None

    widget = PasswordEntryWidget('test', formats=['cleartext'])
    req.form = {}
    mock_form_submission(req, widget, {'test$pwd1': 'foo', 'test$pwd2': 'foo'})
    assert widget.parse() == {'cleartext': 'foo'}

    widget = PasswordEntryWidget('test', formats=['cleartext'], confirmation=False)
    req.form = {}
    mock_form_submission(req, widget, {'test$pwd1': 'foo'})
    assert widget.parse() == {'cleartext': 'foo'}


def test_passwordentry_widget_errors():
    # mismatch
    widget = PasswordEntryWidget('test', formats=['cleartext'])
    req.form = {}
    mock_form_submission(req, widget, {'test$pwd1': 'foo', 'test$pwd2': 'bar'})
    assert widget.parse() is None
    assert widget.has_error() is True

    # too short
    widget = PasswordEntryWidget('test', formats=['cleartext'], min_length=4)
    req.form = {}
    mock_form_submission(req, widget, {'test$pwd1': 'foo', 'test$pwd2': 'foo'})
    assert widget.parse() is None
    assert widget.has_error() is True

    # uppercases
    widget = PasswordEntryWidget('test', formats=['cleartext'], count_uppercase=1)
    req.form = {}
    mock_form_submission(req, widget, {'test$pwd1': 'foo', 'test$pwd2': 'foo'})
    assert widget.parse() is None
    assert widget.has_error() is True

    # digits
    widget = PasswordEntryWidget('test', formats=['cleartext'], count_digit=1)
    req.form = {}
    mock_form_submission(req, widget, {'test$pwd1': 'foo', 'test$pwd2': 'foo'})
    assert widget.parse() is None
    assert widget.has_error() is True

    # specials
    widget = PasswordEntryWidget('test', formats=['cleartext'], count_special=1)
    req.form = {}
    mock_form_submission(req, widget, {'test$pwd1': 'foo', 'test$pwd2': 'foo'})
    assert widget.parse() is None
    assert widget.has_error() is True


def test_textwidget():
    widget = TextWidget('test')
    form = MockHtmlForm(widget)
    assert 'name="test"' in form.as_html
    req.form = {}
    assert widget.parse() is None

    widget = TextWidget('test', value='foo')
    req.form = {}
    assert widget.parse() == 'foo'

    widget = TextWidget('test', value='foo')
    mock_form_submission(req, widget, {'test': ''})
    assert widget.parse() is None

    widget = TextWidget('test', value='foo')
    mock_form_submission(req, widget, {'test': 'bar'})
    assert widget.parse() == 'bar'

    widget = TextWidget('test', value='foo', maxlength=10)
    mock_form_submission(req, widget, {'test': 'bar'})
    assert not widget.has_error()
    assert widget.parse() == 'bar'

    widget = TextWidget('test', value='foo', maxlength=10)
    mock_form_submission(req, widget, {'test': 'bar'*10})
    assert widget.has_error()
    assert widget.get_error() == 'too many characters (limit is 10)'


def test_emailwidget():
    widget = EmailWidget('test')
    form = MockHtmlForm(widget)
    assert 'name="test"' in form.as_html
    req.form = {}
    assert widget.parse() is None

    widget = EmailWidget('test')
    mock_form_submission(req, widget, {'test': 'foo@localhost'})
    assert not widget.has_error()
    assert widget.parse() == 'foo@localhost'

    widget = EmailWidget('test')
    mock_form_submission(req, widget, {'test': 'foo'})
    assert widget.has_error()

    widget = EmailWidget('test')
    mock_form_submission(req, widget, {'test': 'foo@localhost@test'})
    assert widget.has_error()

    widget = EmailWidget('test')
    mock_form_submission(req, widget, {'test': 'foo@localhost..localdomain'})
    assert widget.has_error()

def test_date_widget():
    widget = DateWidget('test')
    form = MockHtmlForm(widget)
    assert 'name="test"' in form.as_html
    req.form = {}
    assert widget.parse() is None

    pub.cfg['language'] = {'language': 'en'}
    widget = DateWidget('test')
    mock_form_submission(req, widget, {'test': '2014-1-20'})
    assert not widget.has_error()
    assert widget.parse() == '2014-01-20'

    # check two-digit years
    widget = DateWidget('test')
    mock_form_submission(req, widget, {'test': '14-1-20'})
    assert not widget.has_error()
    assert widget.parse() == '2014-01-20'

    widget = DateWidget('test', maximum_date='1/1/2014') # accept "fr" format
    mock_form_submission(req, widget, {'test': '2014-1-20'})
    assert widget.has_error()

    pub.cfg['language'] = {'language': 'fr'}
    widget = DateWidget('test')
    mock_form_submission(req, widget, {'test': '20/1/2014'})
    assert not widget.has_error()
    assert widget.parse() == '20/01/2014'

    mock_form_submission(req, widget, {'test': '2014-1-20'})
    assert not widget.has_error()
    assert widget.parse() == '20/01/2014'

    widget = DateWidget('test', minimum_date='1/1/2014')
    mock_form_submission(req, widget, {'test': '20/1/2014'})
    assert not widget.has_error()

    widget = DateWidget('test', minimum_date='1/1/2014')
    mock_form_submission(req, widget, {'test': '20/1/2013'})
    assert widget.has_error()

    widget = DateWidget('test', maximum_date='1/1/2014')
    mock_form_submission(req, widget, {'test': '20/1/2013'})
    assert not widget.has_error()

    widget = DateWidget('test', maximum_date='1/1/2014')
    mock_form_submission(req, widget, {'test': '20/1/2014'})
    assert widget.has_error()

    widget = DateWidget('test', maximum_date='2014-1-1') # accept "C" format
    mock_form_submission(req, widget, {'test': '20/1/2014'})
    assert widget.has_error()

    yesterday = (datetime.date.today() - datetime.timedelta(days=1)).strftime(widget.get_format_string())
    tomorrow = (datetime.date.today() + datetime.timedelta(days=1)).strftime(widget.get_format_string())

    widget = DateWidget('test', minimum_is_future=True)
    mock_form_submission(req, widget, {'test': tomorrow})
    assert not widget.has_error()

    widget = DateWidget('test', minimum_is_future=True)
    mock_form_submission(req, widget, {'test': yesterday})
    assert widget.has_error()

    widget = DateWidget('test', date_in_the_past=True)
    mock_form_submission(req, widget, {'test': tomorrow})
    assert widget.has_error()

    widget = DateWidget('test', date_in_the_past=True)
    mock_form_submission(req, widget, {'test': yesterday})
    assert not widget.has_error()


def test_wysiwygwidget():
    widget = WysiwygTextWidget('test')
    form = MockHtmlForm(widget)
    assert 'name="test"' in form.as_html
    req.form = {}
    assert widget.parse() is None

    widget = WysiwygTextWidget('test')
    mock_form_submission(req, widget, {'test': 'bla bla bla'})
    assert not widget.has_error()
    assert widget.parse() == 'bla bla bla'

    import wcs.qommon.form
    sanitize_html = wcs.qommon.form._sanitizeHTML
    if sanitize_html:
        widget = WysiwygTextWidget('test')
        mock_form_submission(req, widget, {'test': '<p>bla bla bla</p>'})
        assert not widget.has_error()
        assert widget.parse() == '<p>bla bla bla</p>'

        widget = WysiwygTextWidget('test')
        mock_form_submission(req, widget, {'test': '<a href="#">a</a>'})
        assert not widget.has_error()
        assert widget.parse() == '<a href="#">a</a>'

        widget = WysiwygTextWidget('test')
        mock_form_submission(req, widget, {'test': '<a href="javascript:alert()">a</a>'})
        assert not widget.has_error()
        assert widget.parse() == '<a href="">a</a>' # javascript: got filtered

    # check django syntax is kept intact
    widget = WysiwygTextWidget('test')
    mock_form_submission(req, widget, {'test': '<a href="{% if 1 > 2 %}héllo{% endif %}">{% if 2 > 1 %}{{plop|date:"Y"}}{% endif %}</a>'})
    assert not widget.has_error()
    assert widget.parse() == '<a href="{% if 1 > 2 %}héllo{% endif %}">{% if 2 > 1 %}{{plop|date:"Y"}}{% endif %}</a>'

    # make sure it is kept intact even after ckeditor escaped characters
    widget = WysiwygTextWidget('test')
    mock_form_submission(req, widget, {'test': '<a href="{% if 1 &gt; 2 %}héllo{% endif %}">{% if 2 &gt; 1 %}{{plop|date:&quot;Y&quot;}}{% endif %}</a>'})
    assert not widget.has_error()
    assert widget.parse() == '<a href="{% if 1 > 2 %}héllo{% endif %}">{% if 2 > 1 %}{{plop|date:"Y"}}{% endif %}</a>'

    # check we don't escape HTML if feedparser _sanitizeHTML is missing
    wcs.qommon.form._sanitizeHTML = None
    widget = WysiwygTextWidget('test')
    mock_form_submission(req, widget, {'test': '<p>bla bla bla</p>'})
    assert not widget.has_error()
    assert widget.parse() == '<p>bla bla bla</p>'
    wcs.qommon.form._sanitizeHTML = sanitize_html

def test_select_widget():
    widget = SingleSelectHintWidget('test',
            options=[
                ('apple', 'Apple', 'apple'),
                 ('pear', 'Pear', 'pear'),
                 ('peach', 'Peach', 'peach')])
    assert widget.has_valid_options()

    widget = SingleSelectHintWidget('test',
            options=[
                ('apple', 'Apple', 'apple'),
                 ('pear', 'Pear', 'pear'),
                 ('peach', 'Peach', 'peach')],
            options_with_attributes=[
                ('apple', 'Apple', 'apple', {}),
                ('pear', 'Pear', 'pear', {'disabled': True}),
                ('peach', 'Peach', 'peach', {})])
    assert widget.has_valid_options()
    mock_form_submission(req, widget, {'test': ['apple']})
    assert widget.parse() == 'apple'

    with pytest.raises(AttributeError):
        # mechanize will
        #   raise AttributeError(
        #     "insufficient non-disabled items with name %s" % name)
        # as the item is disabled
        mock_form_submission(req, widget, {'test': ['pear']})

    widget = SingleSelectHintWidget('test',
            options=[
                ('apple', 'Apple', 'apple'),
                 ('pear', 'Pear', 'pear'),
                 ('peach', 'Peach', 'peach')],
            options_with_attributes=[
                ('apple', 'Apple', 'apple', {'disabled': True}),
                ('pear', 'Pear', 'pear', {'disabled': True}),
                ('peach', 'Peach', 'peach', {'disabled': True})])
    assert not widget.has_valid_options()

def test_select_or_other_widget():
    widget = SingleSelectWidgetWithOther('test',
            options=[('apple', 'Apple'), ('pear', 'Pear'), ('peach', 'Peach')])
    form = MockHtmlForm(widget)
    assert '__other' in form.as_html
    assert 'Other:' in form.as_html
    assert widget.parse() is None

    widget = SingleSelectWidgetWithOther('test',
            options=[('apple', 'Apple'), ('pear', 'Pear'), ('peach', 'Peach')],
            other_label='Alternative:')
    form = MockHtmlForm(widget)
    assert '__other' in form.as_html
    assert 'Alternative:' in form.as_html

    widget = SingleSelectWidgetWithOther('test',
            options=[('apple', 'Apple'), ('pear', 'Pear'), ('peach', 'Peach')])
    mock_form_submission(req, widget, {'test$choice': ['apple']})
    assert widget.parse() == 'apple'

    widget = SingleSelectWidgetWithOther('test',
            options=[('apple', 'Apple'), ('pear', 'Pear'), ('peach', 'Peach')])
    mock_form_submission(req, widget, {'test$choice': ['__other'], 'test$other': 'Apricot'})
    assert widget.parse() == 'Apricot'


def test_checkboxes_widget():
    widget = CheckboxesWidget('test',
            options=[('apple', 'Apple', 'apple'), ('pear', 'Pear', 'pear'), ('peach', 'Peach', 'peach')])
    mock_form_submission(req, widget, {'test$elementpeach': ['yes'], 'test$elementpear': ['yes']})
    assert widget.parse() == ['pear', 'peach']


def test_composite_widget():
    widget = CompositeWidget('compotest')
    widget.add(StringWidget, name='str1')
    widget.add(StringWidget, name='str2', required=True)
    req.form = {'compotest$str1': 'foo1', 'compotest$str2': 'foo2'}
    form = MockHtmlForm(widget)
    assert not widget.has_error()
    assert len(widget.widgets) == 2
    assert widget.widgets[0].parse() == 'foo1'
    assert widget.widgets[1].parse() == 'foo2'

    widget = CompositeWidget('compotest')
    widget.add(StringWidget, name='str1')
    widget.add(StringWidget, name='str2', required=True)
    req.form = {'compotest$str1': 'alone'}
    form = MockHtmlForm(widget)
    assert widget.has_error()
    assert not widget.widgets[0].has_error()
    assert widget.widgets[0].parse() == 'alone'
    assert widget.widgets[1].has_error()
    assert 'required' in widget.widgets[1].get_error()

    req.session = sessions.Session(id=1)  # needed by FileWithPreviewWidget
    widget = CompositeWidget('compotest')
    widget.add(StringWidget, name='str1')
    widget.add(FileWithPreviewWidget, name='')
    assert 'class="FileWithPreviewWidget widget file-upload-widget"' in str(
        widget.render_content_as_tr())  # extra_css_class is present


def test_computed_expression_widget():
    widget = ComputedExpressionWidget('test')
    form = MockHtmlForm(widget)
    mock_form_submission(req, widget, {'test$value_text': 'hello world', 'test$type': ['text']})
    assert widget.parse() == 'hello world'
    assert not widget.has_error()

    widget = ComputedExpressionWidget('test')
    form = MockHtmlForm(widget)
    mock_form_submission(req, widget, {'test$value_text': '', 'test$type': ['text']})
    assert widget.parse() == None
    assert not widget.has_error()

    widget = ComputedExpressionWidget('test')
    mock_form_submission(req, widget, {'test$value_python': 'hello world', 'test$type': ['python']})
    assert widget.has_error()
    assert widget.get_error().startswith('syntax error')

    widget = ComputedExpressionWidget('test')
    mock_form_submission(req, widget, {'test$value_python': '=3', 'test$type': ['python']})
    assert widget.has_error()
    assert widget.get_error().startswith('syntax error')

    widget = ComputedExpressionWidget('test')
    mock_form_submission(req, widget, {'test$value_python': '', 'test$type': ['python']})
    assert widget.has_error()
    assert widget.get_error().startswith('syntax error')

    widget = ComputedExpressionWidget('test')
    mock_form_submission(req, widget, {'test$type': ['python']})
    assert widget.has_error()
    assert widget.get_error().startswith('syntax error')

    widget = ComputedExpressionWidget('test')
    mock_form_submission(req, widget, {'test$value_python': '{{form_var_foo}}', 'test$type': ['python']})
    assert widget.has_error()
    assert 'Python expression cannot contain {{' in widget.get_error()

    widget = ComputedExpressionWidget('test')
    mock_form_submission(req, widget, {'test$value_template': '{{ form_var_xxx }}', 'test$type': ['template']})
    assert not widget.has_error()

    widget = ComputedExpressionWidget('test')
    mock_form_submission(req, widget, {'test$value_template': '{% if True %}', 'test$type': ['template']})
    assert widget.has_error()
    assert widget.get_error().startswith('syntax error in Django template')

    widget = ComputedExpressionWidget('test')
    mock_form_submission(req, widget, {'test$value_template': '[form_var_xxx]', 'test$type': ['template']})
    assert not widget.has_error()

    widget = ComputedExpressionWidget('test')
    mock_form_submission(req, widget, {'test$value_template': '[end]', 'test$type': ['template']})
    assert widget.has_error()
    assert widget.get_error().startswith('syntax error in ezt template')

def test_wcsextrastringwidget():
    widget = WcsExtraStringWidget('test', value='foo', required=True)
    mock_form_submission(req, widget, {'test': ''})
    assert widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=True)
    mock_form_submission(req, widget, {'test': 'bar'})
    assert not widget.has_error()
    assert widget.parse() == 'bar'

def test_wcsextrastringwidget_regex_validation():
    # check regex validation
    class FakeField: pass
    fakefield = FakeField()
    fakefield.validation = {'type': 'regex', 'value': r'\d+'}

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '123'})
    assert not widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '123 ab'})
    assert widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': 'cdab 12'})
    assert widget.has_error()

    fakefield.validation = {'type': 'regex', 'value': r'\d+(\.\d{1,2})?'}
    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '12'})
    assert not widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '12.34'})
    assert not widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '12,34'})
    assert widget.has_error()

def test_wcsextrastringwidget_builtin_validation():
    class FakeField: pass
    fakefield = FakeField()

    fakefield.validation = {'type': 'digits'}
    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '12'})
    assert not widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': 'az'})
    assert widget.has_error()

    fakefield.validation = {'type': 'zipcode-fr'}
    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '12345'})
    assert not widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '1234'})
    assert widget.has_error()

def test_wcsextrastringwidget_siren_validation():
    class FakeField: pass
    fakefield = FakeField()
    fakefield.validation = {'type': 'siren-fr'}

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '443170139'})
    assert not widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '443170130'})
    assert widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '44317013900036'})
    assert widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': 'XXX170130'})
    assert widget.has_error()


def test_wcsextrastringwidget_siret_validation():
    class FakeField: pass
    fakefield = FakeField()
    fakefield.validation = {'type': 'siret-fr'}

    # regular case
    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '44317013900036'})
    assert not widget.has_error()

    # special case la poste
    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '35600000000048'})
    assert not widget.has_error()

    # failing cases
    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '44317013900037'})
    assert widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': 'ABC17013900037'})
    assert widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '443170139'})
    assert widget.has_error()


def test_wcsextrastringwidget_nir_validation():
    class FakeField: pass
    fakefield = FakeField()
    fakefield.validation = {'type': 'nir-fr'}

    # regular cases
    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    # https://fr.wikipedia.org/wiki/Num%C3%A9ro_de_s%C3%A9curit%C3%A9_sociale_en_France#/media/Fichier:CarteVitale2.jpg
    mock_form_submission(req, widget, {'test': '269054958815780'})
    assert not widget.has_error()

    # corsica
    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '269052A58815717'})
    assert not widget.has_error()
    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '269052B58815744'})
    assert not widget.has_error()

    # failing cases
    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '42'})
    assert widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '269054958815700'})
    assert widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': 'hello 789012345'})
    assert widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '069054958815780'})
    assert widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '269004958815780'})
    assert widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '269054900015780'})
    assert widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '269054958800080'})
    assert widget.has_error()


def test_wcsextrastringwidget_iban_validation():
    class FakeField: pass
    fakefield = FakeField()
    fakefield.validation = {'type': 'iban'}

    # regular cases
    for iban in ['BE71 0961 2345 6769',                # Belgium
                 'FR76 3000 6000 0112 3456 7890 189',  # France
                 'FR27 2004 1000 0101 2345 6Z02 068',  # France (having letter)
                 'DE91 1000 0000 0123 4567 89',        # Germany
                 'GR96 0810 0010 0000 0123 4567 890',  # Greece
                 'RO09 BCYP 0000 0012 3456 7890',      # Romania
                 'SA44 2000 0001 2345 6789 1234',      # Saudi Arabia
                 'ES79 2100 0813 6101 2345 6789',      # Spain
                 'CH56 0483 5012 3456 7800 9',         # Switzerland
                 'GB98 MIDL 0700 9312 3456 78',        # United Kingdom
            ]:
        widget = WcsExtraStringWidget('test', value='foo', required=False)
        widget.field = fakefield
        mock_form_submission(req, widget, {'test': iban.replace(' ', '')})
        assert not widget.has_error()

    # failing cases
    for iban in ['42',
                 'FR76 2004 1000 0101 2345 6Z02 068',
                 'FR76 2004 1000 0101 2345 6%02 068',
                 'FR76 hello 234 6789 1234 6789 123',
                 'FRxx 2004 1000 0101 2345 6Z02 068',
            ]:
        widget = WcsExtraStringWidget('test', value='foo', required=False)
        widget.field = fakefield
        mock_form_submission(req, widget, {'test': iban.replace(' ', '')})
        assert widget.has_error()


def test_wcsextrastringwidget_django_validation():
    class FakeField: pass
    fakefield = FakeField()

    fakefield.validation = {'type': 'django', 'value': 'value|decimal and value|decimal < 20'}
    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '12'})
    assert not widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': '35'})
    assert widget.has_error()

    widget = WcsExtraStringWidget('test', value='foo', required=False)
    widget.field = fakefield
    mock_form_submission(req, widget, {'test': 'az'})
    assert widget.has_error()


def test_widgetdict_widget():
    widget = WidgetDict('test', value={'a': None, 'b': None, 'c': None})
    mock_form_submission(req, widget, {'test$element0key': 'a', 'test$element0value': 'value-a',
                                       'test$element1key': 'c', 'test$element1value': 'value-c',
                                       'test$element2key': 'b', 'test$element2value': 'value-b'})
    assert widget.parse() == {'a': 'value-a', 'b': 'value-b', 'c': 'value-c'}

    # on rendering, elements are ordered by their key name
    html_frags = str(widget.render_content()).split()
    assert (html_frags.index('name="test$element0key"') <  # a
            html_frags.index('name="test$element2key"') <  # b
            html_frags.index('name="test$element1key"'))   # c

def test_map_widget():
    widget = MapWidget('test', title='Map')
    form = MockHtmlForm(widget)
    assert 'name="test$latlng"' in form.as_html
    req.form = {}
    assert widget.parse() is None

    widget = MapWidget('test', title='Map')
    mock_form_submission(req, widget, hidden_html_vars={'test$latlng': '1.23;2.34'})
    assert not widget.has_error()
    assert widget.parse() == '1.23;2.34'

    assert '<label' in str(widget.render())
    assert not '<label ' in str(widget.render_widget_content())

    pub.load_site_options()
    pub.site_options.set('options', 'map-bounds-top-left', '1.23;2.34')
    pub.site_options.set('options', 'map-bounds-bottom-right', '2.34;3.45')
    widget = MapWidget('test', title='Map')
    assert 'data-max-bounds-lat1=' in str(widget.render())
    assert 'data-max-bounds-lat2=' in str(widget.render())
    assert 'data-max-bounds-lng1=' in str(widget.render())
    assert 'data-max-bounds-lng2=' in str(widget.render())
