Testing forms
=============

Before we can begin, we need to set up a few things.  We need a
manager account:

  >>> uf = self.folder.acl_users
  >>> uf._doAddUser('manager', 'r00t', ['Manager'], [])

We need to configure all of Five for the functional test:

  >>> import Products.Five.form.tests
  >>> from Products.Five import zcml
  >>> zcml.load_config('configure.zcml', package=Products.Five)
  >>> zcml.load_config('configure.zcml', package=Products.Five.form.tests)

Finally, we need to setup a traversable folder.  Otherwise, Five won't
get to to do its view lookup:

  >>> from Products.Five.tests.testing import manage_addFiveTraversableFolder
  >>> manage_addFiveTraversableFolder(self.folder, 'ftf')


Add forms
---------

We can add objects to containers (object managers) through add forms.
An unprotected form can be accessed with anonymously:

  >>> print http(r"""
  ... GET /test_folder_1_/ftf/+/addfieldcontent.html HTTP/1.1
  ... """, handle_errors=False)
  HTTP/1.1 200 OK
  ...

For a protected one we need a manager account:

  >>> print http(r"""
  ... GET /test_folder_1_/ftf/+/protectedaddform.html HTTP/1.1
  ... Authorization: Basic manager:r00t
  ... """, handle_errors=False)
  HTTP/1.1 200 OK
  ...

otherwise we will fail to access it (N.B: this test will fail on Zope 2.8.1,
which incorrectly ignored its 'handle_errors' argument):

  >>> print http(r"""
  ... GET /test_folder_1_/ftf/+/protectedaddform.html HTTP/1.1
  ... """, handle_errors=False)
  Traceback (most recent call last):
  ...
  Unauthorized: ...

Now let's add a piece of our sample content object to test more things
on it:

  >>> print http(r"""
  ... POST /test_folder_1_/ftf/+/addfieldcontent.html HTTP/1.1
  ... Authorization: Basic manager:r00t
  ... Content-Type: multipart/form-data; boundary=---------------------------968064918930967154199105236
  ... Content-Length: 527
  ... 
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... title
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... 
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Add
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="add_input_name"
  ... 
  ... edittest
  ... -----------------------------968064918930967154199105236--
  ... """, handle_errors=False)
  HTTP/1.1 302 Moved Temporarily
  ...
  Location: http://localhost/test_folder_1_/ftf/manage_main
  ...

Having added this piece of content, we can access it under its URL:

  >>> print http(r"""
  ... GET /test_folder_1_/ftf/edittest HTTP/1.1
  ... """, handle_errors=False)
  HTTP/1.1 200 OK
  ...

We can also verify that the title was set correctly, and the not
specified attribute is the default value:

  >>> edittest = self.folder.ftf.edittest
  >>> edittest.title
  u'title'
  >>> edittest.description #XXX shouldn't we get a u'' here???


Edit forms
----------

First, it's important to note that forms validate user input.
Therefore, if we specify invalid data, our object won't change:

  >>> print http(r"""
  ... POST /test_folder_1_/ftf/edittest/@@edit.html HTTP/1.1
  ... Authorization: Basic manager:r00t
  ... Content-Type: multipart/form-data; boundary=---------------------------968064918930967154199105236
  ... Content-Length: 418
  ... 
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... 
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... BarDescription
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Change
  ... -----------------------------968064918930967154199105236--
  ... """, handle_errors=False)
  HTTP/1.1 200 OK
  ...
            There are <strong>1</strong> input errors.
  ...

We will see that nothing has changed:

  >>> edittest.title
  u'title'
  >>> edittest.description #XXX shouldn't we get a u'' here???

However, when we specify the correct fields:

  >>> print http(r"""
  ... POST /test_folder_1_/ftf/edittest/@@edit.html HTTP/1.1
  ... Authorization: Basic manager:r00t
  ... Content-Type: multipart/form-data; boundary=---------------------------968064918930967154199105236
  ... Content-Length: 426
  ... 
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... FooTitle
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... FooDescription
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Change
  ... -----------------------------968064918930967154199105236--
  ... """, handle_errors=False)
  HTTP/1.1 200 OK
  ...

We will see that nothing has changed:

  >>> edittest.title
  u'FooTitle'
  >>> edittest.description
  u'FooDescription'


Unicode-safety of forms
-----------------------

Even though ZPublisher does not support unicode, automatically
generated forms do.  In the following we will enter the following two
chinese sequences (How do you do? and I'm doing good) in forms
(they're encoded in UTF-8 here):

  >>> ni_hao = '\xe4\xbd\xa0\xe5\xa5\xbd'
  >>> wo_hen_hao = '\346\210\221\345\276\210\345\245\275'

First, it's imaginable that we make a mistake and enter one of the
phrases in the integer field:

  >>> print http(r"""
  ... POST /test_folder_1_/ftf/+/addfieldcontent.html HTTP/1.1
  ... Authorization: Basic manager:r00t
  ... Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
  ... Content-Type: multipart/form-data; boundary=---------------------------968064918930967154199105236
  ... Content-Length: 418
  ... 
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... ChineseTitle
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... ChineseDescription
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.somenumber"
  ... 
  ... %s
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Add
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="add_input_name"
  ... 
  ... unicodetest
  ... -----------------------------968064918930967154199105236--
  ... """ % ni_hao, handle_errors=False)
  HTTP/1.1 200 OK
  ...
            There are <strong>1</strong> input errors.
  ...

When we enter the unicode data in the right fields (the text fields),
the form will submit correctly and create the object:

  >>> print http(r"""
  ... POST /test_folder_1_/ftf/+/addfieldcontent.html HTTP/1.1
  ... Authorization: Basic manager:r00t
  ... Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
  ... Content-Type: multipart/form-data; boundary=---------------------------968064918930967154199105236
  ... Content-Length: 418
  ... 
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... %s
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... %s
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.somenumber"
  ... 
  ... 0
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Add
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="add_input_name"
  ... 
  ... unicodetest
  ... -----------------------------968064918930967154199105236--
  ... """ % (ni_hao, wo_hen_hao), handle_errors=False)
  HTTP/1.1 302 Moved Temporarily
  ...
  Location: http://localhost/test_folder_1_/ftf/manage_main
  ...

We can test the object has the correct values, as unicode strings, of
course:

  >>> unicodetest = self.folder.ftf.unicodetest
  >>> unicodetest.title == ni_hao.decode('utf-8')
  True
  >>> unicodetest.description == wo_hen_hao.decode('utf-8')
  True
  >>> unicodetest.somenumber
  0

Of course, the same should apply to edit forms.  First, we happen to
again make the mistake of entering unicode data in the integer field:

  >>> print http(r"""
  ... POST /test_folder_1_/ftf/unicodetest/@@edit.html HTTP/1.1
  ... Authorization: Basic manager:r00t
  ... Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
  ... Content-Type: multipart/form-data; boundary=---------------------------968064918930967154199105236
  ... Content-Length: 418
  ... 
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... ChineseTitle
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... ChineseDescription
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.somenumber"
  ... 
  ... %s
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Change
  ... -----------------------------968064918930967154199105236--
  ... """ % ni_hao, handle_errors=False)
  HTTP/1.1 200 OK
  ...
            There are <strong>1</strong> input errors.
  ...

We see that the object hasn't changed:

  >>> unicodetest.title == ni_hao.decode('utf-8')
  True
  >>> unicodetest.description == wo_hen_hao.decode('utf-8')
  True
  >>> unicodetest.somenumber
  0

Now we provide some valid form data:

  >>> print http(r"""
  ... POST /test_folder_1_/ftf/unicodetest/@@edit.html HTTP/1.1
  ... Authorization: Basic manager:r00t
  ... Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
  ... Content-Type: multipart/form-data; boundary=---------------------------968064918930967154199105236
  ... Content-Length: 418
  ... 
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... %s
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... %s
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.somenumber"
  ... 
  ... 1
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Change
  ... -----------------------------968064918930967154199105236--
  ... """ % (wo_hen_hao, ni_hao), handle_errors=False)
  HTTP/1.1 200 OK
  ...

We see that the object's data has changed:

  >>> unicodetest.title == wo_hen_hao.decode('utf-8')
  True
  >>> unicodetest.description == ni_hao.decode('utf-8')
  True
  >>> unicodetest.somenumber
  1

Let's also not forget about List widgets.  Let's see if we can add an
element to the list:

  >>> print http(r"""
  ... POST /test_folder_1_/ftf/unicodetest/@@edit.html HTTP/1.1
  ... Authorization: Basic manager:r00t
  ... Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
  ... Content-Type: multipart/form-data; boundary=---------------------------968064918930967154199105236
  ... Content-Length: 418
  ... 
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... %s
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... %s
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.somenumber"
  ... 
  ... 1
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.somelist.add"
  ... 
  ... Add
  ... -----------------------------968064918930967154199105236--
  ... """ % (wo_hen_hao, ni_hao), handle_errors=False)
  HTTP/1.1 200 OK
  ...
  ...<input class="textType" id="field.somelist.0." name="field.somelist.0." size="20" type="text" value=""  />...
  ...

Now, let's enter some more Chinese:

  >>> de_guo = '\345\276\267\345\233\275'
  
  >>> print http(r"""
  ... POST /test_folder_1_/ftf/unicodetest/@@edit.html HTTP/1.1
  ... Authorization: Basic manager:r00t
  ... Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
  ... Content-Type: multipart/form-data; boundary=---------------------------968064918930967154199105236
  ... Content-Length: 418
  ... 
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... %s
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... %s
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.somenumber"
  ... 
  ... 1
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="field.somelist.0."
  ... 
  ... %s
  ... -----------------------------968064918930967154199105236
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Change
  ... -----------------------------968064918930967154199105236--
  ... """ % (wo_hen_hao, ni_hao, de_guo), handle_errors=False)
  HTTP/1.1 200 OK
  ...

The object's data will have changed accordingly:

  >>> unicodetest.somelist == [de_guo.decode('utf-8')]
  True


Object widget:
--------------

A little more complex is the ``ObjectWidget``.  Here we simply test
that the edit form works:

  >>> from Products.Five.form.tests.schemacontent import \
  ...     manage_addComplexSchemaContent
  >>> n = manage_addComplexSchemaContent(self.folder.ftf, 'objecttest')

  >>> print http(r"""
  ... GET /test_folder_1_/ftf/objecttest/@@edit.html HTTP/1.1
  ... """, handle_errors=False)
  HTTP/1.1 200 OK
  ...


i18n:
-----

And now the add form in German:

  >>> print http(r"""
  ... GET /test_folder_1_/ftf/+/addfieldcontent.html HTTP/1.1
  ... Accept-Language: de
  ... Authorization: Basic manager:r00t
  ... """, handle_errors=False)
  HTTP/1.1 200 OK
  ...Felderinhalt hinzuf...
  ...Eine kurz...Titel...
  ...Eine ausf...Beschreibung...
  ...Irgendeine Zahl...
  ...Irgendeine Liste...
  ...hinzuf...
  ...Auffrischen...
  ...Hinzuf...
  ...Objektname...

The same with an input error:

  >>> print http(r"""
  ... POST /test_folder_1_/ftf/+/addfieldcontent.html HTTP/1.1
  ... Accept-Language: de
  ... Authorization: Basic manager:r00t
  ... Content-Length: 670
  ... Content-Type: multipart/form-data; boundary=---------------------------19588947601368617292863650127
  ... 
  ... -----------------------------19588947601368617292863650127
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... 
  ... -----------------------------19588947601368617292863650127
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... 
  ... -----------------------------19588947601368617292863650127
  ... Content-Disposition: form-data; name="field.somenumber"
  ... 
  ... 0
  ... -----------------------------19588947601368617292863650127
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Hinzufxgen
  ... -----------------------------19588947601368617292863650127
  ... Content-Disposition: form-data; name="add_input_name"
  ... 
  ... 
  ... -----------------------------19588947601368617292863650127--
  ... """, handle_errors=False)
  HTTP/1.1 200 OK
  ...Felderinhalt hinzuf...
  ...Ein Fehler ist aufgetreten...
  ...Es gab <strong>1</strong> Eingabefehler...
  ...Eine kurz...Titel...
  ...Erforderliche Eingabe fehlt...
  ...Eine ausf...Beschreibung...
  ...Irgendeine Zahl...
  ...Irgendeine Liste...
  ...hinzuf...
  ...Auffrischen...
  ...Hinzuf...
  ...Objektname...

And now the translated edit form:

  >>> from Products.Five.form.tests.schemacontent import \
  ...     manage_addFieldContent
  >>> dummy = manage_addFieldContent(self.folder.ftf, 'i18ntest', 'titel')

  >>> print http(r"""
  ... GET /test_folder_1_/ftf/i18ntest/edit.html HTTP/1.1
  ... Accept-Language: de
  ... Authorization: Basic manager:r00t
  ... """, handle_errors=False)
  HTTP/1.1 200 OK
  ...Felderinhalt bearbeiten...
  ...Eine kurz...Titel...
  ...Eine ausf...Beschreibung...
  ...Irgendeine Zahl...
  ...Irgendeine Liste...
  ...hinzuf...
  ...Auffrischen...
  ...Abschicken...

Again with an input error:

  >>> print http(r"""
  ... POST /test_folder_1_/ftf/i18ntest/edit.html HTTP/1.1
  ... Accept-Language: de
  ... Authorization: Basic manager:r00t
  ... Content-Length: 550
  ... Content-Type: multipart/form-data; boundary=---------------------------13070562555632576681565633754
  ... 
  ... -----------------------------13070562555632576681565633754
  ... Content-Disposition: form-data; name="field.title"
  ... 
  ... 
  ... -----------------------------13070562555632576681565633754
  ... Content-Disposition: form-data; name="field.description"
  ... 
  ... 
  ... -----------------------------13070562555632576681565633754
  ... Content-Disposition: form-data; name="field.somenumber"
  ... 
  ... 0
  ... -----------------------------13070562555632576681565633754
  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
  ... 
  ... Abschicken
  ... -----------------------------13070562555632576681565633754--
  ... """, handle_errors=False)
  HTTP/1.1 200 OK
  ...Felderinhalt bearbeiten...
  ...Ein Fehler ist aufgetreten...
  ...Es gab <strong>1</strong> Eingabefehler...
  ...Eine kurz...Titel...
  ...Erforderliche Eingabe fehlt...
  ...Eine ausf...Beschreibung...
  ...Irgendeine Zahl...
  ...Irgendeine Liste...
  ...hinzuf...
  ...Auffrischen...
  ...Abschicken...


Clean up
--------

Finally, we need to clean up:

  >>> from zope.app.tests.placelesssetup import tearDown
  >>> tearDown()
