##############################################################################
#
# Copyright (c) 2001, 2002 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Editview tests"""
import unittest

import transaction
from persistent import Persistent
from webtest import TestApp
from zope.interface import Interface
from zope.interface import implementer
from zope.schema import TextLine
from zope.traversing.api import traverse

from zope.app.form.browser.editview import EditView
from zope.app.form.browser.tests.support import defineSecurity
from zope.app.form.browser.tests.support import patternExists
from zope.app.form.browser.tests.support import registerEditForm
from zope.app.form.testing import AppFormLayer


class IFoo(Interface):

    optional_text = TextLine(required=False)
    required_text = TextLine(required=True)


@implementer(IFoo)
class Foo(Persistent):
    pass


class Test(unittest.TestCase):

    layer = AppFormLayer

    def setUp(self):
        self.getRootFolder = self.layer.getRootFolder
        registerEditForm(IFoo)
        defineSecurity(Foo, IFoo)
        self._testapp = TestApp(self.layer.make_wsgi_app())

    def publish(self, path, basic=None, form=None, headers=None):
        if basic:
            self._testapp.authorization = ('Basic', tuple(basic.split(':')))
        else:
            self._testapp.authorization = None
        env = {'wsgi.handleErrors': False}
        if form:
            response = self._testapp.post(path, params=form,
                                          extra_environ=env, headers=headers)
        else:
            response = self._testapp.get(
                path, extra_environ=env, headers=headers)
        return response

    def test_rollback_on_error(self):
        """Tests rollback when a widget error occurs.

        When one or more errors are generated by input widgets, the current
        transaction should be rolledback to ensure object integrity.
        """
        self.getRootFolder()['foo'] = Foo()
        self.getRootFolder()['foo'].required_text = 'initial required'
        self.getRootFolder()['foo'].optional_text = 'initial optional'
        transaction.commit()

        # submit form with legal value for optional_text and invalid for
        # required_text
        old_update = EditView.update
        try:
            def new_update(self):
                # This update changes something after form validation has
                # failed. Side effects like this should not be committed.
                # http://www.zope.org/Collectors/Zope3-dev/655
                result = old_update(self)
                self.context.required_text = 'changed after form validation'
                return result
            EditView.update = new_update
            response = self.publish('/foo/edit.html', form={
                'field.optional_text': '',
                'field.required_text': '',
                'UPDATE_SUBMIT': ''})
            self.assertEqual(response.status_int, 200)
        finally:
            EditView.update = old_update

        # confirm that one errors exists
        self.assertTrue(patternExists(
            'There are <strong>1</strong> input errors.', response.text))

        # confirm that foo was not modified
        foo = traverse(self.getRootFolder(), 'foo')
        self.assertEqual(foo.required_text, 'initial required')
        self.assertEqual(foo.optional_text, 'initial optional')


def test_suite():
    return unittest.defaultTestLoader.loadTestsFromName(__name__)
