Note that for the sake of the test, the test setup has installed a dummy schema
context that will allow us to demonstrate editing a dummy IDummySchema schema, via the
/schemaeditor URL.  It also registers an event handler for various schema events that
will print out the event, so that we can make sure events are getting raised properly.

Let's set up the test browser::
    
    >>> from Products.Five.testbrowser import Browser
    >>> browser = Browser()
    >>> portal_url = 'http://nohost'
    >>> browser.handleErrors = False


Navigating to a schema
----------------------

If we try to access the schema editor without logging in, we should get an Unauthorized
error::

    >>> browser.open(portal_url + '/@@schemaeditor')
    Traceback (most recent call last):
    ...
    Unauthorized: ...You are not authorized to access this resource...
    
We need to log in as a manager, because by default only managers get the 'Manage Schemata' permission::

    >>> user = self.app.acl_users.userFolderAddUser('root', 'secret', ['Manager'], [])
    >>> browser.addHeader('Authorization', 'Basic root:secret')

Now we should be able to navigate to the IDummySchema schema in the browser::

    >>> browser.open(portal_url + '/@@schemaeditor')
    >>> 'Edit @@schemaeditor' in browser.contents
    True


Adding a field
--------------

Let's add a 'favorite-color' field to the IDummySchema schema::

    >>> browser.getControl('Add new field').click()
    >>> browser.getControl('Title').value = 'Favorite Color'
    >>> browser.getControl('Short Name').value = 'favorite_color'
    >>> browser.getControl('Field type').value = ['Text line (String)']
    >>> browser.getControl('Add').click()
    [event: ObjectAddedEvent on TextLine]
    [event: SchemaModifiedEvent on DummySchemaContext]
    >>> browser.url
    'http://nohost/@@schemaeditor'

Now the actual IDummySchema schema should have the new field (the field id is a
normalized form of the title)::

    >>> from plone.schemaeditor.tests.fixtures import IDummySchema
    >>> 'favorite_color' in IDummySchema
    True
    >>> from zope.schema import TextLine
    >>> isinstance(IDummySchema['favorite_color'], TextLine)
    True
    >>> IDummySchema['favorite_color'].title
    u'Favorite Color'


Editing a schema field attribute
--------------------------------

Let's navigate to the 'favorite-color' field we just created::

    >>> browser.getLink(url='favorite_color').click()
    >>> browser.url
    'http://nohost/@@schemaeditor/favorite_color'
    >>> "Edit Field 'favorite_color'" in browser.contents
    True

Now we can change various attributes.  For instance, let's change the default
value of the 'color' field to 'orange'::

    >>> browser.getControl('Default Value').value = 'orange'

And now click the button to save the change.  This should take us back to the list
of schema fields, which should reflect the change::

    >>> browser.getControl('Save').click()
    [event: ObjectModifiedEvent on TextLine]
    [event: SchemaModifiedEvent on DummySchemaContext]
    >>> browser.url
    'http://nohost/@@schemaeditor'
    
Let's confirm that the new default value was correctly saved to the actual schema::

    >>> IDummySchema['favorite_color'].default
    u'orange'

Let's go back and try to make an invalid change.  The form won't let us::

    >>> browser.getLink(url='favorite_color').click()
    >>> browser.url
    'http://nohost/@@schemaeditor/favorite_color'
    >>> browser.getControl('Minimum length').value = 'asdf'
    >>> browser.getControl('Save').click()
    >>> browser.url
    'http://nohost/@@schemaeditor/favorite_color/@@edit'
    >>> 'The entered value is not a valid integer literal.' in browser.contents
    True

We also cannot set the field title to an empty string, even though the field is
not required in zope.schema.interfaces.IField::

    >>> browser.open('http://nohost/@@schemaeditor/favorite_color')
    >>> browser.getControl('Title').value = ''
    >>> browser.getControl('Save').click()
    >>> browser.url
    'http://nohost/@@schemaeditor/favorite_color/@@edit'
    >>> 'Required input is missing.' in browser.contents
    True

We can give up and hit the Cancel button, which should take us back to the schema listing,
without trying to save changes::

    >>> browser.getControl('Cancel').click()
    >>> browser.url
    'http://nohost/@@schemaeditor'


Re-ordering a field
-------------------

The field we added was created in a position following the 5 existing fields on the
interface::

    >>> from zope.schema import getFieldsInOrder
    >>> getFieldsInOrder(IDummySchema)[5][0]
    'favorite_color'

Fields can be reordered via drag-and-drop.  Let's simulate the AJAX request that would
result from dragging the 'favorite_color' field to the 3rd position (since the
testbrowser doesn't support Javascript)::

    >>> browser.open('http://nohost/@@schemaeditor/favorite_color/@@order?pos=2')
    [event: ContainerModifiedEvent on InterfaceClass]
    [event: SchemaModifiedEvent on DummySchemaContext]
    >>> browser.contents
    ''

Now the field should be the third field of the schema::

    >>> getFieldsInOrder(IDummySchema)[2][0]
    'favorite_color'

Now let's move it to be the first field (as there is an edge case in the ordering
algorithm that we need to test)::

    >>> browser.open('http://nohost/@@schemaeditor/favorite_color/@@order?pos=0')
    [event: ContainerModifiedEvent on InterfaceClass]
    [event: SchemaModifiedEvent on DummySchemaContext]
    >>> getFieldsInOrder(IDummySchema)[0][0]
    'favorite_color'


Removing a field
----------------

We can also remove a field::

    >>> browser.open('http://nohost/@@schemaeditor')
    >>> browser.getLink(url='favorite_color/@@delete').click()
    [event: ObjectRemovedEvent on TextLine]
    [event: SchemaModifiedEvent on DummySchemaContext]

And confirm that the real schema was updated::

    >>> 'favorite_color' in IDummySchema
    False


Miscellaneous field types
-------------------------

Demonstrate that all the registered field types can be added edited
and saved.

    >>> from zope import component
    >>> from plone.schemaeditor import interfaces
    >>> schema = IDummySchema
    >>> start_field_count = len(IDummySchema.names())
    >>> for name, factory in sorted(component.getUtilitiesFor(
    ...     interfaces.IFieldFactory)):
    ...     browser.open(portal_url + '/@@schemaeditor')
    ...     browser.getControl('Add new field').click()
    ...     browser.getControl('Title').value = name
    ...     field_id = name.replace('-', '_')
    ...     browser.getControl('Short Name').value = field_id
    ...     browser.getControl('Field type').getControl(
    ...         value=getattr(factory.title, 'default', factory.title)
    ...         ).selected = True
    ...     browser.getControl('Add').click()
    ...     assert browser.url == portal_url + '/@@schemaeditor', (
    ...         'Failed to create %r' % name)
    ...     assert field_id in schema, '%r not in %r' % (
    ...         field_id, schema)
    ...     assert factory.fieldcls._type is None or isinstance(
    ...         schema[field_id], factory.fieldcls
    ...         ), '%r is not an instance of %r' % (
    ...             schema[field_id], factory.fieldcls)
    ...     browser.getLink(url=field_id).click()
    ...     browser.getControl('Title').value += ' '
    ...     browser.getControl('Save').click()
    [event: ObjectAddedEvent on Bool]
    [event: SchemaModifiedEvent on DummySchemaContext]
    [event: ObjectModifiedEvent on Bool]
    [event: SchemaModifiedEvent on DummySchemaContext]
    [event: ObjectAddedEvent on Int]
    [event: SchemaModifiedEvent on DummySchemaContext]
    [event: ObjectModifiedEvent on Int]
    [event: SchemaModifiedEvent on DummySchemaContext]
    [event: ObjectAddedEvent on Password]
    [event: SchemaModifiedEvent on DummySchemaContext]
    [event: ObjectModifiedEvent on Password]
    [event: SchemaModifiedEvent on DummySchemaContext]
    [event: ObjectAddedEvent on Text]
    [event: SchemaModifiedEvent on DummySchemaContext]
    [event: ObjectModifiedEvent on Text]
    [event: SchemaModifiedEvent on DummySchemaContext]
    [event: ObjectAddedEvent on TextLine]
    [event: SchemaModifiedEvent on DummySchemaContext]
    [event: ObjectModifiedEvent on TextLine]
    [event: SchemaModifiedEvent on DummySchemaContext]
    [event: ObjectAddedEvent on Choice]
    [event: SchemaModifiedEvent on DummySchemaContext]
    [event: ObjectModifiedEvent on Choice]
    [event: SchemaModifiedEvent on DummySchemaContext]
    [event: ObjectAddedEvent on Datetime]
    [event: SchemaModifiedEvent on DummySchemaContext]
    [event: ObjectModifiedEvent on Datetime]
    [event: SchemaModifiedEvent on DummySchemaContext]
    [event: ObjectAddedEvent on Float]
    [event: SchemaModifiedEvent on DummySchemaContext]
    [event: ObjectModifiedEvent on Float]
    [event: SchemaModifiedEvent on DummySchemaContext]
    [event: ObjectAddedEvent on List]
    [event: SchemaModifiedEvent on DummySchemaContext]
    [event: ObjectModifiedEvent on List]
    [event: SchemaModifiedEvent on DummySchemaContext]
