from euphorie.client.tests.database import DatabaseTests
from euphorie.client import model
from euphorie.client import navigation
from z3c.saconfig import Session
import unittest

def createSurvey():
    session=Session()
    account=model.Account(loginname=u"jane", password=u"secret")
    session.add(account)
    survey=model.SurveySession(title=u"Session", zodb_path="survey", account=account)
    session.add(survey)
    return (session, survey)



class MockRequest:
    def __init__(self, agent=None):
        self.__headers={}
        if agent is not None:
            self.__headers["User-Agent"]=agent
    def get_header(self, key, default):
        return self.__headers.get(key, default)



class FindNextQuestionTests(DatabaseTests):
    def testSingleQuestion(self):
        (session, survey)=createSurvey()
        child=model.Risk(title=u"Risk", risk_id="1", zodb_path="1")
        survey.addChild(child)
        self.failUnless(navigation.FindNextQuestion(child, survey) is None)

    def testQuestionAtSameModule(self):
        (session, survey)=createSurvey()
        session.add(survey)
        child=model.Risk(title=u"Risk", risk_id="1", zodb_path="1")
        survey.addChild(child)
        sister=model.Risk(title=u"Risk", risk_id="2", zodb_path="1")
        survey.addChild(sister)
        self.failUnless(navigation.FindNextQuestion(child, survey) is sister)

    def testQuestionIsNextModule(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1")
        survey.addChild(mod1)
        q1=model.Risk(title=u"Risk 1", risk_id="1", zodb_path="1/2")
        mod1.addChild(q1)
        mod2=model.Module(title=u"Module 2", module_id="2", zodb_path="2")
        survey.addChild(mod2)
        self.failUnless(navigation.FindNextQuestion(q1, survey) is mod2)

    def testSkipChildren(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1", skip_children=True)
        survey.addChild(mod1)
        q1=model.Risk(title=u"Risk 1", risk_id="1", zodb_path="1/1")
        mod1.addChild(q1)
        mod2=model.Module(title=u"Module 2", module_id="2", zodb_path="2")
        survey.addChild(mod2)
        self.failUnless(navigation.FindNextQuestion(mod1, survey) is mod2)




class FindPreviousQuestionTests(DatabaseTests):
    def testSingleQuestion(self):
        (session, survey)=createSurvey()
        child=model.Risk(title=u"Risk", risk_id="1", zodb_path="1")
        survey.addChild(child)
        self.failUnless(navigation.FindPreviousQuestion(child, survey) is None)

    def testQuestionAtSameModule(self):
        (session, survey)=createSurvey()
        child=model.Risk(title=u"Risk 1", risk_id="1", zodb_path="1")
        survey.addChild(child)
        sister=model.Risk(title=u"Risk 2", risk_id="2", zodb_path="2")
        survey.addChild(sister)
        self.failUnless(navigation.FindPreviousQuestion(sister, survey) is child)

    def testQuestionAtPreviousModule(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1")
        survey.addChild(mod1)
        q1=model.Risk(title=u"Risk 1", risk_id="1", zodb_path="1/1")
        mod1.addChild(q1)
        mod2=model.Module(title=u"Module 2", module_id="2", zodb_path="2")
        survey.addChild(mod2)
        self.failUnless(navigation.FindPreviousQuestion(mod2, survey) is q1)

    def testQuestionAtPreviousModuleWithSkippedChildren(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1", skip_children=True)
        survey.addChild(mod1)
        q1=model.Risk(title=u"Risk 1", risk_id="1", zodb_path="1/1")
        mod1.addChild(q1)
        mod2=model.Module(title=u"Module 2", module_id="2", zodb_path="2")
        survey.addChild(mod2)
        self.failUnless(navigation.FindPreviousQuestion(mod2, survey) is mod1)



class IdentificationNavigationTests(DatabaseTests):
    """Test if the filter determining which modules and risks to show during
    the identification phase are correct.
    """
    def filter(self):
        from euphorie.client.risk import IdentificationView
        return IdentificationView.question_filter

    def testShowRisk(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1", skip_children=False)
        survey.addChild(mod1)
        q11=model.Risk(title=u"Risk 1.1", risk_id="1", zodb_path="1/1")
        mod1.addChild(q11)
        self.failUnless(navigation.FindNextQuestion(mod1, survey, self.filter()) is q11)

    def testSkipTop5Risk(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1", skip_children=False)
        survey.addChild(mod1)
        q11=model.Risk(title=u"Risk 1.1", risk_id="1", zodb_path="1/1", risk_type="top5")
        mod1.addChild(q11)
        self.assertEqual(navigation.FindNextQuestion(mod1, survey, self.filter()), None)



class EvaluationNavigationTests(DatabaseTests):
    """Test if the filter determining which modules and risks to show during
    the evaluation phase are correct.
    """
    def filter(self):
        from euphorie.client.risk import EvaluationView
        return EvaluationView.question_filter

    def testSkipModuleWithoutRisks(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1", skip_children=False)
        survey.addChild(mod1)
        mod11=model.Module(title=u"Module 1.1", module_id="11", zodb_path="1/1", skip_children=False)
        mod1.addChild(mod11)
        self.assertEqual(navigation.FindNextQuestion(mod1, survey, self.filter()), None)

    def testSkipModuleIfNoRisksPresent(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1", skip_children=False)
        survey.addChild(mod1)
        mod11=model.Module(title=u"Module 1.1", module_id="11", zodb_path="1/1", skip_children=False)
        mod1.addChild(mod11)
        q111=model.Risk(title=u"Risk 1.1.1", risk_id="1", zodb_path="1/1/1", identification="yes")
        mod11.addChild(q111)
        self.assertEqual(navigation.FindNextQuestion(mod1, survey, self.filter()), None)

    def testShowModuleWithPresentRisk(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1", skip_children=False)
        survey.addChild(mod1)
        mod11=model.Module(title=u"Module 1.1", module_id="11", zodb_path="1/1", skip_children=False)
        mod1.addChild(mod11)
        q111=model.Risk(title=u"Risk 1.1.1", risk_id="1", zodb_path="1/1/1", identification="no")
        mod11.addChild(q111)
        self.failUnless(navigation.FindNextQuestion(mod1, survey, self.filter()) is mod11)

    def testSkipModuleWithPresentTop5Risk(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1", skip_children=False)
        survey.addChild(mod1)
        mod11=model.Module(title=u"Module 1.1", module_id="11", zodb_path="1/1", skip_children=False)
        mod1.addChild(mod11)
        q111=model.Risk(title=u"Risk 1.1.1", risk_id="1", zodb_path="1/1/1", risk_type="top5", identification="no")
        mod11.addChild(q111)
        self.assertEqual(navigation.FindNextQuestion(mod1, survey, self.filter()), None)

    def testSkipModuleWithPresentPolicyRisk(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1", skip_children=False)
        survey.addChild(mod1)
        mod11=model.Module(title=u"Module 1.1", module_id="11", zodb_path="1/1", skip_children=False)
        mod1.addChild(mod11)
        q111=model.Risk(title=u"Risk 1.1.1", risk_id="1", zodb_path="1/1/1", risk_type="policy", identification="no")
        mod11.addChild(q111)
        self.assertEqual(navigation.FindNextQuestion(mod1, survey, self.filter()), None)

    def testSkipRisksIfNotPresent(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1", skip_children=False)
        survey.addChild(mod1)
        q11=model.Risk(title=u"Risk 1.1", risk_id="1", zodb_path="1/1", identification="yes")
        mod1.addChild(q11)
        self.assertEqual(navigation.FindNextQuestion(mod1, survey, self.filter()), None)

    def testShowRisksIfPresent(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1", skip_children=False)
        survey.addChild(mod1)
        q11=model.Risk(title=u"Risk 1.1", risk_id="1", zodb_path="1/1", identification="no")
        mod1.addChild(q11)
        self.failUnless(navigation.FindNextQuestion(mod1, survey, self.filter()) is q11)

    def testSkipRisksIfPresentTop5(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1", skip_children=False)
        survey.addChild(mod1)
        q11=model.Risk(title=u"Risk 1.1", risk_id="1", zodb_path="1/1", risk_type="top5", identification="no")
        mod1.addChild(q11)
        self.assertEqual(navigation.FindNextQuestion(mod1, survey, self.filter()), None)

    def testSkipRisksIfPresentPolicyType(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1", skip_children=False)
        survey.addChild(mod1)
        q11=model.Risk(title=u"Risk 1.1", risk_id="1", zodb_path="1/1", risk_type="policy", identification="no")
        mod1.addChild(q11)
        self.assertEqual(navigation.FindNextQuestion(mod1, survey, self.filter()), None)



class ActionPlanNavigationTests(DatabaseTests):
    """Test if the filter determining which modules and risks to show during
    the action plan phase are correct.
    """
    def filter(self):
        from euphorie.client.risk import ActionPlanView
        return ActionPlanView.question_filter

    def testSkipModuleWithoutRisks(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1", skip_children=False)
        survey.addChild(mod1)
        mod11=model.Module(title=u"Module 1.1", module_id="11", zodb_path="1/1", skip_children=False)
        mod1.addChild(mod11)
        self.assertEqual(navigation.FindNextQuestion(mod1, survey, self.filter()), None)

    def testSkipModuleIfNoRisksPresent(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1", skip_children=False)
        survey.addChild(mod1)
        mod11=model.Module(title=u"Module 1.1", module_id="11", zodb_path="1/1", skip_children=False)
        mod1.addChild(mod11)
        q111=model.Risk(title=u"Risk 1.1.1", risk_id="1", zodb_path="1/1/1", identification="yes")
        mod11.addChild(q111)
        self.assertEqual(navigation.FindNextQuestion(mod1, survey, self.filter()), None)

    def testShowModuleWithTop5RiskEvenIfNotPresent(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1", skip_children=False)
        survey.addChild(mod1)
        mod11=model.Module(title=u"Module 1.1", module_id="11", zodb_path="1/1", skip_children=False)
        mod1.addChild(mod11)
        q111=model.Risk(title=u"Risk 1.1.1", risk_id="1", zodb_path="1/1/1", identification="yes", risk_type="top5")
        mod11.addChild(q111)
        self.failUnless(navigation.FindNextQuestion(mod1, survey, self.filter()) is mod11)

    def testSkipRiskIfNotPresent(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1", skip_children=False)
        survey.addChild(mod1)
        q11=model.Risk(title=u"Risk 1.1", risk_id="1", zodb_path="1/1", identification="yes")
        mod1.addChild(q11)
        self.assertEqual(navigation.FindNextQuestion(mod1, survey, self.filter()), None)

    def testShowTop5RiskEvenIfNotPresent(self):
        (session, survey)=createSurvey()
        mod1=model.Module(title=u"Module 1", module_id="1", zodb_path="1", skip_children=False)
        survey.addChild(mod1)
        q11=model.Risk(title=u"Risk 1.1", risk_id="1", zodb_path="1/1", identification="yes", risk_type="top5")
        mod1.addChild(q11)
        self.failUnless(navigation.FindNextQuestion(mod1, survey, self.filter()) is q11)



class GetTreeDataTests(DatabaseTests):
    def createSqlData(self):
        self.request=MockRequest()
        (self.session, self.survey)=createSurvey()
        self.request.survey=self.survey
        self.survey.absolute_url=lambda self=None: "http://nohost"
        self.session.flush()
        self.mod1=self.survey.addChild(model.Module(
            title=u"module 1", module_id="1", zodb_path="a"))
        self.q1=self.mod1.addChild(model.Risk(
            title=u"question 1", risk_id="1", zodb_path="a/b"))
        self.session.flush()

    def testMinimalTree(self):
        self.createSqlData()
        data=navigation.getTreeData(self.request, self.q1)
        self.failUnless(isinstance(data, dict))
        children=data["children"]
        self.assertEqual(len(children), 1)
        mod1=children[0]
        self.assertEqual(mod1["id"], self.mod1.id)
        self.assertEqual(mod1["type"], "module")
        self.assertEqual(mod1["number"], "1")
        self.assertEqual(mod1["title"], "module 1")
        self.assertEqual(mod1["current"], False)
        self.assertEqual(mod1["current_parent"], True)
        self.assertEqual(mod1["leaf_module"], True)
        self.assertEqual(mod1["active"], True)
        self.assertEqual(mod1["class"], "active current")
        self.assertEqual(mod1["url"], "http://nohost/identification/1")
        self.assertEqual(len(mod1["children"]), 1)
        q1=mod1["children"][0]
        self.assertEqual(q1["id"], self.q1.id)
        self.assertEqual(q1["type"], "risk")
        self.assertEqual(q1["number"], "1.1")
        self.assertEqual(q1["title"], "question 1")
        self.assertEqual(q1["current"], True)
        self.assertEqual(q1["active"], False)
        self.assertEqual(q1["class"], "current")
        self.assertEqual(q1["url"], "http://nohost/identification/1/1")
        self.assertEqual(len(q1["children"]), 0)

    def testIncludeRisksChildrenOfModule(self):
        self.createSqlData()
        data=navigation.getTreeData(self.request, self.mod1)
        mod1_data=data["children"][0]
        self.assertEqual(len(mod1_data["children"]), 1)
        self.assertEqual(mod1_data["leaf_module"], True)

    def testIncludeRisksChildrenOfModuleUnlessSkipped(self):
        self.createSqlData()
        self.mod1.skip_children=True
        data=navigation.getTreeData(self.request, self.mod1)
        mod1_data=data["children"][0]
        self.assertEqual(len(mod1_data["children"]), 0)
        self.assertEqual(mod1_data["leaf_module"], False)

    def testListSiblingModulesOfParentIfRisk(self):
        self.createSqlData()
        self.mod1.removeChildren()
        mod11=self.mod1.addChild(model.Module(
            title=u"module 1.1", module_id="11", zodb_path="a/a"))
        mod12=self.mod1.addChild(model.Module(
            title=u"module 1.2", module_id="12", zodb_path="a/a"))
        q111=mod11.addChild(model.Risk(
            title=u"question 1.1.1", risk_id="111", zodb_path="a/a/a"))
        data=navigation.getTreeData(self.request, q111)
        mod1_data=data["children"][0]
        self.assertEqual(len(mod1_data["children"]), 2)
        self.assertEqual(mod1_data["children"][0]["id"], mod11.id)
        self.assertEqual(mod1_data["children"][0]["current_parent"], True)
        self.assertEqual(mod1_data["children"][0]["current"], False)
        self.assertEqual(mod1_data["children"][0]["leaf_module"], True)
        self.assertEqual(mod1_data["children"][0]["active"], True)
        self.assertEqual(mod1_data["children"][1]["id"], mod12.id)
        self.assertEqual(mod1_data["children"][1]["current_parent"], False)
        self.assertEqual(mod1_data["children"][1]["current"], False)
        self.assertEqual(mod1_data["children"][1]["active"], False)

    def testIgnoreSiblingQuestions(self):
        self.createSqlData()
        self.mod1.removeChildren()
        mod11=self.mod1.addChild(model.Module(
            title=u"module 1.1", module_id="11", zodb_path="a/a"))
        q111=mod11.addChild(model.Risk(
            title=u"question 1.1.1", risk_id="111", zodb_path="a/a/a"))
        self.mod1.addChild(model.Risk(
            title=u"question 1.2", risk_id="12", zodb_path="a/b"))
        data=navigation.getTreeData(self.request, q111)
        mod1_data=data["children"][0]
        self.assertEqual(len(mod1_data["children"]), 1)
        self.assertEqual(mod1_data["children"][0]["id"], mod11.id)

    def testListRootSiblingModules(self):
        self.createSqlData()
        self.mod1.removeChildren()
        mod11=self.mod1.addChild(model.Module(
            title=u"module 1.1", module_id="11", zodb_path="a/a"))
        q111=mod11.addChild(model.Risk(
            title=u"question 1.1.1", risk_id="111", zodb_path="a/a/a"))
        mod2=self.survey.addChild(model.Module(
            title=u"module 2", module_id="2", zodb_path="b"))
        data=navigation.getTreeData(self.request, q111)
        self.assertEqual(len(data["children"]), 2)
        self.assertEqual(data["children"][0]["id"], self.mod1.id)
        self.assertEqual(data["children"][0]["current"], False)
        self.assertEqual(data["children"][0]["active"], True)
        self.assertEqual(data["children"][1]["id"], mod2.id)
        self.assertEqual(data["children"][1]["current"], False)
        self.assertEqual(data["children"][1]["active"], False)



class FirstTests(unittest.TestCase):
    def testNonIterableRaisesTypeError(self):
        self.assertRaises(TypeError, navigation.first, lambda x:x, None)

    def testEmptyList(self):
        self.assertEqual(navigation.first(lambda x:x, []), None)

    def testNoMatchInList(self):
        self.assertEqual(navigation.first(lambda x:x, [False]), None)
            
    def testMatch(self):
        self.assertEqual(navigation.first(lambda x:x, [False, True]), True)

    def testFirstMatch(self):
        self.assertEqual(navigation.first(lambda x:x, [1, 2]), 1)

    def testGenerator(self):
        self.assertEqual(navigation.first(lambda x:x, xrange(5)), 1)

