# -*- coding: utf-8 -*-
#
# CMFDiffTool tests
#

from Products.CMFCore.utils import getToolByName
from zExceptions import BadRequest

from Products.CMFDiffTool.CMFDiffTool import registerDiffType
from Products.CMFDiffTool.CMFDiffTool import unregisterDiffType


class DummyDiff:
    meta_type = "Dummy Diff Type"


class DummyDiff2:
    meta_type = "Second Dummy Diff Type"

from unittest import TestCase
from plone.app.testing import PLONE_INTEGRATION_TESTING


class TestDiffTool(TestCase):
    """Test the portal_diff tool"""

    layer = PLONE_INTEGRATION_TESTING

    def setUp(self):
        self.p_diff = getToolByName(self.layer['portal'], 'portal_diff')
        # clear pt_diff registry
        self.p_diff._pt_diffs = {}

        # patch portal_types to list `Document` in the listContentTypes
        # a plausability check is done in the `setDiffForPortalType` method
        # but we have no content registry
        portal_types = getToolByName(self.layer['portal'], 'portal_types')
        self._old_listContentTypes = portal_types.listContentTypes
        portal_types.listContentTypes = lambda: ['Document']
        registerDiffType(DummyDiff)

    def tearDown(self):
        portal_types = getToolByName(self.layer['portal'], 'portal_types')
        portal_types.listContentTypes = self._old_listContentTypes

    def testInterface(self):
        """Ensure that tool instances implement the portal_diff interface"""
        from Products.CMFDiffTool.interfaces.portal_diff import portal_diff
        self.assertTrue(portal_diff.providedBy(self.p_diff))

    def testRegisterDiffType(self):
        """Test registration of Diff types"""
        unregisterDiffType(DummyDiff)
        self.assertNotIn('Dummy Diff Type', self.p_diff.listDiffTypes())
        registerDiffType(DummyDiff)
        self.assertIn('Dummy Diff Type', self.p_diff.listDiffTypes())

    def testSetDiff(self):
        """Test setDiffForPortalType() method"""
        d = {'field1': 'TestDiff', 'field2': 'Dummy Diff Type'}
        self.p_diff.setDiffForPortalType('Document', d)
        self.assertEqual(self.p_diff.getDiffForPortalType('Document'), d)

    def testSetDiffReplaces(self):
        """Test that setDiffForPortalType() replaces old data"""
        d1 = {'field1': 'TestDiff', 'field2': 'Dummy Diff Type'}
        d2 = {'field3': 'Dummy Diff Type'}
        self.p_diff.setDiffForPortalType('Document', d1)
        self.p_diff.setDiffForPortalType('Document', d2)
        self.assertEqual(self.p_diff.getDiffForPortalType('Document'), d2)

    def testSingleSetDiffField(self):
        """Test setDiffField method"""
        self.p_diff.setDiffField('Document', 'title', 'Dummy Diff Type')
        self.assertEqual(self.p_diff.getDiffForPortalType('Document'),
                         {'title': 'Dummy Diff Type'})

    def testMultipleSetDiffField(self):
        """Test setDiffField method adding a second field to one content type"""
        self.p_diff.setDiffField('Document', 'title', 'Dummy Diff Type')
        self.p_diff.setDiffField('Document', 'description', 'Dummy Diff Type')
        d = {'title': 'Dummy Diff Type', 'description': 'Dummy Diff Type'}
        self.assertEqual(self.p_diff.getDiffForPortalType('Document'), d)

    def testReplaceSetDiffField(self):
        """Test that setDiffField does a replace for existing fields"""
        registerDiffType(DummyDiff2)
        self.p_diff.setDiffField('Document', 'title', 'Dummy Diff Type')
        self.p_diff.setDiffField('Document', 'title', 'Second Dummy Diff Type')
        d = {'title': 'Second Dummy Diff Type'}
        self.assertEqual(self.p_diff.getDiffForPortalType('Document'), d)
        unregisterDiffType(DummyDiff2)

    def testSetDiffFieldNameFailure(self):
        self.assertRaises(BadRequest, self.p_diff.setDiffField, 'Bob', 'title', 'Dummy Diff Type')

    def testSetDiffFieldBlankFieldFailure(self):
        self.assertRaises(BadRequest, self.p_diff.setDiffField, 'Document', '', 'Dummy Diff Type')

    def testSetDiffFieldInvalidDiffFailure(self):
        self.assertRaises(BadRequest, self.p_diff.setDiffField, 'Document', 'title', 'NoDiff')

    def beforeTearDown(self):
        # Undo changes that don't get rolled back (i.e. module level changes)
        unregisterDiffType(DummyDiff)
