text: #!/usr/bin/env python
  from __future__ import unicode_literals
  
  import sys
  
  from datetime import date, datetime
  from decimal import Decimal, ROUND_UP, ROUND_DOWN
  from unittest import TestCase
  
  from wtforms import validators, widgets
  from wtforms.fields import *
  from wtforms.fields import Label, Field
  from wtforms.form import Form
  from wtforms.compat import text_type
  
  
  PYTHON_VERSION = sys.version_info
  
  class DummyPostData(dict):
      def getlist(self, key):
          v = self[key]
          if not isinstance(v, (list, tuple)):
              v = [v]
          return v
  
  class AttrDict(object):
      def __init__(self, *args, **kw):
          self.__dict__.update(*args, **kw)
  
  def make_form(_name='F', **fields):
      return type(str(_name), (Form, ), fields)
  
  
  class DefaultsTest(TestCase):
      def test(self):
          expected = 42
  
          def default_callable():
              return expected
  
          test_value = TextField(default=expected).bind(Form(), 'a')
          test_value.process(None)
          self.assertEqual(test_value.data, expected)
  
          test_callable = TextField(default=default_callable).bind(Form(), 'a')
          test_callable.process(None)
          self.assertEqual(test_callable.data, expected)
  
  
  class LabelTest(TestCase):
      def test(self):
          expected = """<label for="test">Caption</label>"""
          label = Label('test', 'Caption')
          self.assertEqual(label(), expected)
          self.assertEqual(str(label), expected)
          self.assertEqual(text_type(label), expected)
          self.assertEqual(label.__html__(), expected)
          self.assertEqual(label().__html__(), expected)
          self.assertEqual(label('hello'), """<label for="test">hello</label>""")
          self.assertEqual(TextField('hi').bind(Form(), 'a').label.text, 'hi')
          if PYTHON_VERSION < (3,):
              self.assertEqual(repr(label), "Label(u'test', u'Caption')")
          else:
              self.assertEqual(repr(label), "Label('test', 'Caption')")
  
      def test_auto_label(self):
          t1 = TextField().bind(Form(), 'foo_bar')
          self.assertEqual(t1.label.text, 'Foo Bar')
  
          t2 = TextField('').bind(Form(), 'foo_bar')
          self.assertEqual(t2.label.text, '')
  
  
  class FlagsTest(TestCase):
      def setUp(self):
          t = TextField(validators=[validators.Required()]).bind(Form(), 'a')
          self.flags = t.flags
  
      def test_existing_values(self):
          self.assertEqual(self.flags.required, True)
          self.assertTrue('required' in self.flags)
          self.assertEqual(self.flags.optional, False)
          self.assertTrue('optional' not in self.flags)
  
      def test_assignment(self):
          self.assertTrue('optional' not in self.flags)
          self.flags.optional = True
          self.assertEqual(self.flags.optional, True)
          self.assertTrue('optional' in self.flags)
  
      def test_unset(self):
          self.flags.required = False
          self.assertEqual(self.flags.required, False)
          self.assertTrue('required' not in self.flags)
  
      def test_repr(self):
          self.assertEqual(repr(self.flags), '<wtforms.fields.Flags: {required}>')
  
  
  class FiltersTest(TestCase):
      class F(Form):
          a = TextField(default=' hello', filters=[lambda x: x.strip()])
          b = TextField(default='42', filters=[lambda x: int(x)])
  
      def test_working(self):
          form = self.F()
          self.assertEqual(form.a.data, 'hello')
          self.assertEqual(form.b.data, 42)
          assert form.validate()
  
      def test_failure(self):
          form = self.F(DummyPostData(a=['  foo bar  '], b=['hi']))
          self.assertEqual(form.a.data, 'foo bar')
          self.assertEqual(form.b.data, 'hi')
          self.assertEqual(len(form.b.process_errors), 1)
          assert not form.validate()
  
  
  class FieldTest(TestCase):
      class F(Form):
          a = TextField(default='hello')
  
      def setUp(self):
          self.field = self.F().a
  
      def test_unbound_field(self):
          unbound = self.F.a
          assert unbound.creation_counter != 0
          assert unbound.field_class is TextField
          self.assertEqual(unbound.args, ())
          self.assertEqual(unbound.kwargs, {'default': 'hello'})
          assert repr(unbound).startswith('<UnboundField(TextField')
  
      def test_htmlstring(self):
          self.assertTrue(isinstance(self.field.__html__(), widgets.HTMLString))
  
      def test_str_coerce(self):
          self.assertTrue(isinstance(str(self.field), str))
          self.assertEqual(str(self.field), str(self.field()))
  
      def test_unicode_coerce(self):
          self.assertEqual(text_type(self.field), self.field())
  
      def test_process_formdata(self):
          Field.process_formdata(self.field, [42])
          self.assertEqual(self.field.data, 42)
  
  
  class PrePostTestField(TextField):
      def pre_validate(self, form):
          if self.data == "stoponly":
              raise validators.StopValidation()
          elif self.data.startswith("stop"):
              raise validators.StopValidation("stop with message")
  
      def post_validate(self, form, stopped):
          if self.data == "p":
              raise ValueError("Post")
          elif stopped and self.data == "stop-post":
              raise ValueError("Post-stopped")
  
  
  class PrePostValidationTest(TestCase):
      class F(Form):
          a = PrePostTestField(validators=[validators.Length(max=1, message="too long")])
  
      def _init_field(self, value):
          form = self.F(a=value)
          form.validate()
          return form.a
  
      def test_pre_stop(self):
          a = self._init_field("long")
          self.assertEqual(a.errors, ["too long"])
  
          stoponly = self._init_field("stoponly")
          self.assertEqual(stoponly.errors, [])
  
          stopmessage = self._init_field("stopmessage")
          self.assertEqual(stopmessage.errors, ["stop with message"])
  
      def test_post(self):
          a = self._init_field("p")
          self.assertEqual(a.errors, ["Post"])
          stopped = self._init_field("stop-post")
          self.assertEqual(stopped.errors, ["stop with message", "Post-stopped"])
  
  
  class SelectFieldTest(TestCase):
      class F(Form):
          a = SelectField(choices=[('a', 'hello'), ('btest','bye')], default='a')
          b = SelectField(choices=[(1, 'Item 1'), (2, 'Item 2')], coerce=int, option_widget=widgets.TextInput())
  
      def test_defaults(self):
          form = self.F()
          self.assertEqual(form.a.data, 'a')
          self.assertEqual(form.b.data, None)
          self.assertEqual(form.validate(), False)
          self.assertEqual(form.a(), """<select id="a" name="a"><option selected value="a">hello</option><option value="btest">bye</option></select>""")
          self.assertEqual(form.b(), """<select id="b" name="b"><option value="1">Item 1</option><option value="2">Item 2</option></select>""")
  
      def test_with_data(self):
          form = self.F(DummyPostData(a=['btest']))
          self.assertEqual(form.a.data, 'btest')
          self.assertEqual(form.a(), """<select id="a" name="a"><option value="a">hello</option><option selected value="btest">bye</option></select>""")
  
      def test_value_coercion(self):
          form = self.F(DummyPostData(b=['2']))
          self.assertEqual(form.b.data, 2)
          self.assertTrue(form.b.validate(form))
          form = self.F(DummyPostData(b=['b']))
          self.assertEqual(form.b.data, None)
          self.assertFalse(form.b.validate(form))
  
      def test_iterable_options(self):
          form = self.F()
          first_option = list(form.a)[0]
          self.assertTrue(isinstance(first_option, form.a._Option))
          self.assertEqual(list(text_type(x) for x in form.a), ['<option selected value="a">hello</option>',
                                                              '<option value="btest">bye</option>'])
          self.assertTrue(isinstance(first_option.widget, widgets.Option))
          self.assertTrue(isinstance(list(form.b)[0].widget, widgets.TextInput))
          self.assertEqual(first_option(disabled=True), '<option disabled selected value="a">hello</option>')
  
      def test_default_coerce(self):
          F = make_form(a=SelectField(choices=[('a', 'Foo')]))
          form = F(DummyPostData(a=[]))
          assert not form.validate()
          self.assertEqual(form.a.data, 'None')
          self.assertEqual(len(form.a.errors), 1)
          self.assertEqual(form.a.errors[0], 'Not a valid choice')
  
  
  class SelectMultipleFieldTest(TestCase):
      class F(Form):
          a = SelectMultipleField(choices=[('a', 'hello'), ('b','bye'), ('c', 'something')], default=('a', ))
          b = SelectMultipleField(coerce=int, choices=[(1, 'A'), (2, 'B'), (3, 'C')], default=("1", "3"))
  
      def test_defaults(self):
          form = self.F()
          self.assertEqual(form.a.data, ['a'])
          self.assertEqual(form.b.data, [1, 3])
          # Test for possible regression with null data
          form.a.data = None
          self.assertTrue(form.validate())
          self.assertEqual(list(form.a.iter_choices()), [(v, l, False) for v, l in form.a.choices])
  
      def test_with_data(self):
          form = self.F(DummyPostData(a=['a', 'c']))
          self.assertEqual(form.a.data, ['a', 'c'])
          self.assertEqual(list(form.a.iter_choices()), [('a', 'hello', True), ('b', 'bye', False), ('c', 'something', True)])
          self.assertEqual(form.b.data, [])
          form = self.F(DummyPostData(b=['1', '2']))
          self.assertEqual(form.b.data, [1, 2])
          self.assertTrue(form.validate())
          form = self.F(DummyPostData(b=['1', '2', '4']))
          self.assertEqual(form.b.data, [1, 2, 4])
          self.assertFalse(form.validate())
  
  
  class RadioFieldTest(TestCase):
      class F(Form):
          a = RadioField(choices=[('a', 'hello'), ('b','bye')], default='a')
          b = RadioField(choices=[(1, 'Item 1'), (2, 'Item 2')], coerce=int)
  
      def test(self):
          form = self.F()
          self.assertEqual(form.a.data, 'a')
          self.assertEqual(form.b.data, None)
          self.assertEqual(form.validate(), False)
          self.assertEqual(form.a(), """<ul id="a"><li><input checked id="a-0" name="a" type="radio" value="a"> <label for="a-0">hello</label></li><li><input id="a-1" name="a" type="radio" value="b"> <label for="a-1">bye</label></li></ul>""")
          self.assertEqual(form.b(), """<ul id="b"><li><input id="b-0" name="b" type="radio" value="1"> <label for="b-0">Item 1</label></li><li><input id="b-1" name="b" type="radio" value="2"> <label for="b-1">Item 2</label></li></ul>""")
          self.assertEqual([text_type(x) for x in form.a], ['<input checked id="a-0" name="a" type="radio" value="a">', '<input id="a-1" name="a" type="radio" value="b">'])
  
      def test_text_coercion(self):
          # Regression test for text coercsion scenarios where the value is a boolean.
          coerce_func = lambda x: False if x == 'False' else bool(x)
          F = make_form(a=RadioField(choices=[(True, 'yes'), (False, 'no')], coerce=coerce_func))
          form = F()
          self.assertEqual(form.a(), '<ul id="a"><li><input id="a-0" name="a" type="radio" value="True"> <label for="a-0">yes</label></li><li><input checked id="a-1" name="a" type="radio" value="False"> <label for="a-1">no</label></li></ul>')
  
  class TextFieldTest(TestCase):
      class F(Form):
          a = TextField()
  
      def test(self):
          form = self.F()
          self.assertEqual(form.a.data, None)
          self.assertEqual(form.a(), """<input id="a" name="a" type="text" value="">""")
          form = self.F(DummyPostData(a=['hello']))
          self.assertEqual(form.a.data, 'hello')
          self.assertEqual(form.a(), """<input id="a" name="a" type="text" value="hello">""")
          form = self.F(DummyPostData(b=['hello']))
          self.assertEqual(form.a.data, '')
  
  class HiddenFieldTest(TestCase):
      class F(Form):
          a = HiddenField(default="LE DEFAULT")
  
      def test(self):
          form = self.F()
          self.assertEqual(form.a(), """<input id="a" name="a" type="hidden" value="LE DEFAULT">""")
  
  
  class TextAreaFieldTest(TestCase):
      class F(Form):
          a = TextAreaField(default="LE DEFAULT")
  
      def test(self):
          form = self.F()
          self.assertEqual(form.a(), """<textarea id="a" name="a">LE DEFAULT</textarea>""")
  
  
  class PasswordFieldTest(TestCase):
      class F(Form):
          a = PasswordField(widget=widgets.PasswordInput(hide_value=False), default="LE DEFAULT")
          b = PasswordField(default="Hai")
  
      def test(self):
          form = self.F()
          self.assertEqual(form.a(), """<input id="a" name="a" type="password" value="LE DEFAULT">""")
          self.assertEqual(form.b(), """<input id="b" name="b" type="password" value="">""")
  
  
  class FileFieldTest(TestCase):
      class F(Form):
          a = FileField(default="LE DEFAULT")
  
      def test(self):
          form = self.F()
          self.assertEqual(form.a(), """<input id="a" name="a" type="file" value="LE DEFAULT">""")
  
  
  class IntegerFieldTest(TestCase):
      class F(Form):
          a = IntegerField()
          b = IntegerField(default=48)
  
      def test(self):
          form = self.F(DummyPostData(a=['v'], b=['-15']))
          self.assertEqual(form.a.data, None)
          self.assertEqual(form.a.raw_data, ['v'])
          self.assertEqual(form.a(), """<input id="a" name="a" type="text" value="v">""")
          self.assertEqual(form.b.data, -15)
          self.assertEqual(form.b(), """<input id="b" name="b" type="text" value="-15">""")
          self.assertTrue(not form.a.validate(form))
          self.assertTrue(form.b.validate(form))
          form = self.F(DummyPostData(a=[], b=['']))
          self.assertEqual(form.a.data, None)
          self.assertEqual(form.a.raw_data, [])
          self.assertEqual(form.b.data, None)
          self.assertEqual(form.b.raw_data, [''])
          self.assertTrue(not form.validate())
          self.assertEqual(len(form.b.process_errors), 1)
          self.assertEqual(len(form.b.errors), 1)
          form = self.F(b=9)
          self.assertEqual(form.b.data, 9)
          self.assertEqual(form.a._value(), '')
          self.assertEqual(form.b._value(), '9')
  
  
  class DecimalFieldTest(TestCase):
      def test(self):
          F = make_form(a=DecimalField())
          form = F(DummyPostData(a='2.1'))
          self.assertEqual(form.a.data, Decimal('2.1'))
          self.assertEqual(form.a._value(), '2.1')
          form.a.raw_data = None
          self.assertEqual(form.a._value(), '2.10')
          self.assertTrue(form.validate())
          form = F(DummyPostData(a='2,1'), a=Decimal(5))
          self.assertEqual(form.a.data, None)
          self.assertEqual(form.a.raw_data, ['2,1'])
          self.assertFalse(form.validate())
  
  
      def test_quantize(self):
          F = make_form(a=DecimalField(places=3, rounding=ROUND_UP), b=DecimalField(places=None))
          form = F(a=Decimal('3.1415926535'))
          self.assertEqual(form.a._value(), '3.142')
          form.a.rounding = ROUND_DOWN
          self.assertEqual(form.a._value(), '3.141')
          self.assertEqual(form.b._value(), '')
          form = F(a=3.14159265, b=72)
          self.assertEqual(form.a._value(), '3.142')
          self.assertTrue(isinstance(form.a.data, float))
          self.assertEqual(form.b._value(), '72')
  
  
  class FloatFieldTest(TestCase):
      class F(Form):
          a = FloatField()
          b = FloatField(default=48.0)
  
      def test(self):
          form = self.F(DummyPostData(a=['v'], b=['-15.0']))
          self.assertEqual(form.a.data, None)
          self.assertEqual(form.a.raw_data, ['v'])
          self.assertEqual(form.a(), """<input id="a" name="a" type="text" value="v">""")
          self.assertEqual(form.b.data, -15.0)
          self.assertEqual(form.b(), """<input id="b" name="b" type="text" value="-15.0">""")
          self.assertFalse(form.a.validate(form))
          self.assertTrue(form.b.validate(form))
          form = self.F(DummyPostData(a=[], b=['']))
          self.assertEqual(form.a.data, None)
          self.assertEqual(form.b.data, None)
          self.assertEqual(form.b.raw_data, [''])
          self.assertFalse(form.validate())
          self.assertEqual(len(form.b.process_errors), 1)
          self.assertEqual(len(form.b.errors), 1)
          form = self.F(b=9.0)
          self.assertEqual(form.b.data, 9.0)
          self.assertEqual(form.b._value(), "9.0")
  
  
  class BooleanFieldTest(TestCase):
      class BoringForm(Form):
          bool1 = BooleanField()
          bool2 = BooleanField(default=True)
  
      obj = AttrDict(bool1=None, bool2=True)
  
      def test_defaults(self):
          # Test with no post data to make sure defaults work
          form = self.BoringForm()
          self.assertEqual(form.bool1.raw_data, None)
          self.assertEqual(form.bool1.data, False)
          self.assertEqual(form.bool2.data, True)
  
      def test_rendering(self):
          form = self.BoringForm(DummyPostData(bool2="x"))
          self.assertEqual(form.bool1(), '<input id="bool1" name="bool1" type="checkbox" value="y">')
          self.assertEqual(form.bool2(), '<input checked id="bool2" name="bool2" type="checkbox" value="x">')
          self.assertEqual(form.bool2.raw_data, ['x'])
  
      def test_with_postdata(self):
          form = self.BoringForm(DummyPostData(bool1=['a']))
          self.assertEqual(form.bool1.raw_data, ['a'])
          self.assertEqual(form.bool1.data, True)
  
      def test_with_model_data(self):
          form = self.BoringForm(obj=self.obj)
          self.assertEqual(form.bool1.data, False)
          self.assertEqual(form.bool1.raw_data, None)
          self.assertEqual(form.bool2.data, True)
  
      def test_with_postdata_and_model(self):
          form = self.BoringForm(DummyPostData(bool1=['y']), obj=self.obj)
          self.assertEqual(form.bool1.data, True)
          self.assertEqual(form.bool2.data, False)
  
  
  class DateFieldTest(TestCase):
      class F(Form):
          a = DateField()
          b = DateField(format='%m/%d %Y')
  
      def test_basic(self):
          d = date(2008, 5, 7)
          form = self.F(DummyPostData(a=['2008-05-07'], b=['05/07', '2008']))
          self.assertEqual(form.a.data, d)
          self.assertEqual(form.a._value(), '2008-05-07')
          self.assertEqual(form.b.data, d)
          self.assertEqual(form.b._value(), '05/07 2008')
  
      def test_failure(self):
          form = self.F(DummyPostData(a=['2008-bb-cc'], b=['hi']))
          assert not form.validate()
          self.assertEqual(len(form.a.process_errors), 1)
          self.assertEqual(len(form.a.errors), 1)
          self.assertEqual(len(form.b.errors), 1)
          self.assertEqual(form.a.process_errors[0], 'Not a valid date value')
  
  
  class DateTimeFieldTest(TestCase):
      class F(Form):
          a = DateTimeField()
          b = DateTimeField(format='%Y-%m-%d %H:%M')
  
      def test_basic(self):
          d = datetime(2008, 5, 5, 4, 30, 0, 0)
          form = self.F(DummyPostData(a=['2008-05-05', '04:30:00'], b=['2008-05-05 04:30']))
          self.assertEqual(form.a.data, d)
          self.assertEqual(form.a(), """<input id="a" name="a" type="text" value="2008-05-05 04:30:00">""")
          self.assertEqual(form.b.data, d)
          self.assertEqual(form.b(), """<input id="b" name="b" type="text" value="2008-05-05 04:30">""")
          self.assertTrue(form.validate())
          form = self.F(DummyPostData(a=['2008-05-05']))
          self.assertFalse(form.validate())
          self.assertEqual(form.a.errors[0], 'Not a valid datetime value')
  
      def test_microseconds(self):
          if PYTHON_VERSION < (2, 6):
              return # Microsecond formatting support was only added in 2.6
  
          d = datetime(2011, 5, 7, 3, 23, 14, 424200)
          F = make_form(a=DateTimeField(format='%Y-%m-%d %H:%M:%S.%f'))
          form = F(DummyPostData(a=['2011-05-07 03:23:14.4242']))
          self.assertEqual(d, form.a.data)
  
  
  class SubmitFieldTest(TestCase):
      class F(Form):
          a = SubmitField('Label')
  
      def test(self):
          self.assertEqual(self.F().a(), """<input id="a" name="a" type="submit" value="Label">""")
  
  
  class FormFieldTest(TestCase):
      def setUp(self):
          F = make_form(
              a = TextField(validators=[validators.required()]),
              b = TextField(),
          )
          self.F1 = make_form('F1', a = FormField(F))
          self.F2 = make_form('F2', a = FormField(F, separator='::'))
  
      def test_formdata(self):
          form = self.F1(DummyPostData({'a-a':['moo']}))
          self.assertEqual(form.a.form.a.name, 'a-a')
          self.assertEqual(form.a.form.a.data, 'moo')
          self.assertEqual(form.a.form.b.data, '')
          self.assertTrue(form.validate())
  
      def test_iteration(self):
          self.assertEqual([x.name for x in self.F1().a], ['a-a', 'a-b'])
  
      def test_with_obj(self):
          obj = AttrDict(a=AttrDict(a='mmm'))
          form = self.F1(obj=obj)
          self.assertEqual(form.a.form.a.data, 'mmm')
          self.assertEqual(form.a.form.b.data, None)
          obj_inner = AttrDict(a=None, b='rawr')
          obj2 = AttrDict(a=obj_inner)
          form.populate_obj(obj2)
          self.assertTrue(obj2.a is obj_inner)
          self.assertEqual(obj_inner.a, 'mmm')
          self.assertEqual(obj_inner.b, None)
  
      def test_widget(self):
          self.assertEqual(self.F1().a(), '''<table id="a"><tr><th><label for="a-a">A</label></th><td><input id="a-a" name="a-a" type="text" value=""></td></tr><tr><th><label for="a-b">B</label></th><td><input id="a-b" name="a-b" type="text" value=""></td></tr></table>''')
  
      def test_separator(self):
          form = self.F2(DummyPostData({'a-a': 'fake', 'a::a': 'real'}))
          self.assertEqual(form.a.a.name, 'a::a')
          self.assertEqual(form.a.a.data, 'real')
          self.assertTrue(form.validate())
  
      def test_no_validators_or_filters(self):
          class A(Form):
              a = FormField(self.F1, validators=[validators.required()])
          self.assertRaises(TypeError, A)
          class B(Form):
              a = FormField(self.F1, filters=[lambda x: x])
          self.assertRaises(TypeError, B)
  
          class C(Form):
              a = FormField(self.F1)
              def validate_a(form, field):
                  pass
          form = C()
          self.assertRaises(TypeError, form.validate)
  
  
  class FieldListTest(TestCase):
      t = TextField(validators=[validators.Required()])
  
      def test_form(self):
          F = make_form(a = FieldList(self.t))
          data = ['foo', 'hi', 'rawr']
          a = F(a=data).a
          self.assertEqual(a.entries[1].data, 'hi')
          self.assertEqual(a.entries[1].name, 'a-1')
          self.assertEqual(a.data, data)
          self.assertEqual(len(a.entries), 3)
  
          pdata = DummyPostData({'a-0': ['bleh'], 'a-3': ['yarg'], 'a-4': [''], 'a-7': ['mmm']})
          form = F(pdata)
          self.assertEqual(len(form.a.entries), 4)
          self.assertEqual(form.a.data, ['bleh', 'yarg', '', 'mmm'])
          self.assertFalse(form.validate())
  
          form = F(pdata, a=data)
          self.assertEqual(form.a.data, ['bleh', 'yarg', '', 'mmm'])
          self.assertFalse(form.validate())
  
          # Test for formdata precedence
          pdata = DummyPostData({'a-0': ['a'], 'a-1': ['b']})
          form = F(pdata, a=data)
          self.assertEqual(len(form.a.entries), 2)
          self.assertEqual(form.a.data, ['a', 'b'])
  
      def test_enclosed_subform(self):
          make_inner = lambda: AttrDict(a=None)
          F = make_form(
              a = FieldList(FormField(make_form('FChild', a=self.t), default=make_inner))
          )
          data = [{'a': 'hello'}]
          form = F(a=data)
          self.assertEqual(form.a.data, data)
          self.assertTrue(form.validate())
          form.a.append_entry()
          self.assertEqual(form.a.data, data + [{'a': None}])
          self.assertFalse(form.validate())
  
          pdata = DummyPostData({'a-0': ['fake'], 'a-0-a': ['foo'], 'a-1-a': ['bar']})
          form = F(pdata, a=data)
          self.assertEqual(form.a.data, [{'a': 'foo'}, {'a': 'bar'}])
  
          inner_obj = make_inner()
          inner_list = [inner_obj]
          obj = AttrDict(a=inner_list)
          form.populate_obj(obj)
          self.assertTrue(obj.a is not inner_list)
          self.assertEqual(len(obj.a), 2)
          self.assertTrue(obj.a[0] is inner_obj)
          self.assertEqual(obj.a[0].a, 'foo')
          self.assertEqual(obj.a[1].a, 'bar')
  
      def test_entry_management(self):
          F = make_form(a = FieldList(self.t))
          a = F(a=['hello', 'bye']).a
          self.assertEqual(a.pop_entry().name, 'a-1')
          self.assertEqual(a.data, ['hello'])
          a.append_entry('orange')
          self.assertEqual(a.data, ['hello', 'orange'])
          self.assertEqual(a[-1].name, 'a-1')
          self.assertEqual(a.pop_entry().data, 'orange')
          self.assertEqual(a.pop_entry().name, 'a-0')
          self.assertRaises(IndexError, a.pop_entry)
  
      def test_min_max_entries(self):
          F = make_form(a = FieldList(self.t, min_entries=1, max_entries=3))
          a = F().a
          self.assertEqual(len(a), 1)
          self.assertEqual(a[0].data, None)
          big_input = ['foo',  'flaf', 'bar', 'baz']
          self.assertRaises(AssertionError, F, a=big_input)
          pdata = DummyPostData(('a-%d' % i, v) for i, v in enumerate(big_input))
          a = F(pdata).a
          self.assertEqual(a.data, ['foo', 'flaf', 'bar'])
          self.assertRaises(AssertionError, a.append_entry)
  
      def test_validators(self):
          def validator(form, field):
              if field.data and field.data[0] == 'fail':
                  raise ValueError('fail')
              elif len(field.data) > 2:
                  raise ValueError('too many')
  
          F = make_form(a = FieldList(self.t, validators=[validator]))
  
          # Case 1: length checking validators work as expected.
          fdata = DummyPostData({'a-0': ['hello'], 'a-1': ['bye'], 'a-2': ['test3']})
          form = F(fdata)
          assert not form.validate()
          self.assertEqual(form.a.errors, ['too many'])
  
          # Case 2: checking a value within.
          fdata['a-0'] = ['fail']
          form = F(fdata)
          assert not form.validate()
          self.assertEqual(form.a.errors, ['fail'])
  
          # Case 3: normal field validator still works
          form = F(DummyPostData({'a-0': ['']}))
          assert not form.validate()
          self.assertEqual(form.a.errors, [['This field is required.']])
  
  
  if __name__ == '__main__':
      from unittest import main
      main()
  