# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2004 Nexedi SARL and Contributors. All Rights Reserved.
#          Sebastien Robin <seb@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################

import unittest

from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from Products.ERP5Type.Base import _aq_reset
from AccessControl import ClassSecurityInfo
from AccessControl.SecurityManagement import newSecurityManager
import Products.ERP5Type
from Products.ERP5Type.Workflow import addWorkflowByType

class TestInteractionWorkflow(ERP5TypeTestCase):

  # Different variables used for this test
  run_all_test = 1
  portal_type = 'Organisation'

  def getTitle(self):
    """
    """
    return "Interaction Workflow"

  def getBusinessTemplateList(self):
    return ('erp5_base',)

  def afterSetUp(self):
    self.login()

  def beforeTearDown(self):
    Organisation = Products.ERP5.Document.Organisation.Organisation
    Organisation.security.names.pop('doSomethingStupid', None)
    if hasattr(Organisation, 'doSomethingStupid'):
      delattr(Organisation, 'doSomethingStupid')
    if hasattr(Organisation, 'doSomethingStupid__roles__'):
      delattr(Organisation, 'doSomethingStupid__roles__')

  def login(self, quiet=0):
    uf = self.getPortal().acl_users
    uf._doAddUser('seb', '', ['Manager', 'Assignor'], [])
    user = uf.getUserById('seb').__of__(uf)
    newSecurityManager(None, user)

  def createData(self):
    def doSomethingStupid(self,value,**kw):
      """
      """
      self.setDescription(value)
    Organisation = Products.ERP5.Document.Organisation.Organisation
    Organisation.doSomethingStupid = doSomethingStupid
    portal_type = self.getTypeTool()['Organisation']
    portal_type._setTypeBaseCategoryList(['size'])
    organisation_module = self.getOrganisationModule()
    self.organisation = organisation_module.newContent(
                          portal_type = self.portal_type)
    self.organisation.immediateReindexObject()

  def _createInteractionWorkflowWithId(self, wf_id):
    wf_tool = self.getWorkflowTool()
    return addWorkflowByType(wf_tool, "interaction_workflow", wf_id)

  def createInteractionWorkflow(self):
    id = 'test_workflow'
    wf_type = "interaction_workflow"
    if getattr(self.getWorkflowTool(), id, None) is None:
      self._createInteractionWorkflowWithId(id)
    wf = self.getWorkflowTool()[id]
    self.wf = wf
    if getattr(wf.scripts, 'afterEdit', None) is None:
      wf.scripts.manage_addProduct['PythonScripts']\
                    .manage_addPythonScript(id='afterEdit')
    self.script = wf.scripts['afterEdit']
    if getattr(wf.interactions, 'edit_interaction', None) is None:
      wf.interactions.addInteraction(id='edit_interaction')
    self.interaction = wf.interactions['edit_interaction']
    self.getWorkflowTool().setChainForPortalTypes(
                  [self.portal_type],'test_workflow, validation_workflow')
    _aq_reset() # XXX Fails XXX _setLastId not found when doing newContent

  def createInteractionWorkflowWithTwoInteractions(self):
    id = 'test_workflow'
    wf_type = "interaction_workflow (Web-configurable interaction workflow)"
    wf = self._createInteractionWorkflowWithId(id)
    self.wf = wf
    wf.scripts.manage_addProduct['PythonScripts']\
                  .manage_addPythonScript(id='afterEditA')
    self.scriptA = wf.scripts['afterEditA']
    wf.interactions.addInteraction(id='editA')
    self.interactionA = wf.interactions['editA']
    wf.scripts.manage_addProduct['PythonScripts']\
                  .manage_addPythonScript(id='afterEditB')
    self.scriptB = wf.scripts['afterEditB']
    wf.interactions.addInteraction(id='editB')
    self.interactionB = wf.interactions['editB']
    self.getWorkflowTool().setChainForPortalTypes(
                  [self.portal_type],'test_workflow, validation_workflow')
    _aq_reset() # XXX Fails XXX _setLastId not found when doing newContent

  def test_01(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage('No Interactions')
    self.createData()
    organisation = self.organisation
    organisation.edit()
    self.assertEqual(organisation.getDescription(),'')

  def test_02(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage('Interactions On Edit')
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'afterEdit',
            method_id='edit',
            after_script_name=('afterEdit',))
    #body = "sci.object.setDescription('toto')"
    params = 'sci,**kw'
    body = "context = sci.object\n" +\
           "context.setDescription('toto')"
    self.script.ZPythonScript_edit(params,body)
    self.createData()
    organisation = self.organisation
    organisation.setDescription('bad')
    organisation.edit()
    self.assertEqual(organisation.getDescription(),'toto')

  def test_03(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage(
        'Interactions, Edit Set Description and also After Script')
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'afterEdit',
            method_id='edit',
            after_script_name=('afterEdit',))
    body = "context = sci.object\n" +\
           "context.setDescription('toto')"
    params = 'sci,**kw'
    self.script.ZPythonScript_edit(params,body)
    self.createData()
    organisation = self.organisation
    organisation.setDescription('bad')
    organisation.edit(description='tutu')
    self.assertEqual(organisation.getDescription(),'toto')

  def test_04(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage('Interactions, Automatic Workflow Method')
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'afterEdit',
            method_id='doSomethingStupid',
            after_script_name=('afterEdit',))
    body = "context = sci.object\n" +\
           "context.setDescription('toto')"
    params = 'sci,**kw'
    self.script.ZPythonScript_edit(params, body)
    self.createData()
    organisation = self.organisation
    organisation.setDescription('bad')
    organisation.doSomethingStupid('tutu')
    self.assertEqual(organisation.getDescription(),'toto')

  def test_05(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage(
        'Interactions, Automatic Workflow Method With Extra Base Category')
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'afterEdit',
            method_id='setSizeList _setSizeList',
            after_script_name=('afterEdit',))
    body = "context = sci.object\n" +\
           "context.setDescription('toto')"
    params = 'sci,**kw'
    self.script.ZPythonScript_edit(params,body)
    self.createData()
    organisation = self.organisation
    organisation.setDescription('bad')
    organisation.setSizeList(['size/1','size/2'])
    self.assertEqual(organisation.getDescription(),'toto')

  def test_06(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage('Interactions, Check If There Is Only One Call')
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'afterEdit',
            method_id='edit',
            after_script_name=('afterEdit',))
    params = 'sci,**kw'
    body = "context = sci.object\n" +\
           "description = context.getDescription()\n" +\
           "context.setDescription(description + 'a')"
    self.script.ZPythonScript_edit(params,body)
    self.createData()
    organisation = self.organisation
    organisation.edit()
    self.assertEqual(organisation.getDescription(),'a')
    organisation.edit()
    self.assertEqual(organisation.getDescription(),'aa')

  def test_07(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage('Interactions, Check If The Return Value Is Not Altered')
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'afterEdit',
            method_id='newContent',
            after_script_name=('afterEdit',))
    params = 'sci,**kw'
    body = "context = sci.object\n" +\
           "return 3\n"
    self.script.ZPythonScript_edit(params,body)
    self.createData()
    organisation = self.organisation
    dummy_bank_account = organisation.newContent(
          portal_type='Bank Account',
          id='dummy_bank_account')
    self.assertNotEquals(dummy_bank_account, None)
    self.assertNotEquals(dummy_bank_account, 3)
    self.assertEqual(dummy_bank_account.getPortalType(), 'Bank Account')

  def test_08(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage('Interactions, Check If Multiple method_id Can Be Hooked')
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'afterEdit',
            method_id='setCorporateName setActivityCode',
            after_script_name=('afterEdit',))
    params = 'sci,**kw'
    body = "context = sci.object\n" +\
           "description = context.getDescription()\n" +\
           "context.setDescription(description + 'a')"
    self.script.ZPythonScript_edit(params,body)
    self.createData()
    organisation = self.organisation
    organisation.setCorporateName('corp')
    self.assertEqual(organisation.getDescription(),'a')
    organisation.setActivityCode('acode')
    self.assertEqual(organisation.getDescription(),'aa')

  def test_09(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage('Interactions, Check if the same method_id '\
                      'can be hooked by two Interactions')
    self.createInteractionWorkflowWithTwoInteractions()
    self.interactionA.setProperties(
            'afterEditA',
            method_id='edit',
            after_script_name=('afterEditA',))
    self.interactionB.setProperties(
            'afterEditB',
            method_id='edit',
            after_script_name=('afterEditB',))
    params = 'sci,**kw'
    body = "context = sci.object\n" +\
           "context.log('InteractionWF.test_09 in script', 'a')\n" +\
           "description = context.getDescription()\n" +\
           "context.setDescription(description + 'a')"
    self.scriptA.ZPythonScript_edit(params, body)
    self.scriptB.ZPythonScript_edit(params, body.replace("'a'", "'b'"))

    self.createData()
    organisation = self.organisation
    organisation.edit()
    self.assert_(organisation.getDescription() in ('ab', 'ba'),
        "description should be 'ab' or 'ba', it is %s" %
        organisation.getDescription())
    organisation.setCorporateName("this should not change anything")
    self.assert_(organisation.getDescription() in ('ab', 'ba'),
        "description should be 'ab' or 'ba', it is %s" %
        organisation.getDescription())

  def test_10(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage('Interactions, check if multiple scripts can be '
                      'called')
    self.createInteractionWorkflowWithTwoInteractions()
    self.interactionA.setProperties(
            'afterEdit',
            method_id='edit',
            after_script_name=('afterEditA', 'afterEditB'))
    params = 'sci,**kw'
    body = "context = sci.object\n" +\
           "context.log('InteractionWF.test_10 in script', 'a')\n" +\
           "description = context.getDescription()\n" +\
           "context.setDescription(description + 'a')"
    self.scriptA.ZPythonScript_edit(params, body)
    self.scriptB.ZPythonScript_edit(params, body.replace("'a'", "'b'"))

    self.createData()
    organisation = self.organisation
    organisation.edit()
    self.assert_(organisation.getDescription() in ('ab', 'ba'),
        "description should be 'ab' or 'ba', it is %s" %
        organisation.getDescription())
    organisation.setCorporateName("this should not change anything")
    self.assert_(organisation.getDescription() in ('ab', 'ba'),
        "description should be 'ab' or 'ba', it is %s" %
        organisation.getDescription())

  def test_11(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage(
        'Interactions, Test that the private accessor is called')

    self.createInteractionWorkflowWithTwoInteractions()
    self.interactionA.setProperties(
            'afterEditA',
            method_id='_setVatCode',
            after_script_name=('afterEditA',))
    self.interactionB.setProperties(
            'afterEditB',
            method_id='setVatCode',
            after_script_name=('afterEditB',))
    params = 'sci,**kw'
    body = "context = sci.object\n" +\
           "context.log('InteractionWF.test_11 in script', 'a')\n" +\
           "description = context.getDescription()\n" +\
           "context.setDescription(description + 'a')"
    self.scriptA.ZPythonScript_edit(params, body)
    self.scriptB.ZPythonScript_edit(params, body.replace("'a'", "'b'"))

    self.createData()
    organisation = self.organisation
    organisation._baseSetVatCode('x')
    organisation.setDescription('x')
    self.assertEqual(organisation.getVatCode(),'x')
    self.assertEqual(organisation.getDescription(),'x')
    organisation.edit(description='bar')
    organisation.edit(vat_code='foo')
    self.assertEqual(organisation.getVatCode(),'foo')
    self.assertEqual(organisation.getDescription(),'bara')

  def test_12(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage(
        'Interactions, Test that the private accessor is called, '
        'when using an Acquired Property')

    self.createInteractionWorkflowWithTwoInteractions()
    self.interactionA.setProperties(
            'afterEditA',
            method_id='_setDefaultEmailText',
            after_script_name=('afterEditA',))
    self.interactionB.setProperties(
            'afterEditB',
            method_id='setDefaultEmailText',
            after_script_name=('afterEditB',))
    params = 'sci,**kw'
    body = "context = sci.object\n" +\
           "context.log('InteractionWF.test_12 in script', 'a')\n" +\
           "vat_code = context.getVatCode()\n" +\
           "if vat_code is None:\n" +\
           "  vat_code = ''\n" +\
           "context.setVatCode(vat_code + 'a')"
    self.scriptA.ZPythonScript_edit(params, body)
    self.scriptB.ZPythonScript_edit(params, body.replace("'a'", "'b'"))

    self.createData()
    organisation = self.organisation
    organisation._baseSetDefaultEmailText('x')
    organisation.setVatCode('x')
    self.assertEqual(organisation.getDefaultEmailText(),'x')
    self.assertEqual(organisation.getVatCode(),'x')
    organisation.edit(vat_code='foo')
    organisation.edit(default_email_text='bar')
    self.assertEqual(organisation.getVatCode(),'fooa')
    self.assertEqual(organisation.getDefaultEmailText(),'bar')

  def test_13(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage('Interactions, Check that edit does not detect the '
          'property modified in interaction script as modified by user')
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'afterEdit',
            method_id='_setTitle',
            after_script_name=('afterEdit',))
    params = 'sci,**kw'
    body = "context = sci.object\n" +\
           "vat_code = context.getVatCode()\n" +\
           "if vat_code is None:\n" +\
           "  vat_code = ''\n" +\
           "context.setVatCode(vat_code + 'a')"
    self.script.ZPythonScript_edit(params,body)
    self.createData()
    organisation = self.organisation
    organisation.setTitle('foo')
    organisation.setVatCode('bar')
    self.assertEqual(organisation.getTitle(), 'foo')
    self.assertEqual(organisation.getVatCode(), 'bar')

    organisation.edit(title='baz', vat_code='bar', edit_order=['vat_code',
      'title'])
    self.assertEqual(organisation.getTitle(),'baz')
    # here, the wrong behaviour is:
    # - edit:setTitle(baz)
    # - interaction:setVatCode(bara)
    # - edit:setVatCode(bar)
    # whereas, the correct order is:
    # - edit:setTitle(baz)
    # - edit:setVatCode(bar)
    # - interaction:setVatCode(bara)
    self.assertEqual(organisation.getVatCode(),'bara')
    # now, test the other way around
    organisation.edit(title='baz', vat_code='bara', edit_order=['title',
      'vat_code'])
    self.assertEqual(organisation.getTitle(),'baz')
    # here, we assert the failure:
    # - edit:setTitle(baz)
    # - interaction:setVatCode(baraa)
    # - edit:setVatCode(bara)
    self.assertEqual(organisation.getVatCode(),'bara')


  def test_14_BeforeScriptParameters(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage('Before Script Parameters')
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'afterEdit',
            method_id='getProperty',
            script_name=('afterEdit',))
    params = 'sci,**kw'
    body = """\
context = sci['object']
kwargs = sci['kwargs'] or {}
d = kwargs.get('d', None)
args = kwargs.get('workflow_method_args', ())
result = kwargs.get('workflow_method_result', None)
context.setDescription('%s,%s,%s' % (d, args, result))
"""
    self.script.ZPythonScript_edit(params,body)
    self.createData()
    organisation = self.organisation
    organisation.setDescription('bad')
    value = organisation.getProperty('description', d='toto')
    self.assertEqual(value, "toto,('description',),None")

  def test_15_AfterScriptParameters(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage('After Script Parameters')
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'afterEdit',
            method_id='getProperty',
            after_script_name=('afterEdit',))
    params = 'sci,**kw'
    body = """\
context = sci['object']
kwargs = sci['kwargs'] or {}
d = kwargs.get('d', None)
args = kwargs.get('workflow_method_args', ())
result = kwargs.get('workflow_method_result', None)
context.setDescription('%s,%s,%s' % (d, args, result))
"""
    self.script.ZPythonScript_edit(params,body)
    self.createData()
    organisation = self.organisation
    organisation.setDescription('bad')
    organisation.getProperty('description', d='toto')
    value = organisation.getDescription()
    self.assertEqual(value, "toto,('description',),bad")

  def test_16_BeforeCommitParameters(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage('Before Commit Script Parameters')
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'beforeCommit',
            method_id='getProperty',
            before_commit_script_name=('afterEdit',))
    params = 'sci, **kw'
    body = """\
context = sci['object']
kwargs = sci['kwargs'] or {}
d = kwargs.get('d', None)
args = kwargs.get('workflow_method_args', ())
result = kwargs.get('workflow_method_result', None)
context.setDescription('%s,%s,%s' % (d, args, result))
"""
    self.script.ZPythonScript_edit(params, body)
    self.createData()
    organisation = self.organisation
    organisation.setDescription('bad')
    self.assertEqual(organisation.getDescription(), 'bad')
    organisation.getProperty('description', d='toto')
    self.assertEqual(organisation.getDescription(), 'bad')
    # before-commit interactions should be immune to security changes
    self.logout()
    self.commit()
    self.login()
    self.assertEqual(organisation.getDescription(), "toto,('description',),bad")

  def test_17_activity_interaction(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage('Later Script (In activity)')
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'editObject',
            once_per_transaction=1,
            method_id='_setGroup.*',
            activate_script_name=('afterEdit',))
    params = 'sci, **kw'
    body = """\
context = sci['object']
context.setTitle('Bar')
"""
    self.script.ZPythonScript_edit(params, body)
    self.createData()
    organisation = self.organisation
    organisation.setTitle('Foo')
    organisation.setGroupValue(organisation)
    self.assertEqual(organisation.getTitle(), 'Foo')
    self.commit()
    self.assertEqual(organisation.getTitle(), 'Foo')
    self.tic()
    self.assertEqual(organisation.getTitle(), 'Bar')

  def test_18_no_temp_object(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage('Skips Temp Objects')
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'editObject',
            temporary_document_disallowed=False,
            method_id='_setGroup.*',
            after_script_name=('afterEdit',))
    params = 'sci, **kw'
    body = """\
context = sci['object']
context.setTitle('Bar')
"""
    self.script.ZPythonScript_edit(params, body)
    self.createData()
    organisation = self.organisation
    temp = organisation.asContext()
    temp.setTitle('Foo')
    # interaction workflows can affect temp objects
    temp.setGroupValue(organisation)
    self.assertEqual(temp.getTitle(), 'Bar')
    # but not if it has been forbidden
    temp.setTitle('Foo')
    self.interaction.setProperties(
            'editObject',
            temporary_document_disallowed=True,
            method_id='_setGroup.*',
            after_script_name=('afterEdit',))
    temp.setGroupValue(None)
    self.assertEqual(temp.getTitle(), 'Foo')

  def test_19_temp_object_doesnt_skip_normal(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage('Skips Temp Objects, but run in normal objects in the same transaction')
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'editObject',
            once_per_transaction=True,
            temporary_document_disallowed=True,
            method_id='_setGroup.*',
            after_script_name=('afterEdit',))
    params = 'sci, **kw'
    body = """\
context = sci['object']
context.setTitle('Bar')
"""
    self.script.ZPythonScript_edit(params, body)
    self.createData()
    organisation = self.organisation
    organisation.setTitle('Foo')
    temp = organisation.asContext()
    # temp and organisation have the same path
    self.assertEqual(temp.getPath(), organisation.getPath())
    # which means that a transactional variable key based on path
    # would match both the organisation and the temp object, but
    # triggering the workflow on the temp object should not change it
    # because it's prevented by configuration:
    temp.setGroupValue(organisation)
    self.assertEqual(temp.getTitle(), 'Foo')
    # nor should it change the normal object
    self.assertEqual(organisation.getTitle(), 'Foo')
    # however, it should allow triggering the normal object later on the same
    # transaction
    organisation.setGroupValue(organisation)
    self.assertEqual(organisation.getTitle(), 'Bar')
    # while still not changing the temp object
    self.assertEqual(temp.getTitle(), 'Foo')

  def test_20_temp_object_does_skip_normal(self, quiet=0, run=run_all_test):
    if not run: return
    if not quiet:
      self.logMessage('Runs on temp Objects and skip normal objects')
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'editObject',
            once_per_transaction=True,
            temporary_document_disallowed=False,
            method_id='_setGroup.*',
            after_script_name=('afterEdit',))
    params = 'sci, **kw'
    body = """\
context = sci['object']
context.setTitle('Bar')
"""
    self.script.ZPythonScript_edit(params, body)
    self.createData()
    organisation = self.organisation
    organisation.setTitle('Foo')
    temp = organisation.asContext()
    # temp and organisation have the same path
    self.assertEqual(temp.getPath(), organisation.getPath())
    # which means that a transactional variable key based on path
    # would match both the organisation and the temp
    # object. Triggering the workflow on the temp object Will change
    # it, since this is not prevented by configuration:
    temp.setGroupValue(organisation)
    self.assertEqual(temp.getTitle(), 'Bar')
    # This should not change the normal object
    self.assertEqual(organisation.getTitle(), 'Foo')
    # However, since the interaction can only run once per transaction
    # (and per object path), it cannot run again on the normal object:
    organisation.setGroupValue(organisation)
    self.assertEqual(organisation.getTitle(), 'Foo')
    # This can be considered an undesired side-effect, so if this test
    # starts failing in the assertion above for a good reason, just
    # fix the test.
    self.commit()
    # committing the transaction allows the interaction workflow to
    # run on the normal object again:
    organisation.setGroupValue(None)
    self.assertEqual(organisation.getTitle(), 'Bar')

  def test_regular_expression(self):
    # test that we can add an interaction by defining methods using regular
    # expression
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'regexp',
            method_id='_set.* set.*',
            after_script_name=('afterEdit',))

    call_list = self.portal.REQUEST['call_list'] = []
    self.script.ZPythonScript_edit('sci',
        'container.REQUEST["call_list"].append(1)')
    self.createData()
    organisation = self.organisation
    # all methods matching set.* regular expression are matched
    organisation.setDescription('')
    # two calls: setDescription, _setDescription
    self.assertEqual(len(call_list), 2)
    organisation.setTitle('')
    # two calls: setTitle, _setTitle
    self.assertEqual(len(call_list), 4)
    organisation.getDescription()
    # no calls
    self.assertEqual(len(call_list), 4)
    organisation.edit(description='desc')
    # two calls: one to _setProperty, and one to _setDescription
    self.assertEqual(len(call_list), 6)


  def test_security(self):
    # wrapping a method in an interaction workflow adds a default security to
    # this method if the method does not exists.
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'default',
            method_id='nonExistantMethod',
            after_script_name=('afterEdit',))
    self.script.ZPythonScript_edit('sci', '')
    self.createData()
    # the default security is "Access contents information"
    self.organisation.manage_permission(
                      'Access contents information', ['Role1'], 0)
    self.assertEqual(self.organisation.nonExistantMethod__roles__,
                      ('Role1',))

  def test_security_defined(self):
    # wrapping a method in an interaction workflow adds a default security to
    # this method, but does not override existing security definition
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'default',
            method_id='setDescription',
            after_script_name=('afterEdit',))
    self.script.ZPythonScript_edit('sci', '')
    self.createData()
    # This rely on the fact that 'setDescription' is protected with 'Modify
    # portal content'
    self.organisation.manage_permission(
                     'Modify portal content', ['Role2'], 0)
    self.assertEqual(self.organisation.setDescription__roles__,
                      ('Role2',))

  def test_security_defined_on_class(self):
    # wrapping a method in an interaction workflow adds a default security to
    # this method, but does not override existing security definition (defined
    # on the class)
    Organisation = Products.ERP5.Document.Organisation.Organisation
    security = ClassSecurityInfo()
    security.declarePrivate('doSomethingStupid')
    security.apply(Organisation)

    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'default',
            method_id='doSomethingStupid',
            after_script_name=('afterEdit',))
    self.script.ZPythonScript_edit('sci', '')
    self.createData()

    self.assertEqual(self.organisation.doSomethingStupid__roles__, ())

  def test_wrap_workflow_transition(self):
    self.logMessage('Wrap workflow transition')
    self.createInteractionWorkflow()
    self.interaction.setProperties(
            'default',
            method_id='validate',
            after_script_name=('afterEdit',))
    params = 'sci, **kw'
    body = "context = sci[\'object\']\n" +\
           "context.setDescription('titi')"
    self.script.ZPythonScript_edit(params, body)
    self.createData()
    self.assertEqual('', self.organisation.getDescription())
    self.portal.portal_workflow.doActionFor(self.organisation, 'validate_action')
    self.assertEqual('validated', self.organisation.getValidationState())
    self.assertEqual('titi', self.organisation.getDescription())

def test_suite():
  suite = unittest.TestSuite()
  suite.addTest(unittest.makeSuite(TestInteractionWorkflow))
  return suite