##############################################################################
#
# Copyright (c) 2002-2011 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility 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
# guarantees 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################

from Products.ERP5Type.tests.SecurityTestCase import SecurityTestCase
from httplib import OK as HTTP_OK
import random

class TestQuestionnaireSecurity(SecurityTestCase):  
  def getTitle(self):
    return "Test Questionnaire Security"
  
  def getBusinessTemplateList(self):
    """
    Tuple of Business Templates we need to install
    """
    return ('erp5_base',
            'erp5_credential',
            'erp5_deferred_style',
            'erp5_ingestion',
            'erp5_ingestion_mysql_innodb_catalog',
            'erp5_web',
            'erp5_dms',
            'erp5_ods_style',
            'erp5_odt_style',
            'erp5_workflow',
            'erp5_survey')
  
  def afterSetUp(self):
    """
    This is ran before anything, used to set the environment
    """
    # here, you can create the categories and objects your test will depend on
    self.portal = self.getPortal()
    self.assertTrue(self.portal is not None)

    #Create users to interact with the questionnaire (ran only once)
    user_list = [
     dict(title ='Researcher', reference='researcher', function='education/researcher'),
     dict(title ='Professor', reference='professor', function='education/professor'),
     dict(title ='Student', reference='student', function='education/student'),
     dict(title ='Spy', reference='spy', function=None)
     ]
    # let's create the users
    self.person_module = self.portal.getDefaultModule(portal_type='Person')
    for user in user_list:
      try:
        self.createSimpleUser(**user)
      except RuntimeError:
        pass
    self.tic()

    self.question_module = self.portal.getDefaultModule(portal_type='Boolean Question')
    self.question_module.updateLocalRolesOnSecurityGroups()
    self.assertTrue(self.question_module is not None)
    self.questionnaire_module = self.portal.getDefaultModule(portal_type='Questionnaire')
    self.questionnaire_module.updateLocalRolesOnSecurityGroups()
    self.assertTrue(self.questionnaire_module is not None)
    self.person_module = self.portal.getDefaultModule(portal_type='Person')
    self.person_module.updateLocalRolesOnSecurityGroups()
    self.assertTrue(self.person_module is not None)
    self.organisation_module = self.portal.getDefaultModule(portal_type='Organisation')
    self.organisation_module.updateLocalRolesOnSecurityGroups()
    self.assertTrue(self.organisation_module is not None)
    self.answer_set_module = self.portal.getDefaultModule(portal_type='Answer Set')
    self.answer_set_module.updateLocalRolesOnSecurityGroups()
    self.assertTrue(self.answer_set_module is not None)
    self.correction_module = self.portal.getDefaultModule(portal_type='Correction')
    self.correction_module.updateLocalRolesOnSecurityGroups()
    self.assertTrue(self.correction_module is not None)
    self.standard_category_module = self.portal.standard_category_module #portal_catalog(portal_type='Standard Category Module')[0] #Standard Category Module is not Base Category's default module
    self.standard_category_module.updateLocalRolesOnSecurityGroups()
    self.assertTrue(self.standard_category_module is not None)

  def _newQuestionnaire(self, content=''):
    # Helper function to create a new Questionnaire
    questionnaire = self.questionnaire_module.newContent( portal_type = 'Questionnaire',
                                title       =  content,
                                comment     = 'Some Comment',
                                description = 'Some Description',
                                batch_mode  = True
                              )
    return questionnaire

  def _newQuestion(self, portal_type = 'Boolean Question', content=''):
    # Helper function to create a new Question
    question = self.question_module.newContent( portal_type = portal_type,
                                title       = 'Some ' + portal_type + ' Title', 
                                comment     = 'Some Comment',
                                description = 'Some Description',
                                max_grade   = random.randint(1, 10),
                                batch_mode   = True
                              )
    return question

  def _getQuestionPortalTypeList(self, include_statement = True, everything = True, multiple_choice = False):
    l =  []
    if everything:
      l = ['Boolean Question','Document Question','Float Question','Integer Question', 'String Question', 'Text Question', 'Multi Selection Question', 'Selection Question']
    else :
      if multiple_choice:
        l = ['Multi Selection Question', 'Selection Question']
      else :
        l = ['Boolean Question','Document Question','Float Question','Integer Question', 'String Question', 'Text Question']
    if include_statement:
      l.append('Statement')
    return l
    

  def _addPossibleAnswer(self, question = None, value_property_id = 'float_value'):
    if value_property_id == 'string_value':
      possible_answer = question.newContent(portal_type = 'Possible Answer',
                          title       = 'Some String Answer',
                          string_value= 'some_string_answer',
                          value_property_id = 'string_value',
                          batch_mode  = True
                          )
    elif value_property_id == 'integer_value':
      value = random.randint(1,10)
      possible_answer = question.newContent(portal_type = 'Possible Answer',
                          title       = 'Some Integer Answer (' + str(value) + ')',
                          integer_value = value,
                          value_property_id = 'integer_value',
                          batch_mode  = True
                          )
    else:
      value = random.uniform(1,10)

      possible_answer = question.newContent(portal_type = 'Possible Answer',
                          title       = 'Some Float Answer (' + str(value) + ')',
                          float_value = value,
                          value_property_id = 'float_value',
                          batch_mode  = True
                          )
    return possible_answer

  def _UserCanCreateQuestion(self, reference = 'professor', access_capability = True, add_capability = True, multiple_choice = False):
    """
    Use case:
        - user creates a question
        - that user can see it
        - that user can edit it
    """
    self.login(reference)

    # user should be able to access/view the question module
    if access_capability:
      self.assertUserCanAccessDocument(reference, self.question_module)
      self.assertUserCanViewDocument(reference, self.question_module)
      if add_capability:
        self.assertUserCanAddDocument(reference, self.question_module)
      else:
        self.failIfUserCanAddDocument(reference, self.question_module)
    else :
      add_capability = False 
      self.failIfUserCanAccessDocument(reference, self.question_module)
      self.failIfUserCanViewDocument(reference, self.question_module)
      self.failIfUserCanAddDocument(reference, self.question_module)

    if multiple_choice :
      question_list = self._getQuestionPortalTypeList(include_statement = False, everything = False, multiple_choice = True)
    else :
      question_list = self._getQuestionPortalTypeList(everything = False, multiple_choice = False)

    for portal_type in question_list :
      # students cannot add questions, let's make researcher add them
      if add_capability:        
        question_content='New question'
        question = self._newQuestion(portal_type = portal_type, content=question_content)
        self.assertTrue(question is not None)
      else:
        self.login('researcher')
        question_content='New question'
        question = self._newQuestion(portal_type = portal_type, content=question_content)
        self.assertTrue(question is not None)
        self.login(reference)    

      # user should be able to access/view the created question
      if access_capability:
        self.assertUserCanViewDocument(reference, question)
        self.assertUserCanAccessDocument(reference, question)
      else:
        self.failIfUserCanViewDocument(reference, question)
        self.failIfUserCanAccessDocument(reference, question)        

      # user should be able to modify question and add/access/view/modify possible_answers
      if add_capability:
        self.assertUserCanModifyDocument(reference, question)
        if multiple_choice :
          self.assertUserCanAddDocument(reference, question)
          for value_property_id in ['string_value','integer_value','float_value']:
            possible_answer = self._addPossibleAnswer(question = question, value_property_id = value_property_id)
            self.assertTrue(possible_answer is not None)
            self.assertUserCanViewDocument(reference, possible_answer)
            self.assertUserCanAccessDocument(reference, possible_answer) 
            self.assertUserCanModifyDocument(reference, possible_answer) 

            # Check that the possible answer is inserted in the question
            self.assertEquals(possible_answer.getParentValue().getRelativeUrl(), question.getRelativeUrl())
            self.assertEquals(len(possible_answer.objectValues()), 0)
      else:
        self.failIfUserCanModifyDocument(reference, question)
        if multiple_choice :
          self.failIfUserCanAddDocument(reference, question)
          
          # student cannot add possible answers so let researcher add one
          self.login('researcher')
          for value_property_id in ['string_value','integer_value','float_value']:
            possible_answer = self._addPossibleAnswer(question = question, value_property_id = value_property_id)
            self.assertTrue(possible_answer is not None)
            if access_capability :
              self.assertUserCanViewDocument(reference, possible_answer)
              self.assertUserCanAccessDocument(reference, possible_answer)
            else :
              self.failIfUserCanViewDocument(reference, possible_answer)
              self.failIfUserCanAccessDocument(reference, possible_answer)
            self.failIfUserCanModifyDocument(reference, possible_answer) 

            # Check that the possible answer is inserted in the question
            self.assertEquals(possible_answer.getParentValue().getRelativeUrl(), question.getRelativeUrl())
            self.assertEquals(len(possible_answer.objectValues()), 0)
          self.login(reference)
      # get content
      content = question.objectValues()
      
      # question shouldn't have any content
      if multiple_choice:
        self.assertEquals(len(content), 3)
      else :
        self.assertEquals(len(content), 0)
      
      # Check that the question is inserted in the question module
      self.assertEquals(question.getParentValue().getRelativeUrl(), self.question_module.getRelativeUrl())
      
     # the question should be in draft state
      self.assertEquals(question.getValidationState(), 'draft')
    #transaction.commit()
    #self.tic()

  def test_001_ProfessorCanCreateSimpleQuestion(self):
    self._UserCanCreateQuestion(reference = 'professor')

  def test_002_ResearcherCanCreateSimpleQuestion(self):
    self._UserCanCreateQuestion(reference = 'researcher')

  def test_003_StudentCannotCreateSimpleQuestion(self):
    self._UserCanCreateQuestion(reference = 'student', add_capability = False)

  def test_004_SpyCannotViewAccessSimpleQuestion(self):
    self._UserCanCreateQuestion(reference = 'spy', access_capability = False)

  def test_005_ProfessorCanCreateMultipleChoiceQuestion(self):
    self._UserCanCreateQuestion(reference = 'professor', multiple_choice = True)

  def test_006_ResearcherCanCreateMultipleChoiceQuestion(self):
    self._UserCanCreateQuestion(reference = 'researcher', multiple_choice = True)

  def test_007_StudentCannotCreateMultipleChoiceQuestion(self):
    self._UserCanCreateQuestion(reference = 'student', add_capability = False, multiple_choice = True)

  def test_008_SpyCannotViewAccessMultipleChoiceQuestion(self):
    self._UserCanCreateQuestion(reference = 'spy', access_capability = False, multiple_choice = True)

  def _UserCanCreateQuestionnaire(self, reference = 'professor', access_capability = True, add_capability = True):
    """
    Use case:
        - user creates a questionnaire
        - that user can see it
        - that user can edit it
    """
    self.login(reference)

    # user should be able to access/view the questionnaire module
    
    if access_capability:
      self.assertUserCanAccessDocument(reference, self.questionnaire_module)
      self.assertUserCanViewDocument(reference, self.questionnaire_module)
      if add_capability:
        self.assertUserCanAddDocument(reference, self.questionnaire_module)
      else:
        self.failIfUserCanAddDocument(reference, self.questionnaire_module)
    else :
      add_capability = False
      self.failIfUserCanAccessDocument(reference, self.questionnaire_module)
      self.failIfUserCanViewDocument(reference, self.questionnaire_module)
      self.failIfUserCanAddDocument(reference, self.questionnaire_module)

    # students and spies cannot add questionnaires, let's make researcher add them
    questionnaire_content='Some Questionnaire Title'
    if add_capability:
      questionnaire = self._newQuestionnaire(content=questionnaire_content)        
    else:
      self.login('researcher')
      questionnaire = self._newQuestionnaire(content=questionnaire_content)
      self.login(reference)    
      
    self.assertTrue(questionnaire is not None)

    # user should be able to access/view the created questionnaire
    if access_capability:
      self.assertUserCanViewDocument(reference, questionnaire)
      self.assertUserCanAccessDocument(reference, questionnaire)
    else:
      self.failIfUserCanViewDocument(reference, questionnaire)
      self.failIfUserCanAccessDocument(reference, questionnaire)

    # user should be able to modify questionnaire and add/access/view/modify question states
    if add_capability:
      self.assertUserCanModifyDocument(reference, questionnaire)
      self.assertUserCanAddDocument(reference, questionnaire)                                  
    else:
      self.failIfUserCanModifyDocument(reference, questionnaire)
      self.failIfUserCanAddDocument(reference, questionnaire)        
      
    # get content
    content = questionnaire.objectValues()
      
    # questionnaire shouldn't have any content
    self.assertEquals(len(content), 0)
      
    # Check that the questionnaire is inserted in the questionnaire module
    self.assertEquals(questionnaire.getParentValue().getRelativeUrl(), self.questionnaire_module.getRelativeUrl())
      
    # the questionnaire should be in draft state
    self.assertEquals(questionnaire.getValidationState(), 'draft')
    
    #transaction.commit()
    #self.tic()


  def test_009_ProfessorCanCreateQuestionnaire(self):
    self._UserCanCreateQuestionnaire(reference = 'professor')

  def test_010_ResearcherCanCreateQuestionnaire(self):
    self._UserCanCreateQuestionnaire(reference = 'researcher')

  def test_011_StudentCannotCreateQuestionnaire(self):
    self._UserCanCreateQuestionnaire(reference = 'student', add_capability = False)

  def test_012_SpyCannotViewAccessQuestionnaire(self):
    self._UserCanCreateQuestionnaire(reference = 'spy', access_capability = False)

  def _newQuestionState(self, question = None, questionnaire = None):
    # Helper function to create a new Question
    question_state = questionnaire.newContent( portal_type = 'Question State',
                                title       = 'Some Question State Title',
                                description = 'Some Description',
                                batch_mode   = True
                              )
    question_state.setResourceValue(question)
    return question_state


  def _UserCanCreateQuestionState(self, reference = 'professor', access_capability = True, add_capability = True):
    """
    Use case:
        - user creates a question state
        - that user can see it
        - that user can edit it
    """
    self.login(reference)

    # students and spies cannot add questionnaires and questions, let's make researcher add them
    questionnaire_content='Some Questionnaire Title'
    if add_capability:
      questionnaire = self._newQuestionnaire(content=questionnaire_content)
      self.assertTrue(questionnaire is not None)
      question = self._newQuestion()
      self.assertTrue(question is not None)
      question_state = self._newQuestionState(questionnaire=questionnaire, question=question)
      self.assertTrue(question_state is not None)
      self.assertUserCanAccessDocument(reference, question_state)
      self.assertUserCanViewDocument(reference, question_state)   
      self.assertUserCanModifyDocument(reference, question_state)    
      self.assertUserCanAddDocument(reference, question_state)         
    else:
      self.login('researcher')
      questionnaire = self._newQuestionnaire(content=questionnaire_content)
      self.assertTrue(questionnaire is not None)
      question = self._newQuestion()
      self.assertTrue(question is not None)
      question_state = self._newQuestionState(questionnaire=questionnaire, question=question)
      self.assertTrue(question_state is not None)
      self.login(reference)
      self.failIfUserCanModifyDocument(reference, question_state)  
      self.failIfUserCanAddDocument(reference, question_state)    
      if access_capability:
        self.assertUserCanAccessDocument(reference, question_state)
        self.assertUserCanViewDocument(reference, question_state)
      else:
        self.failIfUserCanAccessDocument(reference, question_state)
        self.failIfUserCanViewDocument(reference, question_state)
      
    # question state shouldn't have any content
    content = question_state.objectValues()
    self.assertEquals(len(content), 0)

    # questionnaire should have content
    content = questionnaire.objectValues()
    self.assertEquals(len(content), 1)
      
    # Check that the question state is inserted in the questionnaire
    self.assertEquals(question_state.getParentValue().getRelativeUrl(), questionnaire.getRelativeUrl())
    

  def test_013_ProfessorCanCreateQuestionState(self):
    self._UserCanCreateQuestionState(reference = 'professor')

  def test_014_ResearcherCanCreateQuestionState(self):
    self._UserCanCreateQuestionState(reference = 'researcher')

  def test_015_StudentCannotCreateQuestionState(self):
    self._UserCanCreateQuestionState(reference = 'student', add_capability = False)
 
  def test_016_SpyCannotViewAccessQuestionState(self):
    self._UserCanCreateQuestionState(reference = 'spy', access_capability = False, add_capability = False)

  def _newVariable(self, questionnaire = None):
    # Helper function to create a new Variable
    variable = questionnaire.newContent( portal_type = 'Variable',
                                title       = 'Some Variable Title',
                                description = 'Some Description',
                                comment = 'Some Comment',
                                automatic_update = True,
                                initial_value = 'python: 1',
                                batch_mode   = True
                              )
    return variable

  def _UserCanCreateVariable(self, reference = 'professor', access_capability = True, add_capability = True):
    """
    Use case:
        - user creates a variable
        - that user can see it
        - that user can edit it
    """
    self.login(reference)

    # students and spies cannot add questionnaires and questions, let's make researcher add them
    questionnaire_content='Some Questionnaire Title'
    if add_capability:
      questionnaire = self._newQuestionnaire(content=questionnaire_content)
      self.assertTrue(questionnaire is not None)
      question = self._newQuestion()
      self.assertTrue(question is not None)
      variable = self._newVariable(questionnaire=questionnaire)
      self.assertTrue(variable is not None)
      self.assertUserCanAccessDocument(reference, variable)
      self.assertUserCanViewDocument(reference, variable)   
      self.assertUserCanModifyDocument(reference, variable)    
      self.assertUserCanAddDocument(reference, variable)         
    else:
      self.login('researcher')
      questionnaire = self._newQuestionnaire(content=questionnaire_content)
      self.assertTrue(questionnaire is not None)
      question = self._newQuestion()
      self.assertTrue(question is not None)
      variable = self._newVariable(questionnaire=questionnaire)
      self.assertTrue(variable is not None)
      self.login(reference)
      if access_capability:
        self.assertUserCanAccessDocument(reference, variable)
        self.assertUserCanViewDocument(reference, variable)
      else:
        self.failIfUserCanAccessDocument(reference, variable)
        self.failIfUserCanViewDocument(reference, variable)
      self.failIfUserCanModifyDocument(reference, variable)  
      self.failIfUserCanAddDocument(reference, variable)   
    # get content
    content = variable.objectValues()
      
    # variable shouldn't have any content
    self.assertEquals(len(content), 0)

    # questionnaire should have content
    content = questionnaire.objectValues()
    self.assertEquals(len(content), 1)
      
    # Check that the question_state is inserted in the questionnaire module
    self.assertEquals(variable.getParentValue().getRelativeUrl(), questionnaire.getRelativeUrl())

  def test_017_ProfessorCanCreateVariable(self):
    self._UserCanCreateVariable(reference = 'professor')

  def test_018_ResearcherCanCreateVariable(self):
    self._UserCanCreateVariable(reference = 'researcher')

  def test_019_StudentCanViewAccessVariable(self):
    self._UserCanCreateVariable(reference = 'student', add_capability = False)
 
  def test_020_SpyCannotViewAccessVariable(self):
    self._UserCanCreateVariable(reference = 'spy', access_capability = False, add_capability = False)

  def _newAnswerTransition(self, question_state = None, test_version = True, destination_question_state = None):
    # Helper function to create a new Answer Transition
    if test_version:
      answer_transition = question_state.newContent( portal_type = 'Answer Transition',
                                title       = 'Some Answer Transition Title',
                                guard_expression = 'python: False',
                                description  = 'Some description',
                                before_script_id = 'before_script',
                                after_script_id  = 'after_script',
                                batch_mode   = True
                              )
    else:
      answer_transition = question_state.newContent( portal_type = 'Answer Transition',
                                title       = 'Some Answer Transition Title',
                                description  = 'Some description',
                                batch_mode   = True
                              )

    if destination_question_state is None:
      answer_transition.setDestinationValue(question_state)
    else :
      answer_transition.setDestinationValue(destination_question_state)
    return answer_transition


  def _UserCanCreateAnswerTransition(self, reference = 'professor', access_capability = True, add_capability = True):
    """
    Use case:
        - user creates an answer transition
        - that user can see it
        - that user can edit it
    """
    self.login(reference)

    # students and spies cannot add questionnaires and questions, let's make researcher add them
    questionnaire_content='Some Questionnaire Title'
    if add_capability:
      questionnaire = self._newQuestionnaire(content=questionnaire_content)
      self.assertTrue(questionnaire is not None)
      question = self._newQuestion()
      self.assertTrue(question is not None)
      question_state = self._newQuestionState(questionnaire=questionnaire, question=question)
      self.assertTrue(question_state is not None)
      answer_transition = self._newAnswerTransition(question_state = question_state)
      self.assertTrue(answer_transition is not None)
      self.assertUserCanAccessDocument(reference, answer_transition)
      self.assertUserCanViewDocument(reference, answer_transition)   
      self.assertUserCanModifyDocument(reference, answer_transition)    
      self.assertUserCanAddDocument(reference, answer_transition)         
    else:
      self.login('researcher')
      questionnaire = self._newQuestionnaire(content=questionnaire_content)
      self.assertTrue(questionnaire is not None)
      question = self._newQuestion()
      self.assertTrue(question is not None)
      question_state = self._newQuestionState(questionnaire=questionnaire, question=question)
      self.assertTrue(question_state is not None)
      answer_transition = self._newAnswerTransition(question_state = question_state)
      self.assertTrue(answer_transition is not None)
      self.login(reference)
      self.failIfUserCanModifyDocument(reference, answer_transition)  
      self.failIfUserCanAddDocument(reference, answer_transition)
      if access_capability:    
        self.assertUserCanAccessDocument(reference, answer_transition)
        self.assertUserCanViewDocument(reference, answer_transition)
      else :    
        self.failIfUserCanAccessDocument(reference, answer_transition)
        self.failIfUserCanViewDocument(reference, answer_transition)

    # get content
    content = answer_transition.objectValues()
      
    # answer_transition shouldn't have any content
    self.assertEquals(len(content), 0)

    # question_state should have content
    content = question_state.objectValues()
    self.assertEquals(len(content), 1)
      
    # Check that the questionnaire is inserted in the questionnaire module
    self.assertEquals(answer_transition.getParentValue().getRelativeUrl(), question_state.getRelativeUrl())

  def test_021_ProfessorCanCreateAnswerTransition(self):
    self._UserCanCreateAnswerTransition(reference = 'professor')

  def test_022_ResearcherCanCreateAnswerTransition(self):
    self._UserCanCreateAnswerTransition(reference = 'researcher')

  def test_023_StudentCanViewAccessAnswerTransition(self):
    self._UserCanCreateAnswerTransition(reference = 'student', access_capability = True, add_capability = False)
 
  def test_024_SpyCannotViewAccessAnswerTransition(self):
    self._UserCanCreateAnswerTransition(reference = 'spy', access_capability = False, add_capability = False)

  def _newTransitionVariable(self, answer_transition = None):
    # Helper function to create a new Transition Variable
    transition_variable = answer_transition.newContent( portal_type = 'Transition Variable',
                                description   = 'Some description',
                                comment       = 'Some comment',
                                initial_value = 'python: None',
                                batch_mode    = True
                              )
    return transition_variable


  def _UserCanCreateTransitionVariable(self, reference = 'professor', access_capability = True, add_capability = True):
    """
    Use case:
        - user creates an transition variable
        - that user can see it
        - that user can edit it
    """
    self.login(reference)

    # students and spies cannot add questionnaires and questions, let's make researcher add them
    questionnaire_content='Some Questionnaire Title'
    if add_capability:
      questionnaire = self._newQuestionnaire(content=questionnaire_content)
      self.assertTrue(questionnaire is not None)
      question = self._newQuestion()
      self.assertTrue(question is not None)
      question_state = self._newQuestionState(questionnaire=questionnaire, question=question)
      self.assertTrue(question_state is not None)
      answer_transition = self._newAnswerTransition(question_state = question_state)
      self.assertTrue(answer_transition is not None)
      transition_variable = self._newTransitionVariable(answer_transition = answer_transition)
      self.assertTrue(transition_variable is not None)
      self.assertUserCanAccessDocument(reference, transition_variable)
      self.assertUserCanViewDocument(reference, transition_variable)   
      self.assertUserCanModifyDocument(reference, transition_variable)    
      self.assertUserCanAddDocument(reference, transition_variable)         
    else:
      self.login('researcher')
      questionnaire = self._newQuestionnaire(content=questionnaire_content)
      self.assertTrue(questionnaire is not None)
      question = self._newQuestion()
      self.assertTrue(question is not None)
      question_state = self._newQuestionState(questionnaire=questionnaire, question=question)
      self.assertTrue(question_state is not None)
      answer_transition = self._newAnswerTransition(question_state = question_state)
      self.assertTrue(answer_transition is not None)
      transition_variable = self._newTransitionVariable(answer_transition = answer_transition)
      self.assertTrue(transition_variable is not None)
      self.login(reference)
      self.failIfUserCanModifyDocument(reference, transition_variable)  
      self.failIfUserCanAddDocument(reference, transition_variable) 
      if access_capability:
        self.assertUserCanAccessDocument(reference, transition_variable)
        self.assertUserCanViewDocument(reference, transition_variable)
      else:
        self.failIfUserCanAccessDocument(reference, transition_variable)
        self.failIfUserCanViewDocument(reference, transition_variable)
    # get content
    content = transition_variable.objectValues()
      
    # transition_variable shouldn't have any content
    self.assertEquals(len(content), 0)

    # answer_transition should have content
    content = answer_transition.objectValues()
    self.assertEquals(len(content), 1)
      
    # Check that the questionnaire is inserted in the questionnaire module
    self.assertEquals(transition_variable.getParentValue().getRelativeUrl(), answer_transition.getRelativeUrl())

  def test_025_ProfessorCanCreateTransitionVariable(self):
    self._UserCanCreateTransitionVariable(reference = 'professor')

  def test_026_ResearcherCanCreateTransitionVariable(self):
    self._UserCanCreateTransitionVariable(reference = 'researcher')

  def test_027_StudentCanViewAccessTransitionVariable(self):
    self._UserCanCreateTransitionVariable(reference = 'student', add_capability = False)
 
  def test_028_SpyCannotViewAccessTransitionVariable(self):
    self._UserCanCreateTransitionVariable(reference = 'spy', access_capability = False, add_capability = False)

  def _newOrganisation(self):
    organisation = self.organisation_module.newContent(portal_type = 'Organisation',
                                        title       = 'Some Organisation'
                                        )
    return organisation


  def _newPerson(self, organisation = None):
    person = self.person_module.newContent(portal_type = 'Person',
                                  title       = 'First Name Last Name',
                                  first_name  = 'First Name',
                                  last_name   = 'Last Name'
                                 )

    if organisation is not None:
      person.setCareerSubordinationValue(organisation)
    return person

  def _newAnswerSet(self, person = None, questionnaire = None, pattern_list = ['organisation_type/hospital']):
    # Helper function to create a new Answer Set
    if person is not None:
      reference = 'A-Example Organisation-' + person.getFirstName() + '-' + person.getLastName() + '-1'
    else :
      reference = 'A-None-None-None-1'
    answer_set = self.answer_set_module.newContent( portal_type = 'Answer Set',
                                title         = reference,
                                reference     = reference,
                                description   = 'Some description',
                                pattern_list  = pattern_list,
                                batch_mode    = True
                              )
    answer_set.setSourceValue(person)
    answer_set.setCausalityValue(questionnaire)
    return answer_set


  def _UserCanCreateAnswerSet(self, reference = 'professor'):
    """
    Use case:
        - user creates an answer set
        - that user can see it
        - that user can edit it
    """
    self.login(reference)


    # user should be able to access/view the Answer Set module
    
    number_of_answer_sets = len(self.answer_set_module.objectValues())
    
    if reference == 'spy':
      self.failIfUserCanAccessDocument(reference, self.answer_set_module)
      self.failIfUserCanViewDocument(reference, self.answer_set_module)
      self.failIfUserCanAddDocument(reference, self.answer_set_module)
      self.failIfUserCanModifyDocument(reference, self.answer_set_module)
    else:
      self.assertUserCanAccessDocument(reference, self.answer_set_module)
      self.assertUserCanViewDocument(reference, self.answer_set_module)
      self.assertUserCanAddDocument(reference, self.answer_set_module)
      if reference == 'student' :
        self.failIfUserCanModifyDocument(reference, self.answer_set_module)
      else:
        self.assertUserCanModifyDocument(reference, self.answer_set_module)
     
    # students and spies cannot add questionnaires, let's make researcher add them
    questionnaire_content='Some Questionnaire Title'
    if reference == 'researcher' or reference == 'professor':
      organisation = self._newOrganisation()
      self.assertTrue(organisation is not None)
      person = self._newPerson(organisation = organisation)
      self.assertTrue(person is not None)
      questionnaire = self._newQuestionnaire(content=questionnaire_content)
      self.assertTrue(questionnaire is not None)
      answer_set = self._newAnswerSet(person = person, questionnaire = questionnaire)
      self.assertTrue(answer_set is not None)
      self.assertUserCanAccessDocument(reference, answer_set)
      self.assertUserCanViewDocument(reference, answer_set)   
      self.assertUserCanModifyDocument(reference, answer_set)    
      self.assertUserCanAddDocument(reference, answer_set)         
    else:
      self.login('researcher')
      organisation = self._newOrganisation()
      self.assertTrue(organisation is not None)
      person = self._newPerson(organisation = organisation)
      self.assertTrue(person is not None)
      questionnaire = self._newQuestionnaire(content=questionnaire_content)
      self.assertTrue(questionnaire is not None)
      if reference == 'student':
        # A student shouldn't be able to modify someone else's answer set
        someone_elses_answer_set = self._newAnswerSet(person = person, questionnaire = questionnaire)
        self.assertTrue(someone_elses_answer_set is not None)
        self.failIfUserCanModifyDocument(reference, someone_elses_answer_set)  
        self.failIfUserCanAddDocument(reference, someone_elses_answer_set)    
        self.failIfUserCanAccessDocument(reference, someone_elses_answer_set)
        self.failIfUserCanViewDocument(reference, someone_elses_answer_set)

        # A student should be able to modify his answer sets and add answers
        self.login(reference)
        answer_set = self._newAnswerSet(person = person, questionnaire = questionnaire)
        self.assertTrue(answer_set is not None)
        self.assertUserCanModifyDocument(reference, answer_set)  
        self.assertUserCanAddDocument(reference, answer_set)    
        self.assertUserCanAccessDocument(reference, answer_set)
        self.assertUserCanViewDocument(reference, answer_set)
      else :
        answer_set = self._newAnswerSet(person = person, questionnaire = questionnaire)
        self.assertTrue(answer_set is not None)
        self.login(reference)
        self.failIfUserCanModifyDocument(reference, answer_set)  
        self.failIfUserCanAddDocument(reference, answer_set)    
        self.failIfUserCanAccessDocument(reference, answer_set)
        self.failIfUserCanViewDocument(reference, answer_set)

    # get content
    content = answer_set.objectValues()
      
    # answer_set shouldn't have any content
    self.assertEquals(len(content), 0)

    # answer_set should have content
    content = self.answer_set_module.objectValues()
    if reference == 'student':
      self.assertEquals(len(content) - number_of_answer_sets, 2)
      
      # Check that someone else's answer_set is inserted in the Answer Set module
      self.assertEquals(someone_elses_answer_set.getParentValue().getRelativeUrl(), self.answer_set_module.getRelativeUrl())
    else :
      self.assertEquals(len(content) - number_of_answer_sets, 1)

    # Check that the answer_set is inserted in the Answer Set module
    self.assertEquals(answer_set.getParentValue().getRelativeUrl(), self.answer_set_module.getRelativeUrl())

  def test_029_ProfessorCanCreateAnswerSet(self):
    self._UserCanCreateAnswerSet(reference = 'professor')

  def test_030_ResearcherCanCreateAnswerSet(self):
    self._UserCanCreateAnswerSet(reference = 'researcher')

  def test_031_StudentCanCreateAnswerSetButNotModifyOthers(self):
    self._UserCanCreateAnswerSet(reference = 'student')
 
  def test_032_SpyCannotViewAccessAnswerSet(self):
    self._UserCanCreateAnswerSet(reference = 'spy')

  def _newCorrection(self, person = None, general = True, question_list = [], grade_reduction = 1, category_correction = False, category_list = []):
    # Helper function to create a new Correction
    if category_correction:
      portal_type = 'Category Correction'
    else :
      portal_type = 'Correction'
    correction = self.correction_module.newContent( portal_type = portal_type,
                                title         = 'Some Correction Title',
                                description   = 'Some description',
                                is_general_value = general,
                                grade_reduction = grade_reduction,
                                batch_mode    = True
                              )

    if category_correction :
      correction.setCorrectionCategoryList(category_list)
      
    correction.setAggregateValueList(question_list)
    if person is not None:
      correction.setSourceValue(person)
    return correction


  def _UserCanCreateCorrection(self, reference = 'professor', category_correction = False):
    """
    Use case:
        - user creates an Correction
        - that user can see it
        - that user can edit it
    """
    self.login(reference)

    # user should be able to access/view the Correction module
    
    number_of_corrections = len(self.correction_module.objectValues())
    
    if reference == 'spy':
      self.failIfUserCanAccessDocument(reference, self.correction_module)
      self.failIfUserCanViewDocument(reference, self.correction_module)
      self.failIfUserCanAddDocument(reference, self.correction_module)
      self.failIfUserCanModifyDocument(reference, self.correction_module)
    elif reference == 'student':
      self.assertUserCanAccessDocument(reference, self.correction_module)
      self.assertUserCanViewDocument(reference, self.correction_module)
      self.failIfUserCanAddDocument(reference, self.correction_module)
      self.failIfUserCanModifyDocument(reference, self.correction_module)
    else:
      self.assertUserCanAccessDocument(reference, self.correction_module)
      self.assertUserCanViewDocument(reference, self.correction_module)
      self.assertUserCanAddDocument(reference, self.correction_module)
      self.assertUserCanModifyDocument(reference, self.correction_module)
      
    # students and spies cannot add questions, let's make researcher add them
    questionnaire_content='Some Questionnaire Title'
    if reference == 'spy' or reference == 'student':
      self.login('researcher')
    else :
      self.login(reference)
    person = self._newPerson()
    self.assertTrue(person is not None)
    
    if category_correction :
      category_list = ['Group','Function']
    else :
      category_list = []
    question_list = []
    for question_type in self._getQuestionPortalTypeList():
      question = self._newQuestion(portal_type = question_type)
      self.assertTrue(question is not None)
    correction = self._newCorrection(person = person, general = False, question_list = question_list, grade_reduction = 2, category_correction = category_correction, category_list = category_list)
    self.assertTrue(correction is not None)
    
    if reference == 'professor' or reference == 'researcher':
      self.assertUserCanAccessDocument(reference, correction)
      self.assertUserCanViewDocument(reference, correction)   
      self.assertUserCanModifyDocument(reference, correction)    
      self.assertUserCanAddDocument(reference, correction)         
    elif reference == 'student':
      self.failIfUserCanModifyDocument(reference, correction)  
      self.failIfUserCanAddDocument(reference, correction)    
      self.assertUserCanAccessDocument(reference, correction)
      self.assertUserCanViewDocument(reference, correction)
    else :
      self.failIfUserCanModifyDocument(reference, correction)  
      self.failIfUserCanAddDocument(reference, correction)    
      self.failIfUserCanAccessDocument(reference, correction)
      self.failIfUserCanViewDocument(reference, correction)

    # get content
    content = correction.objectValues()
      
    # correction shouldn't have any content
    self.assertEquals(len(content), 0)

    # correction should have content
    content = self.correction_module.objectValues()
    self.assertEquals(len(content) - number_of_corrections, 1)

    # Check that the correction is inserted in the Correction module
    self.assertEquals(correction.getParentValue().getRelativeUrl(), self.correction_module.getRelativeUrl())

  def test_033_ProfessorCanCreateCorrection(self):
    self._UserCanCreateCorrection(reference = 'professor')

  def test_034_ResearcherCanCreateCorrection(self):
    self._UserCanCreateCorrection(reference = 'researcher')

  def test_035_StudentCanViewAccessCorrection(self):
    self._UserCanCreateCorrection(reference = 'student')
 
  def test_036_SpyCannotViewAccessCorrection(self):
    self._UserCanCreateCorrection(reference = 'spy')

  def test_037_ProfessorCanCreateCategoryCorrection(self):
    self._UserCanCreateCorrection(reference = 'professor', category_correction = True)

  def test_038_ResearcherCanCreateCategoryCorrection(self):
    self._UserCanCreateCorrection(reference = 'researcher', category_correction = True)

  def test_039_StudentCanViewAccessCategoryCorrection(self):
    self._UserCanCreateCorrection(reference = 'student', category_correction = True)
 
  def test_040_SpyCannotViewAccessCategoryCorrection(self):
    self._UserCanCreateCorrection(reference = 'spy', category_correction = True)

  def _newCorrectionLine(self, parent = None, correction = None, grade_reduction = 1):
    # Helper function to create a new Correction Line
    correction_line = parent.newContent( portal_type = 'Correction Line',
                                title         = 'Some Correction Line Title',
                                comment       = 'Some comment',
                                grade_reduction = grade_reduction,
                                batch_mode    = True
                              )
    if correction is not None:
      correction_line.setSourceValue(correction)
    return correction_line

  def _newAnswer(self, answer_set = None, question = None, value_type    = 'string_value', no_answer_reason = 'do_not_know', boolean_value = 1, float_value   = 10.0, integer_value = 35, string_value  = 'string_value', list_value = ['value1','value2'], text_value = 'text_value'):
    # Helper function to create a new Correction Line
    answer = answer_set.newContent( portal_type = 'Answer',
                                title         = 'Some Answer Title',
                                comment       = 'Some comment',
                                value_type    = value_type,
                                no_answer_reason = no_answer_reason,
                                boolean_value = boolean_value,
                                float_value   = float_value,
                                integer_value = integer_value,
                                string_value  = string_value,
                                list_value    = list_value,
                                text_value    = text_value,
                                batch_mode    = True
                              )
    if question is not None:
      answer.setResourceValue(question)
    return answer

  def _UserCanCreateAnswerSetContent(self, reference = 'professor', portal_type = 'Correction Line'):
    """
    Use case:
        - user creates an Correction Line or an Answer
        - that user can see it
        - that user can edit it
    """
    self.login(reference)

    # students and spies cannot add questionnaire, corrections, let's make researcher add them
    questionnaire_content='Some Questionnaire Title'
    if reference == 'spy' or reference == 'student':
      self.login('researcher')
    else :
      self.login(reference)
    person = self._newPerson()
    self.assertTrue(person is not None)
    correction = self._newCorrection(person = person, general = False, grade_reduction = 2)
    self.assertTrue(correction is not None)
    organisation = self._newOrganisation()
    self.assertTrue(organisation is not None)
    person = self._newPerson(organisation = organisation)
    self.assertTrue(person is not None)
    questionnaire = self._newQuestionnaire(content=questionnaire_content)
    self.assertTrue(questionnaire is not None)
    if portal_type == 'Answer' :
      question = self._newQuestion()
      self.assertTrue(question is not None)

    if reference == 'student':
      self.login(reference)
    answer_set = self._newAnswerSet(person = person, questionnaire = questionnaire)
    self.assertTrue(answer_set is not None)

    if portal_type == 'Answer':
      answer_set_content = self._newAnswer(answer_set = answer_set, question = question)
      self.assertTrue(answer_set_content is not None)
      if reference == 'professor' or reference == 'researcher':
        self.assertUserCanAccessDocument(reference, answer_set_content)
        self.assertUserCanViewDocument(reference, answer_set_content)   
        self.assertUserCanModifyDocument(reference, answer_set_content)
        self.assertUserCanAddDocument(reference, answer_set_content)     
      elif reference == 'student':
        self.assertUserCanModifyDocument(reference, answer_set_content)  
        self.assertUserCanAccessDocument(reference, answer_set_content)
        self.assertUserCanViewDocument(reference, answer_set_content)
        self.failIfUserCanAddDocument(reference, answer_set_content) 
      else :
        self.failIfUserCanModifyDocument(reference, answer_set_content)  
        self.failIfUserCanAccessDocument(reference, answer_set_content)
        self.failIfUserCanViewDocument(reference, answer_set_content)
        self.failIfUserCanAddDocument(reference, answer_set_content) 
    else:
      if reference == 'student':
        self.login('researcher')
      answer_set_content = self._newCorrectionLine(parent = answer_set, correction = correction, grade_reduction = 2)
      self.assertTrue(answer_set_content is not None)
      if reference == 'professor' or reference == 'researcher':
        self.assertUserCanAccessDocument(reference, answer_set_content)
        self.assertUserCanViewDocument(reference, answer_set_content)   
        self.assertUserCanModifyDocument(reference, answer_set_content)    
      elif reference == 'student':
        self.failIfUserCanModifyDocument(reference, answer_set_content)  
        self.assertUserCanAccessDocument(reference, answer_set_content)
        self.assertUserCanViewDocument(reference, answer_set_content)
      else :
        self.failIfUserCanModifyDocument(reference, answer_set_content)  
        self.failIfUserCanAccessDocument(reference, answer_set_content)
        self.failIfUserCanViewDocument(reference, answer_set_content)

    # get content
    content = answer_set_content.objectValues()
      
    # answer_set_content shouldn't have any content
    self.assertEquals(len(content), 0)

    # answer_set should have content
    content = answer_set.objectValues()
    self.assertEquals(len(content), 1)

    # Check that the answer_set_content is inserted in the answer_set
    self.assertEquals(answer_set_content.getParentValue().getRelativeUrl(), answer_set.getRelativeUrl())

  def test_041_ProfessorCanCreateCorrectionLine(self):
    self._UserCanCreateAnswerSetContent(reference = 'professor')

  def test_042_ResearcherCanCreateCorrectionLine(self):
    self._UserCanCreateAnswerSetContent(reference = 'researcher')

  def test_043_StudentCanViewAccessCorrectionLine(self):
    self._UserCanCreateAnswerSetContent(reference = 'student')
 
  def test_044_SpyCannotViewAccessCorrectionLine(self):
    self._UserCanCreateAnswerSetContent(reference = 'spy')

  def test_045_ProfessorCanCreateAnswer(self):
    self._UserCanCreateAnswerSetContent(reference = 'professor', portal_type = 'Answer')

  def test_046_ResearcherCanCreateAnswer(self):
    self._UserCanCreateAnswerSetContent(reference = 'researcher', portal_type = 'Answer')

  def test_047_StudentCanViewAccessModifyAnswer(self):
    self._UserCanCreateAnswerSetContent(reference = 'student', portal_type = 'Answer')
 
  def test_048_SpyCannotViewAccessAnswer(self):
    self._UserCanCreateAnswerSetContent(reference = 'spy', portal_type = 'Answer')

  def _UserCanCreateAnswerCorrectionLine(self, reference = 'professor'):
    """
    Use case:
        - user creates an Correction Line in Answers
        - that user can see it
        - that user can edit it
    """
    self.login(reference)

    # students and spies cannot add questionnaire, corrections, let's make researcher add them
    questionnaire_content='Some Questionnaire Title'
    if reference == 'spy' or reference == 'student':
      self.login('researcher')
    else :
      self.login(reference)
    person = self._newPerson()
    self.assertTrue(person is not None)
    correction = self._newCorrection(person = person, general = False, grade_reduction = 2)
    self.assertTrue(correction is not None)
    organisation = self._newOrganisation()
    self.assertTrue(organisation is not None)
    person = self._newPerson(organisation = organisation)
    self.assertTrue(person is not None)
    questionnaire = self._newQuestionnaire(content=questionnaire_content)
    self.assertTrue(questionnaire is not None)
    if portal_type == 'Answer' :
      question = self._newQuestion()
      self.assertTrue(question is not None)

    if reference == 'student':
      self.login(reference)
    answer_set = self._newAnswerSet(person = person, questionnaire = questionnaire)
    self.assertTrue(answer_set is not None)

    if reference == 'student':
      self.login('researcher')

    answer_set_content = self._newAnswer(answer_set = answer_set, question = question)
    self.assertTrue(answer_set_content is not None)
 
    correction_line = self._newCorrectionLine(parent = answer, correction = correction, grade_reduction = 2)
    self.assertTrue(correction_line is not None)
 
    if reference == 'professor' or reference == 'researcher':
      self.assertUserCanAccessDocument(reference, correction_line)
      self.assertUserCanViewDocument(reference, correction_line)   
      self.assertUserCanModifyDocument(reference, correction_line)    
    elif reference == 'student':
      self.failIfUserCanModifyDocument(reference, correction_line)  
      self.assertUserCanAccessDocument(reference, correction_line)
      self.assertUserCanViewDocument(reference, correction_line)
    else :
      self.failIfUserCanModifyDocument(reference, correction_line)  
      self.failIfUserCanAccessDocument(reference, correction_line)
      self.failIfUserCanViewDocument(reference, correction_line)

    # get content
    content = correction_line.objectValues()
      
    # correction_line shouldn't have any content
    self.assertEquals(len(content), 0)

    # answer should have content
    content = answer.objectValues()
    self.assertEquals(len(content), 1)

    # Check that the correction_line is inserted in the answer
    self.assertEquals(correction_line.getParentValue().getRelativeUrl(), answer.getRelativeUrl())

  def test_049_ProfessorCanCreateCorrectionLine(self):
    self._UserCanCreateAnswerSetContent(reference = 'professor')

  def test_050_ResearcherCanCreateCorrectionLine(self):
    self._UserCanCreateAnswerSetContent(reference = 'researcher')

  def test_051_StudentCanViewAccessCorrectionLine(self):
    self._UserCanCreateAnswerSetContent(reference = 'student')
 
  def test_052_SpyCannotViewAccessCorrectionLine(self):
    self._UserCanCreateAnswerSetContent(reference = 'spy')

  def _executeAnswerSetTransition(self, answer_set = None, transition = 'submit_action'):
    if transition == 'submit_action':
      answer_set.submit()
    elif transition == 'archive_action':
      answer_set.archive()
    elif transition == 'delete_action':
      answer_set.delete()
    elif transition == 'release_action':
      answer_set.release()
    else:
      answer_set.request()

  def _setValidationState(self, answer_set = None, validation_state = 'draft'):
    if validation_state in ['submitted', 'released', 'archived','requested']:
      self.login('student')
      answer_set.submit()
      if validation_state == 'archived':
        self.login('professor')
        answer_set.archive()
      elif validation_state == 'released':
        self.login('professor')
        answer_set.release()
      elif validation_state == 'requested':
        self.login('professor')
        answer_set.request()
    elif validation_state == 'deleted':
      self.login('professor')
      answer_set.delete()
    
  def _UserCanPassWorkflowTransition(self, reference = 'student', transition_capability = True, transition = 'submit_action', initial_validation_state = 'draft', add_capability = False, modify_capability = False):
    """
    Use case:
        - student creates an answer set (professor and researcher are not supposed to be able to submit)
        - we change the answer set validation state to initial_validation_state
        - we check if the user can view, modify, add in the current state
        - user tries to pass the transition 'transition'
    """

    self.login('student')
    answer_set = self._newAnswerSet()
    self._setValidationState(answer_set = answer_set, validation_state = initial_validation_state)

    self.login(reference)
    if transition_capability:
      self.assertUserCanPassWorkflowTransition(reference, transition, answer_set)
      self._executeAnswerSetTransition(answer_set = answer_set, transition = transition)
    else: 
      self.failIfUserCanPassWorkflowTransition(reference, transition, answer_set)
      if transition == 'submit_action':
        self.login('student')
      else:
        self.login('professor')
      self._executeAnswerSetTransition(answer_set = answer_set, transition = transition)
    
    if reference == 'spy':
      self.failIfUserCanAccessDocument(reference, answer_set)
      self.failIfUserCanViewDocument(reference, answer_set)
      self.failIfUserCanAddDocument(reference, answer_set)
      self.failIfUserCanModifyDocument(reference, answer_set)
    else:
      if not (reference == 'student' and transition == 'delete_action'):
        self.assertUserCanAccessDocument(reference, answer_set)
        self.assertUserCanViewDocument(reference, answer_set)
      if modify_capability:
        self.assertUserCanModifyDocument(reference, answer_set)
      else: 
        self.failIfUserCanModifyDocument(reference, answer_set)
      if add_capability:
        self.assertUserCanAddDocument(reference, answer_set)
      else: 
        self.failIfUserCanAddDocument(reference, answer_set)
       
  def test_053_ProfessorCanSubmitFromDraft(self):
    self._UserCanPassWorkflowTransition(reference = 'professor', transition_capability = True, add_capability = True, modify_capability = True)

  def test_054_ResearcherCanSubmitFromDraft(self):
    self._UserCanPassWorkflowTransition(reference = 'researcher', transition_capability = True, add_capability = True, modify_capability = True)

  def test_055_StudentCanSubmitFromDraft(self):
    self._UserCanPassWorkflowTransition()

  def test_056_SpyCannotSubmitFromDraft(self):
    self._UserCanPassWorkflowTransition(reference = 'spy', transition_capability = False)

  def test_057_ProfessorCanDelete(self):
    self._UserCanPassWorkflowTransition(reference = 'professor', transition = 'delete_action')

  def test_058_ResearcherCanDelete(self):
    self._UserCanPassWorkflowTransition(reference = 'researcher', transition = 'delete_action')

  def test_059_StudentCannotDelete(self):
    self._UserCanPassWorkflowTransition(transition = 'delete_action', transition_capability = False)

  def test_060_SpyCannotDelete(self):
    self._UserCanPassWorkflowTransition(reference = 'spy', transition = 'delete_action', transition_capability = False)

  def test_061_ProfessorCanRequest(self):
    self._UserCanPassWorkflowTransition(reference = 'professor', transition = 'request_action', initial_validation_state = 'submitted', add_capability = True, modify_capability = True)

  def test_062_ResearcherCanRequest(self):
    self._UserCanPassWorkflowTransition(reference = 'researcher', transition = 'request_action', initial_validation_state = 'submitted', add_capability = True, modify_capability = True)

  def test_063_StudentCannotRequest(self):
    self._UserCanPassWorkflowTransition(transition = 'request_action', initial_validation_state = 'submitted', transition_capability = False, modify_capability = True, add_capability = True)

  def test_064_SpyCannotRequest(self):
    self._UserCanPassWorkflowTransition(reference = 'spy', transition = 'request_action', initial_validation_state = 'submitted', transition_capability = False)

  def test_065_ProfessorCanArchive(self):
    self._UserCanPassWorkflowTransition(reference = 'professor', transition = 'archive_action', initial_validation_state = 'submitted', modify_capability = True)

  def test_066_ResearcherCanArchive(self):
    self._UserCanPassWorkflowTransition(reference = 'researcher', transition = 'archive_action', initial_validation_state = 'submitted', modify_capability = True)

  def test_067_StudentCannotArchive(self):
    self._UserCanPassWorkflowTransition(transition = 'archive_action', initial_validation_state = 'submitted', transition_capability = False)

  def test_068_SpyCannotArchive(self):
    self._UserCanPassWorkflowTransition(reference = 'spy', transition = 'archive_action', initial_validation_state = 'submitted', transition_capability = False)

  def test_069_ProfessorCanDeleteFromArchive(self):
    self._UserCanPassWorkflowTransition(reference = 'professor', transition = 'delete_action', initial_validation_state = 'archived')

  def test_070_ResearcherCanDeleteFromArchive(self):
    self._UserCanPassWorkflowTransition(reference = 'researcher', transition = 'delete_action', initial_validation_state = 'archived')

  def test_071_StudentCannotDeleteFromArchive(self):
    self._UserCanPassWorkflowTransition(transition = 'delete_action', transition_capability = False, initial_validation_state = 'archived')

  def test_072_SpyCannotDeleteFromArchive(self):
    self._UserCanPassWorkflowTransition(reference = 'spy', transition = 'delete_action', transition_capability = False, initial_validation_state = 'archived')

  def test_073_ProfessorCanRelease(self):
    self._UserCanPassWorkflowTransition(reference = 'professor', transition = 'release_action', initial_validation_state = 'submitted')

  def test_074_ResearcherCanRelease(self):
    self._UserCanPassWorkflowTransition(reference = 'researcher', transition = 'release_action', initial_validation_state = 'submitted')

  def test_075_StudentCannotRelease(self):
    self._UserCanPassWorkflowTransition(transition = 'release_action', transition_capability = False, initial_validation_state = 'submitted')

  def test_076_SpyCannotRelease(self):
    self._UserCanPassWorkflowTransition(reference = 'spy', transition = 'release_action', transition_capability = False, initial_validation_state = 'submitted')

  def test_077_ProfessorCanRequestFromRelease(self):
    self._UserCanPassWorkflowTransition(reference = 'professor', transition = 'request_action', initial_validation_state = 'released', add_capability = True, modify_capability = True)

  def test_078_ResearcherCanRequestFromRelease(self):
    self._UserCanPassWorkflowTransition(reference = 'researcher', transition = 'request_action', initial_validation_state = 'released', add_capability = True, modify_capability = True)

  def test_079_StudentCannotRequestFromRelease(self):
    self._UserCanPassWorkflowTransition(transition = 'request_action', transition_capability = False, initial_validation_state = 'released', add_capability = True, modify_capability = True)

  def test_080_SpyCannotRequestFromRelease(self):
    self._UserCanPassWorkflowTransition(reference = 'spy', transition = 'request_action', transition_capability = False, initial_validation_state = 'released')

  def test_081_ProfessorCanSubmitFromRequest(self):
    self._UserCanPassWorkflowTransition(reference = 'professor', transition_capability = True, initial_validation_state = 'requested', add_capability = True, modify_capability = True)

  def test_082_ResearcherCanSubmitFromRequest(self):
    self._UserCanPassWorkflowTransition(reference = 'researcher', transition_capability = True, initial_validation_state = 'requested', add_capability = True, modify_capability = True)

  def test_083_StudentCanSubmitFromRequest(self):
    self._UserCanPassWorkflowTransition(initial_validation_state = 'requested')

  def test_084_SpyCannotSubmitFromRequest(self):
    self._UserCanPassWorkflowTransition(reference = 'spy', transition_capability = False, initial_validation_state = 'requested')

  def _newCategory(self, parent, portal_type = 'Category', id = 'standard_category', title = ''):
    if title == '':
      title = 'Some ' + portal_type + ' Title'
    if portal_type == 'Category':
      category = parent.newContent(portal_type= portal_type,
                                id          = id,
                                title       = title,
                                short_title = 'Some Short Title',
                                description = 'Some Description',
                                reference   = 'Some Reference',
                                codification= 'code',
                                int_index   =  10,
                                batch_mode  = True
                              )
    else:
      category = parent.newContent(portal_type = portal_type,
                                id          =  id,
                                title       = title,
                                description = 'Some Description',
                                acquisition_object_id_list = ['some_acquisition_object_id'],
                                acquisition_base_category_list = ['some_acquisition_base_category'],
                                acquisition_portal_type_list  = 'python:["some_acquisition_portal_type"]',
                                fallback_base_category_list  = ['some_fallback_base_category'],
                                acquisition_copy_value = True,
                                acquisition_mask_value = True,
                                acquisition_append_value = True,
                                category_type_list = ['line'],
                                batch_mode  = True
                              )
    return category

  def _UserCanCreateCategory(self, reference = 'professor', child_category = False, access_capability = True, add_capability = False):
    """
    Use case:
        - user creates a Category or a Base Category in Standard Category Module
        - that user can see it
        - that user can edit it
    """

    if reference != 'spy':
      self.login(reference)
    else:
      self.login('student')
    answer_set = self._newAnswerSet()
    self.assertTrue(answer_set is not None)

    if reference in ['spy','student']:
      self.login('researcher')

    parent = self.standard_category_module

    category = self._newCategory(parent, portal_type = 'Base Category')
 
    if child_category:
      category = self._newCategory(category, portal_type = 'Category')

    if access_capability:
      self.assertUserCanAccessDocument(reference, category)
      self.assertUserCanViewDocument(reference, category)
      if add_capability:
        self.assertUserCanAddDocument(reference, category)
        self.assertUserCanModifyDocument(reference, category)
      else:
        self.failIfUserCanAddDocument(reference, category)
        self.failIfUserCanModifyDocument(reference, category)
    else:
      self.failIfUserCanAccessDocument(reference, category)
      self.failIfUserCanViewDocument(reference, category)
      self.failIfUserCanAddDocument(reference, category)
      self.failIfUserCanModifyDocument(reference, category)
        
  def test_085_ProfessorCanAddModifyStandardBaseCategory(self):
    self._UserCanCreateCategory( add_capability = True)

  def test_086_ResearcherCanAddModifyStandardBaseCategory(self):
    self._UserCanCreateCategory(reference = 'researcher', add_capability = True)

  def test_087_StudentCanViewStandardBaseCategory(self):
    self._UserCanCreateCategory(reference = 'student')

  def test_088_SpyCannotViewStandardBaseCategory(self):
    self._UserCanCreateCategory(reference = 'spy', access_capability = False)

  def test_089_ProfessorCanAddModifyStandardBaseCategory(self):
    self._UserCanCreateCategory(child_category = True, add_capability = True)

  def test_090_ResearcherCanAddModifyStandardBaseCategory(self):
    self._UserCanCreateCategory(reference = 'researcher', child_category = True, add_capability = True)

  def test_091_StudentCanViewStandardBaseCategory(self):
    self._UserCanCreateCategory(reference = 'student', child_category = True)

  def test_092_SpyCannotViewStandardBaseCategory(self):
    self._UserCanCreateCategory(reference = 'spy', access_capability = False, child_category = True)

  def _executeQuestionnaireTransition(self, questionnaire, transition = 'delete_action'):
    if transition == 'delete_action':
      questionnaire.delete()
    elif transition == 'validate_action':
      questionnaire.validate()
    else:
      questionnaire.update()

  def _setQuestionnaireValidationState(self, questionnaire, validation_state = 'draft'):
    if validation_state == 'deleted':
      questionnaire.delete()
    elif validation_state == 'validated':
      questionnaire.validate()
    
  def _UserCanPassQuestionnaireWorkflowTransition(self, reference = 'student', transition_capability = True, transition = 'validate_action', initial_validation_state = 'draft', add_capability = False, modify_capability = False):
    """
    Use case:
        - A questionnaire is created
        - we change the questionnaire validation state to initial_validation_state
        - we check if the user can view, modify, add in the current state
        - user tries to pass the transition 'transition'
    """

    if reference in ['researcher','professor']:
      self.login(reference)
    else:
      self.login('researcher')

    questionnaire = self._newQuestionnaire()
    self._setQuestionnaireValidationState(questionnaire, validation_state = initial_validation_state)

    if transition_capability:
      self.assertUserCanPassWorkflowTransition(reference, transition, questionnaire)
      self.login(reference)
      self._executeQuestionnaireTransition(questionnaire, transition)
    else: 
      self.failIfUserCanPassWorkflowTransition(reference, transition, questionnaire)
      self.login('researcher')
      self._executeQuestionnaireTransition(questionnaire, transition)
    
    if reference == 'spy':
      self.failIfUserCanAccessDocument(reference, questionnaire)
      self.failIfUserCanViewDocument(reference, questionnaire)
      self.failIfUserCanAddDocument(reference, questionnaire)
      self.failIfUserCanModifyDocument(reference, questionnaire)
    elif transition != 'delete_action':
      self.assertUserCanAccessDocument(reference, questionnaire)
      self.assertUserCanViewDocument(reference, questionnaire)
      if modify_capability:
        self.assertUserCanModifyDocument(reference, questionnaire)
      else: 
        self.failIfUserCanModifyDocument(reference, questionnaire)
      if add_capability:
        self.assertUserCanAddDocument(reference, questionnaire)
      else: 
        self.failIfUserCanAddDocument(reference, questionnaire)
       
  def test_093_ProfessorCanValidateQuestionnaire(self):
    self._UserCanPassQuestionnaireWorkflowTransition(reference = 'professor')

  def test_094_ResearcherCanValidateQuestionnaire(self):
    self._UserCanPassQuestionnaireWorkflowTransition(reference = 'researcher')

  def test_095_StudentCannotValidateQuestionnaire(self):
    self._UserCanPassQuestionnaireWorkflowTransition(transition_capability = False)

  def test_096_SpyCannotValidateQuestionnaire(self):
    self._UserCanPassQuestionnaireWorkflowTransition(reference = 'spy', transition_capability = False)

  def test_097_ProfessorCanDeleteQuestionnaireFromDraft(self):
    self._UserCanPassQuestionnaireWorkflowTransition(reference = 'professor', transition = 'delete_action')

  def test_098_ResearcherCanDeleteQuestionnaireFromDraft(self):
    self._UserCanPassQuestionnaireWorkflowTransition(reference = 'researcher', transition = 'delete_action')

  def test_099_StudentCannotDeleteQuestionnaireFromDraft(self):
    self._UserCanPassQuestionnaireWorkflowTransition(transition = 'delete_action', transition_capability = False)

  def test_100_SpyCannotDeleteQuestionnaireFromDraft(self):
    self._UserCanPassQuestionnaireWorkflowTransition(reference = 'spy', transition = 'delete_action', transition_capability = False)

  def test_101_ProfessorCanUpdateQuestionnaire(self):
    self._UserCanPassQuestionnaireWorkflowTransition(reference = 'professor', transition = 'update_action', initial_validation_state = 'validated', add_capability = True, modify_capability = True)

  def test_102_ResearcherCanUpdateQuestionnaire(self):
    self._UserCanPassQuestionnaireWorkflowTransition(reference = 'researcher', transition = 'update_action', initial_validation_state = 'validated', add_capability = True, modify_capability = True)

  def test_103_StudentCannotUpdateQuestionnaire(self):
    self._UserCanPassQuestionnaireWorkflowTransition(transition = 'update_action', initial_validation_state = 'validated', transition_capability = False)

  def test_104_SpyCannotUpdateQuestionnaire(self):
    self._UserCanPassQuestionnaireWorkflowTransition(reference = 'spy', transition = 'update_action', initial_validation_state = 'validated', transition_capability = False)

  def test_105_ProfessorCanDeleteQuestionnaireFromValidated(self):
    self._UserCanPassQuestionnaireWorkflowTransition(reference = 'professor', transition = 'delete_action', initial_validation_state = 'validated')

  def test_106_ResearcherCanDeleteQuestionnaireFromValidated(self):
    self._UserCanPassQuestionnaireWorkflowTransition(reference = 'researcher', transition = 'delete_action', initial_validation_state = 'validated')

  def test_107_StudentCannotDeleteQuestionnaireFromValidated(self):
    self._UserCanPassQuestionnaireWorkflowTransition(transition = 'archive_action', initial_validation_state = 'validated', transition_capability = False)

  def test_108_SpyCannotDeleteQuestionnaireFromValidated(self):
    self._UserCanPassQuestionnaireWorkflowTransition(reference = 'spy', transition = 'delete_action', initial_validation_state = 'validated', transition_capability = False)

  def _UserCanViewPerson(self, reference = 'professor', access_capability = True):
    """
    Use case:
        - user logs into questionnaire system
        - user can / cannot view / access Person Module / Person
    """
    self.login(reference)

    # user should be able to access/view the person module
    if access_capability:
      self.assertUserCanAccessDocument(reference, self.person_module)
      self.assertUserCanViewDocument(reference, self.person_module)
    # user should not be able to access/view the person module
    else :
      self.failIfUserCanAccessDocument(reference, self.person_module)
      self.failIfUserCanViewDocument(reference, self.person_module)

    # students and spies cannot add person, let's make researcher add them
    self.login('researcher')
    person = self._newPerson()
    self.login(reference)    
      
    self.assertTrue(person is not None)

    # user should be able to access/view the created person
    if access_capability:
      self.assertUserCanViewDocument(reference, person)
      self.assertUserCanAccessDocument(reference, person)
    # user should not be able to access/view the created person
    else:
      self.failIfUserCanViewDocument(reference, person)
      self.failIfUserCanAccessDocument(reference, person)
      
    # Check that the person is inserted in the person module
    self.assertEquals(person.getParentValue().getRelativeUrl(), self.person_module.getRelativeUrl())
      
    # the person should be in draft state
    self.assertEquals(person.getValidationState(), 'draft')

    
  def test_109_StudentCannotViewPerson(self):
    self._UserCanViewPerson(reference = 'student', access_capability = False)
 
  def test_110_SpyCannotViewPerson(self):
    self._UserCanViewPerson(reference = 'spy', access_capability = False)
    
  def test_111_ResearcherCanViewPerson(self):
    self._UserCanViewPerson(reference = 'researcher', access_capability = True)
 
  def test_112_ProfessorCanViewPerson(self):
    self._UserCanViewPerson(reference = 'professor', access_capability = True)
    
  def _UserCanViewOrganisation(self, reference = 'researcher', access_capability = True):
    """
    Use case:
        - user logs into questionnaire system
        - user can /cannot view / access Organisati Module / Organisation
    """
    self.login(reference)

    # user should be able to access/view the organisation module
    if access_capability:
      self.assertUserCanAccessDocument(reference, self.organisation_module)
      self.assertUserCanViewDocument(reference, self.organisation_module)
    # user should not be able to access/view the organisation module
    else :
      self.failIfUserCanAccessDocument(reference, self.organisation_module)
      self.failIfUserCanViewDocument(reference, self.organisation_module)

    # students and spies cannot add organisation, let's make researcher add them
    self.login('researcher')
    organisation = self._newOrganisation()
    self.login(reference)    
      
    self.assertTrue(organisation is not None)

    # user should be able to access/view the created organisation
    if access_capability:
      self.assertUserCanViewDocument(reference, organisation)
      self.assertUserCanAccessDocument(reference, organisation)
    # user should not be able to access/view the created organisation
    else:
      self.failIfUserCanViewDocument(reference, organisation)
      self.failIfUserCanAccessDocument(reference, organisation)
      
    # Check that the organisation is inserted in the organisation module
    self.assertEquals(organisation.getParentValue().getRelativeUrl(), self.organisation_module.getRelativeUrl())
      
    # the organsiation should be in draft state
    self.assertEquals(organisation.getValidationState(), 'draft')

  def test_113_StudentCannotViewOrganisation(self):
    self. _UserCanViewOrganisation(reference = 'student', access_capability = False)
    
  def test_114_SpyCanntoViewOrganisation(self):
    self. _UserCanViewOrganisation(reference = 'spy', access_capability = False)

  def test_115_ResearcherCanViewOrganisation(self):
    self. _UserCanViewOrganisation(reference = 'researcher', access_capability = True)
    
  def test_116_ProfessorCanViewOrganisation(self):
    self. _UserCanViewOrganisation(reference = 'professor', access_capability = True)
