import py
import cgi
import datetime
import decimal
import field

class TestField(object):
    def test_value_from_data(self):
        f = field.field('foo', 'foo')
        assert f.value_from_data({'foo': 'bar'}) == 'bar'
        fs = cgi.FieldStorage(environ={'QUERY_STRING': 'foo=bar'})
        assert f.value_from_data(fs) == 'bar'

    def test_validate(self):
        class myvalidator(object):
            def validate(self, value):
                if value == 'foo':
                    return
                raise ValueError('foo')
        f = field.field('foo', 'foo', validators=(myvalidator(),))
        f.validate('foo')
        py.test.raises(ValueError, "f.validate('bar')")

    def test_validate_mandatory(self):
        f = field.field('foo', 'foo')
        f.validate('foo')
        py.test.raises(ValueError, "f.validate('')")

        f = field.field('foo', 'foo', mandatory=False)
        f.validate('')

    def test_render(self):
        class myfield(field.field):
            def render_validated(self, value, error):
                return '<input value="%s" />' % (value,)

        f = myfield('foo', 'foo', value='default')

        # can it deal with None input?
        html, error = f.render(None)
        assert not error
        assert html == '<input value="default" />'

        # can it deal with proper input?
        html, error = f.render({'foo': 'bar'})
        assert not error
        assert html == '<input value="bar" />'

        # can it deal with wrong input?
        html, error = f.render({'foo': ''})
        assert error == 'field is mandatory'
        assert html == '<input value="" />'

    # not sure about testing the render methods verbatim
    def test_render_validated(self):
        f = field.field('foo', 'foo field')
        html = f.render_validated('bar', None)
        expected = '\n'.join([
            '<div class="former-field-mandatory">',
            '<div class="former-label">',
            '<label for="foo">foo field</label>',
            '</div>',
            '<input />',
            '</div>',
        ])
        assert html == expected

    def test_render_validated_error(self):
        f = field.field('foo', 'foo field')
        html = f.render_validated('bar', 'some error')
        expected = '\n'.join([
            '<div class="former-field-mandatory">',
            '<div class="former-error">some error</div>',
            '<div class="former-label">',
            '<label for="foo">foo field</label>',
            '</div>',
            '<input />',
            '</div>',
        ])
        assert html == expected

    def test_render_attrs(self):
        f = field.field('foo', 'foo field', attributes=('class="spam"',))
        html = f.render_validated('bar', None)
        expected = '\n'.join([
            '<div class="former-field-mandatory">',
            '<div class="former-label">',
            '<label for="foo">foo field</label>',
            '</div>',
            '<input class="spam" />',
            '</div>',
        ])


class TestLine(object):
    def test_basic(self):
        f = field.line('foo', 'foo')
        assert f.render_tag('bar', None) == (
            '<input type="text" name="foo" id="foo" value="bar" />')
        assert f.render_tag('', 'field is mandatory') == (
            '<input type="text" name="foo" id="foo" value="" />')


class TestPassword(object):
    def test_basic(self):
        f =field.password('foo', 'foo')
        assert f.render_tag('bar', None) == (
            '<input type="password" name="foo" id="foo" value="" />')


class TestInt(object):
    def test_value_from_data(self):
        f = field.integer('foo', 'foo')
        assert f.value_from_data({'foo': '1'}) == 1
        assert f.value_from_data({'foo': '-1'}) == -1

    def test_render(self):
        f = field.integer('foo', 'foo')
        html, error = f.render({'foo': '1'})
        expected = '\n'.join([
            '<div class="former-field-mandatory">',
            '<div class="former-label">',
            '<label for="foo">foo</label>',
            '</div>',
            '<input type="text" name="foo" id="foo" value="1" />',
            '</div>',
        ])
        assert html == expected


class TestDate(object):
    def test_value_from_data(self):
        f = field.date('date', 'date')
        assert (f.value_from_data({'date': '2008/01/01'}) ==
                datetime.date(2008, 1, 1))
        assert (f.value_from_data({'date': '1-2-2008'}) ==
                datetime.date(2008, 2, 1))

    def test_render_tag(self):
        f = field.date('date', 'date')
        assert f.render_tag(datetime.date(2008, 2, 1), None) == (
            '<input type="text" name="date" id="date" value="1-2-2008" />')

        f = field.date('date', 'date')
        assert f.render_tag('', None) == (
            '<input type="text" name="date" id="date" value="" />')


class TestMoney(object):
    def test_value_from_data(self):
        f = field.money('price', 'price')
        assert f.value_from_data({'price': '1.00'}) == decimal.Decimal('1.0')

    def test_render_tag(self):
        f = field.money('price', 'price')
        assert f.render_tag(decimal.Decimal('1.0'), None) == (
            '<input type="text" name="price" id="price" value="1,00" />')

        f = field.money('price', 'price')
        assert f.render_tag('', None) == (
            '<input type="text" name="price" id="price" value="" />')


class TestText(object):
    def test_basic(self):
        f = field.text('foo', 'foo')
        assert f.render_tag('bar baz qux', None) == (
            '<textarea name="foo" id="foo">bar baz qux</textarea>')


class TestMultifield(object):
    def test_value_from_data(self):
        f = field.multifield('foo', 'foo', (('s', 'spam'), ('e', 'eggs')))
        assert f.value_from_data({'foo': ['s']}) == ['s']
        assert f.value_from_data({'foo': ['s', 'e']}) == ['s', 'e']
        assert f.value_from_data({'foo': 's'}) == ['s']
        assert f.value_from_data({'foo': []}) == []


class TestRadio(object):
    def test_no_values_mandatory(self):
        f = field.radio('foo', 'foo', (('s', 'spam'), ('e', 'eggs')))
        html = f.render_tag([], None)
        expected = '\n'.join([
            '<div class="former-field-valuegroup">',
            ('<input type="radio" name="foo" id="foo-0" value="s" '
             'checked="checked" />'),
            '<label for="foo-0">spam</label>',
            '<input type="radio" name="foo" id="foo-1" value="e" />',
            '<label for="foo-1">eggs</label>',
            '</div>',
        ])
        assert html == expected

    def test_no_values_optional(self):
        f = field.radio('foo', 'foo', (('s', 'spam'), ('e', 'eggs')),
                        mandatory=False)
        html = f.render_tag([], None)
        expected = '\n'.join([
            '<div class="former-field-valuegroup">',
            '<input type="radio" name="foo" id="foo-0" value="s" />',
            '<label for="foo-0">spam</label>',
            '<input type="radio" name="foo" id="foo-1" value="e" />',
            '<label for="foo-1">eggs</label>',
            '</div>',
        ])
        assert html == expected

    def test_with_value(self):
        f = field.radio('foo', 'foo', (('s', 'spam'), ('e', 'eggs')))
        html = f.render_tag('e', None)
        expected = '\n'.join([
            '<div class="former-field-valuegroup">',
            '<input type="radio" name="foo" id="foo-0" value="s" />',
            '<label for="foo-0">spam</label>',
            ('<input type="radio" name="foo" id="foo-1" value="e" '
             'checked="checked" />'),
            '<label for="foo-1">eggs</label>',
            '</div>',
        ])
        assert html == expected


class TestCheckbox(object):
    def test_no_values_mandatory(self):
        f = field.checkbox('foo', 'foo', (('s', 'spam'), ('e', 'eggs')))
        html = f.render_tag([], None)
        expected = '\n'.join([
            '<div class="former-field-valuegroup">',
            ('<input type="checkbox" name="foo" id="foo-0" value="s" '
             'checked="checked" />'),
            '<label for="foo-0">spam</label>',
            '<input type="checkbox" name="foo" id="foo-1" value="e" />',
            '<label for="foo-1">eggs</label>',
            '</div>',
        ])
        assert html == expected

    def test_no_values_optional(self):
        f = field.checkbox('foo', 'foo', (('s', 'spam'), ('e', 'eggs')),
                           mandatory=False)
        html = f.render_tag([], None)
        expected = '\n'.join([
            '<div class="former-field-valuegroup">',
            '<input type="checkbox" name="foo" id="foo-0" value="s" />',
            '<label for="foo-0">spam</label>',
            '<input type="checkbox" name="foo" id="foo-1" value="e" />',
            '<label for="foo-1">eggs</label>',
            '</div>',
        ])
        assert html == expected

    def test_with_value(self):
        f = field.checkbox('foo', 'foo', (('s', 'spam'), ('e', 'eggs')))
        html = f.render_tag(['e'], None)
        expected = '\n'.join([
            '<div class="former-field-valuegroup">',
            '<input type="checkbox" name="foo" id="foo-0" value="s" />',
            '<label for="foo-0">spam</label>',
            ('<input type="checkbox" name="foo" id="foo-1" value="e" '
             'checked="checked" />'),
            '<label for="foo-1">eggs</label>',
            '</div>',
        ])
        assert html == expected


    def test_more_values(self):
        f = field.checkbox('foo', 'foo', (('s', 'spam'), ('e', 'eggs')))
        html = f.render_tag(['s', 'e'], None)
        expected = '\n'.join([
            '<div class="former-field-valuegroup">',
            ('<input type="checkbox" name="foo" id="foo-0" value="s" '
             'checked="checked" />'),
            '<label for="foo-0">spam</label>',
            ('<input type="checkbox" name="foo" id="foo-1" value="e" '
             'checked="checked" />'),
            '<label for="foo-1">eggs</label>',
            '</div>',
        ])
        assert html == expected

