text: # -*- coding: utf-8 -*-
  """
  Tests for zcml.py.
  
  """
  from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  
  # stdlib imports
  import unittest
  
  from zope import component
  from zope import interface
  from zope.component.testing import PlacelessSetup
  from zope.configuration import xmlconfig
  
  from nti.externalization.interfaces import IClassObjectFactory
  from nti.externalization.interfaces import IMimeObjectFactory
  from nti.externalization.interfaces import _ILegacySearchModuleFactory
  from nti.testing.matchers import is_empty
  
  from hamcrest import assert_that
  from hamcrest import same_instance
  from hamcrest import equal_to
  from hamcrest import is_
  from hamcrest import is_not
  from hamcrest import has_length
  from hamcrest import has_property
  from hamcrest import none
  
  # disable: accessing protected members, too many methods
  # pylint: disable=W0212,R0904
  # pylint: disable=inherit-non-class
  
  class RegistrationMixin(object):
  
      assertRaisesRegex = getattr(unittest.TestCase,
                                  'assertRaisesRegex',
                                  unittest.TestCase.assertRaisesRegexp)
  
      def _getModule(self):
          import sys
          return sys.modules[__name__]
  
      def _addFactory(self, factory, name='Factory'):
          module = self._getModule()
          setattr(module, name, factory)
          self.addCleanup(delattr, module, name)
  
  
  class TestRegisterMimeFactoriesZCML(PlacelessSetup,
                                      RegistrationMixin,
                                      unittest.TestCase):
  
      SCAN_THIS_MODULE = """
          <configure xmlns:ext="http://nextthought.com/ntp/ext">
             <include package="nti.externalization" file="meta.zcml" />
             <ext:registerMimeFactories module="%s" />
          </configure>
          """ % (__name__)
  
      def test_scan_module_with_no_factories(self):
          xmlconfig.string(self.SCAN_THIS_MODULE)
          gsm = component.getGlobalSiteManager()
          assert_that(list(gsm.registeredUtilities()), is_empty())
  
      def test_scan_module_with_factory(self):
          class O(object):
              __external_can_create__ = True
              mimeType = 'application/foo'
          self._addFactory(O)
  
          xmlconfig.string(self.SCAN_THIS_MODULE)
          assert_that(component.getUtility(IMimeObjectFactory,
                                           name=O.mimeType),
                      is_not(none()))
  
      def test_scan_module_with_factories(self):
          class O(object):
              __external_can_create__ = True
              mimeType = 'application/foo'
  
          class P(object):
              __external_can_create__ = True
              mimeType = 'application/foo2'
  
          self._addFactory(O)
          self._addFactory(P, 'Factory2')
          xmlconfig.string(self.SCAN_THIS_MODULE)
          o = component.getUtility(IMimeObjectFactory,
                                   name=O.mimeType)
          p = component.getUtility(IMimeObjectFactory,
                                   name=P.mimeType)
          assert_that(o,
                      is_not(none()))
          assert_that(p,
                      is_not(none()))
          assert_that(o, is_not(p))
  
      def test_scan_module_with_factories_conflict(self):
          from zope.configuration.config import ConfigurationConflictError
          class O(object):
              __external_can_create__ = True
              mimeType = 'application/foo'
  
          class P(object):
              __external_can_create__ = True
              mimeType = O.mimeType
  
          self._addFactory(O)
          self._addFactory(P, 'Factory2')
  
          with self.assertRaises(ConfigurationConflictError):
              xmlconfig.string(self.SCAN_THIS_MODULE)
  
      def test_scan_module_with_factory_legacy(self):
          class O(object):
              __external_can_create__ = True
              mime_type = 'application/foo'
  
          self._addFactory(O)
          xmlconfig.string(self.SCAN_THIS_MODULE)
          assert_that(component.getUtility(IMimeObjectFactory,
                                           name=O.mime_type),
                      is_not(none()))
  
      def test_scan_module_with_factory_no_mime(self):
          class O(object):
              __external_can_create__ = True
  
          self._addFactory(O)
          xmlconfig.string(self.SCAN_THIS_MODULE)
          gsm = component.getGlobalSiteManager()
          assert_that(list(gsm.registeredUtilities()), is_empty())
  
      def test_scan_module_with_factory_imported(self):
          class O(object):
              __external_can_create__ = True
              mimeType = 'application/foo'
  
          O.__module__ = '__dynamic__'
  
          self._addFactory(O)
          xmlconfig.string(self.SCAN_THIS_MODULE)
          gsm = component.getGlobalSiteManager()
          assert_that(list(gsm.registeredUtilities()), is_empty())
  
      def test_scan_module_with_factory_non_create(self):
          class O(object):
              __external_can_create__ = False
              mimeType = 'application/foo'
  
          self._addFactory(O)
          xmlconfig.string(self.SCAN_THIS_MODULE)
          gsm = component.getGlobalSiteManager()
          assert_that(list(gsm.registeredUtilities()), is_empty())
  
  class IExtRoot(interface.Interface):
      pass
  
  class IOBase(object):
  
      @classmethod
      def _ap_find_package_interface_module(cls):
          import sys
          return sys.modules[__name__]
  
  
  class TestAutoPackageZCML(PlacelessSetup,
                            RegistrationMixin,
                            unittest.TestCase):
      SCAN_THIS_MODULE_TMPL = """
          <configure xmlns:ext="http://nextthought.com/ntp/ext">
             <include package="nti.externalization" file="meta.zcml" />
             <ext:registerAutoPackageIO root_interfaces="%(mod)s.%(root)s"
                modules="%(mod)s"
                iobase="%(mod)s.IOBase"
                register_legacy_search_module="yes" />
          </configure>
          """
  
      SCAN_THIS_MODULE = SCAN_THIS_MODULE_TMPL % {'mod': __name__, 'root': IExtRoot.__name__}
  
      def test_scan_package_empty(self):
          from nti.externalization import internalization as INT
          xmlconfig.string(self.SCAN_THIS_MODULE)
          gsm = component.getGlobalSiteManager()
          # The interfaces IExtRoot and IInternalObjectIO were registered
          assert_that(list(gsm.registeredUtilities()), has_length(2))
          # The root interface was registered
          assert_that(list(gsm.registeredAdapters()), has_length(1))
  
          # The module was added to the legacy search list directly,
          # now, producing the factories it needed (which was none)
          assert_that(INT.LEGACY_FACTORY_SEARCH_MODULES,
                      is_empty())
  
      def test_scan_package_inherited(self):
          # Issue #97: When interface tags are inherited,
          # we don't double register.
          import sys
          from zope.interface.interfaces import IInterface
          from ..interfaces import IInternalObjectIOFinder
  
          class IPublic(interface.Interface):
              pass
  
          class IPrivate(IPublic):
              pass
  
          @interface.implementer(IPublic)
          class Public(object):
              pass
  
          @interface.implementer(IPrivate)
          class Private(object):
              pass
  
  
          to_reg = (IPublic, IPrivate, Public, Private, )
          for r in to_reg:
              setattr(sys.modules[__name__], r.__name__, r)
          sys.modules[__name__].Alias = Private # The alias triggers issue #97
          try:
              xmlconfig.string(self.SCAN_THIS_MODULE_TMPL % {
                  'mod': __name__,
                  'root': IPublic.__name__,
              })
              gsm = component.getGlobalSiteManager()
  
              ifaces = list(gsm.getAllUtilitiesRegisteredFor(IInterface))
              assert_that(set(ifaces), is_({
                  _ILegacySearchModuleFactory,
                  IInternalObjectIOFinder,
                  IPublic,
                  IMimeObjectFactory,
              }))
              mime_factories = list(gsm.getAllUtilitiesRegisteredFor(IMimeObjectFactory))
              assert_that(mime_factories, has_length(1))
              # The root interface was registered
              adapters = list(gsm.registeredAdapters())
              assert_that(adapters, has_length(1))
              assert_that(adapters[0], has_property('required', (IPublic,)))
          finally:
              for r in to_reg:
                  delattr(sys.modules[__name__], r.__name__)
              del sys.modules[__name__].Alias
  
      def test_scan_package_legacy_utility(self):
          @interface.implementer(IExtRoot)
          class O(object):
              __external_can_create__ = True
              mimeType = 'application/foo'
  
          self._addFactory(O)
          xmlconfig.string(self.SCAN_THIS_MODULE)
          gsm = component.getGlobalSiteManager()
          # The interfaces IExtRoot and IInternalObjectIO were registered,
          # as well as an IMimeObjectFactory and that interface,
          assert_that(list(gsm.registeredUtilities()), has_length(7))
  
          factory = gsm.getUtility(IMimeObjectFactory, 'application/foo')
          assert_that(factory, has_property('_callable', equal_to(O)))
  
          factory = gsm.getUtility(_ILegacySearchModuleFactory, 'o')
          assert_that(factory, is_(same_instance(O)))
  
          factory = gsm.getUtility(_ILegacySearchModuleFactory, 'O')
          assert_that(factory, is_(same_instance(O)))
  
  class TestClassObjectFactory(PlacelessSetup,
                               RegistrationMixin,
                               unittest.TestCase):
  
      SCAN_THIS_MODULE = """
          <configure xmlns:ext="http://nextthought.com/ntp/ext"
                     xmlns:i18n="http://namespaces.zope.org/i18n"
                     i18n_domain="zope">
             <include package="nti.externalization" file="meta.zcml" />
             <ext:classObjectFactory
                factory="%s.Factory"
                PLACEHOLDER
                />
          </configure>
      """ % (__name__,)
  
  
      def test_scan_no_create(self):
          class O(object):
              pass
  
          self._addFactory(O)
          with self.assertRaisesRegex(xmlconfig.ZopeXMLConfigurationError,
                                      "must set __external_can_create__ to true"):
              xmlconfig.string(self.SCAN_THIS_MODULE.replace('PLACEHOLDER', ''))
  
      def test_scan_not_callable(self):
          class O(object):
              __external_can_create__ = True
  
          self._addFactory(O())
  
          with self.assertRaisesRegex(xmlconfig.ZopeXMLConfigurationError,
                                      "must be callable"):
              xmlconfig.string(self.SCAN_THIS_MODULE.replace('PLACEHOLDER', ''))
  
      def test_scan_no_name(self):
          class O(object):
              __external_can_create__ = True
  
          self._addFactory(O)
          xmlconfig.string(self.SCAN_THIS_MODULE.replace('PLACEHOLDER', ''))
          factory = component.getUtility(IClassObjectFactory, 'O')
          assert_that(factory, has_property('_callable', equal_to(O)))
  
      def test_scan_name_in_xml(self):
          class O(object):
              __external_class_name__ = "Ignored"
              __external_can_create__ = True
  
          self._addFactory(O)
          xmlconfig.string(self.SCAN_THIS_MODULE.replace('PLACEHOLDER',
                                                         'name="AName" title="A title"'))
          factory = component.getUtility(IClassObjectFactory, 'AName')
          assert_that(factory, has_property('_callable', equal_to(O)))
          assert_that(factory, has_property('title', equal_to("A title")))
  
      def test_scan_name_in_class(self):
          class O(object):
              __external_class_name__ = "FromClass"
              __external_can_create__ = True
  
          self._addFactory(O)
          xmlconfig.string(self.SCAN_THIS_MODULE.replace('PLACEHOLDER', ''))
          factory = component.getUtility(IClassObjectFactory, 'FromClass')
          assert_that(factory, has_property('_callable', equal_to(O)))
  
  
  class ISchema(interface.Interface):
  
      field = interface.Attribute("This is a field")
      field2 = interface.Attribute("This is another field")
  
  class IDerived(ISchema):
      pass
  
  class TestAnonymousObjectFactoryZCML(PlacelessSetup,
                                       RegistrationMixin,
                                       unittest.TestCase):
  
      SCAN_THIS_MODULE = """
          <configure xmlns:ext="http://nextthought.com/ntp/ext"
                     xmlns:i18n="http://namespaces.zope.org/i18n"
                     i18n_domain="zope">
             <include package="nti.externalization" file="meta.zcml" />
             <ext:anonymousObjectFactory
                  factory="{0}.Factory"
                  for="{0}.ISchema"
                  field="field"
               />
              <ext:anonymousObjectFactoryInPlace
                  for="{0}.ISchema"
                  field="field2"
               />
          </configure>
      """.format(__name__)
  
      def test_sets_tagged_value(self):
          class O(object):
              __external_can_create__ = True
  
          self._addFactory(O)
  
          xmlconfig.string(self.SCAN_THIS_MODULE)
  
          assert_that(ISchema['field'].getDirectTaggedValue('__external_factory__'),
                      is_('nti.externalization.tests.test_zcml.ISchema:field'))
          assert_that(ISchema['field2'].getDirectTaggedValue('__external_factory__'),
                      is_('nti.externalization.tests.test_zcml.ISchema:field2'))
  
      def test_scan_no_create(self):
          class O(object):
              pass
  
          self._addFactory(O)
          with self.assertRaisesRegex(xmlconfig.ZopeXMLConfigurationError,
                                      "must set __external_can_create__ to true"):
              xmlconfig.string(self.SCAN_THIS_MODULE)
  
      def test_scan_not_callable(self):
          class O(object):
              __external_can_create__ = True
  
          self._addFactory(O())
  
          with self.assertRaisesRegex(xmlconfig.ZopeXMLConfigurationError,
                                      "must be callable"):
              xmlconfig.string(self.SCAN_THIS_MODULE)
  
      def test_scan_not_direct(self):
          class O(object):
              __external_can_create__ = True
  
          self._addFactory(O)
          zcml = self.SCAN_THIS_MODULE.replace("ISchema", 'IDerived')
  
          with self.assertRaisesRegex(xmlconfig.ZopeXMLConfigurationError,
                                      "is not directly part of the interface"):
              xmlconfig.string(zcml)
  
      def test_in_place(self):
          class O(object):
              __external_can_create__ = True
  
          self._addFactory(O)
  
          xmlconfig.string(self.SCAN_THIS_MODULE)
  
          obj = component.createObject('nti.externalization.tests.test_zcml.ISchema:field2',
                                       self)
          assert_that(obj, is_(self))
  