import os
import unittest

from pyramid.exceptions import (
    ConfigurationConflictError,
    ConfigurationExecutionError,
)
from pyramid.interfaces import IRequest

from . import (
    DummyContext,
    dummy_extend,
    dummy_extend2,
    dummy_include,
    dummy_tween_factory,
)


class ConfiguratorTests(unittest.TestCase):
    def _makeOne(self, *arg, **kw):
        from pyramid.config import Configurator

        config = Configurator(*arg, **kw)
        return config

    def _getViewCallable(
        self,
        config,
        ctx_iface=None,
        request_iface=None,
        name='',
        exception_view=False,
    ):
        from pyramid.interfaces import (
            IExceptionViewClassifier,
            IView,
            IViewClassifier,
        )

        if exception_view:  # pragma: no cover
            classifier = IExceptionViewClassifier
        else:
            classifier = IViewClassifier
        return config.registry.adapters.lookup(
            (classifier, request_iface, ctx_iface),
            IView,
            name=name,
            default=None,
        )

    def _registerEventListener(self, config, event_iface=None):
        if event_iface is None:  # pragma: no cover
            from zope.interface import Interface

            event_iface = Interface
        L = []

        def subscriber(*event):
            L.extend(event)

        config.registry.registerHandler(subscriber, (event_iface,))
        return L

    def _makeRequest(self, config):
        request = DummyRequest()
        request.registry = config.registry
        return request

    def test_ctor_no_registry(self):
        import sys

        from pyramid.config import Configurator
        from pyramid.interfaces import IRendererFactory, ISettings

        config = Configurator()
        this_pkg = sys.modules['tests.test_config']
        self.assertTrue(config.registry.getUtility(ISettings))
        self.assertEqual(config.package, this_pkg)
        config.commit()
        self.assertTrue(config.registry.getUtility(IRendererFactory, 'json'))
        self.assertTrue(config.registry.getUtility(IRendererFactory, 'string'))

    def test_begin(self):
        from pyramid.config import Configurator

        config = Configurator()
        manager = DummyThreadLocalManager()
        config.manager = manager
        config.begin()
        self.assertEqual(
            manager.pushed, {'registry': config.registry, 'request': None}
        )
        self.assertEqual(manager.popped, False)

    def test_begin_with_request(self):
        from pyramid.config import Configurator

        config = Configurator()
        request = object()
        manager = DummyThreadLocalManager()
        config.manager = manager
        config.begin(request=request)
        self.assertEqual(
            manager.pushed, {'registry': config.registry, 'request': request}
        )
        self.assertEqual(manager.popped, False)

    def test_begin_overrides_request(self):
        from pyramid.config import Configurator

        config = Configurator()
        manager = DummyThreadLocalManager()
        req = object()
        # set it up for auto-propagation
        pushed = {'registry': config.registry, 'request': None}
        manager.pushed = pushed
        config.manager = manager
        config.begin(req)
        self.assertTrue(manager.pushed is not pushed)
        self.assertEqual(manager.pushed['request'], req)
        self.assertEqual(manager.pushed['registry'], config.registry)

    def test_begin_propagates_request_for_same_registry(self):
        from pyramid.config import Configurator

        config = Configurator()
        manager = DummyThreadLocalManager()
        req = object()
        pushed = {'registry': config.registry, 'request': req}
        manager.pushed = pushed
        config.manager = manager
        config.begin()
        self.assertTrue(manager.pushed is not pushed)
        self.assertEqual(manager.pushed['request'], req)
        self.assertEqual(manager.pushed['registry'], config.registry)

    def test_begin_does_not_propagate_request_for_diff_registry(self):
        from pyramid.config import Configurator

        config = Configurator()
        manager = DummyThreadLocalManager()
        req = object()
        pushed = {'registry': object(), 'request': req}
        manager.pushed = pushed
        config.manager = manager
        config.begin()
        self.assertTrue(manager.pushed is not pushed)
        self.assertEqual(manager.pushed['request'], None)
        self.assertEqual(manager.pushed['registry'], config.registry)

    def test_end(self):
        from pyramid.config import Configurator

        config = Configurator()
        manager = DummyThreadLocalManager()
        pushed = manager.pushed
        config.manager = manager
        config.end()
        self.assertEqual(manager.pushed, pushed)
        self.assertEqual(manager.popped, True)

    def test_context_manager(self):
        from pyramid.config import Configurator

        config = Configurator()
        manager = DummyThreadLocalManager()
        config.manager = manager
        view = lambda r: None
        with config as ctx:
            self.assertTrue(config is ctx)
            self.assertEqual(
                manager.pushed, {'registry': config.registry, 'request': None}
            )
            self.assertFalse(manager.popped)
            config.add_view(view)
        self.assertTrue(manager.popped)
        config.add_view(view)  # did not raise a conflict because of commit
        config.commit()

    def test_ctor_with_package_registry(self):
        import sys

        from pyramid.config import Configurator

        pkg = sys.modules['pyramid']
        config = Configurator(package=pkg)
        self.assertEqual(config.package, pkg)

    def test_ctor_noreg_custom_settings(self):
        from pyramid.interfaces import ISettings

        settings = {'reload_templates': True, 'mysetting': True}
        config = self._makeOne(settings=settings)
        settings = config.registry.getUtility(ISettings)
        self.assertEqual(settings['reload_templates'], True)
        self.assertEqual(settings['debug_authorization'], False)
        self.assertEqual(settings['mysetting'], True)

    def test_ctor_noreg_debug_logger_None_default(self):
        from pyramid.interfaces import IDebugLogger

        config = self._makeOne()
        logger = config.registry.getUtility(IDebugLogger)
        self.assertEqual(logger.name, 'tests.test_config')

    def test_ctor_noreg_debug_logger_non_None(self):
        from pyramid.interfaces import IDebugLogger

        logger = object()
        config = self._makeOne(debug_logger=logger)
        result = config.registry.getUtility(IDebugLogger)
        self.assertEqual(logger, result)

    def test_ctor_security_policy(self):
        from pyramid.interfaces import ISecurityPolicy

        policy = object()
        config = self._makeOne(security_policy=policy)
        config.commit()
        result = config.registry.getUtility(ISecurityPolicy)
        self.assertEqual(policy, result)

    def test_ctor_authentication_policy(self):
        from pyramid.interfaces import IAuthenticationPolicy

        policy = object()
        config = self._makeOne(authentication_policy=policy)
        config.commit()
        result = config.registry.getUtility(IAuthenticationPolicy)
        self.assertEqual(policy, result)

    def test_ctor_authorization_policy_only(self):
        policy = object()
        config = self._makeOne(authorization_policy=policy)
        self.assertRaises(ConfigurationExecutionError, config.commit)

    def test_ctor_no_root_factory(self):
        from pyramid.interfaces import IRootFactory

        config = self._makeOne()
        self.assertEqual(config.registry.queryUtility(IRootFactory), None)
        config.commit()
        self.assertEqual(config.registry.queryUtility(IRootFactory), None)

    def test_ctor_with_root_factory(self):
        from pyramid.interfaces import IRootFactory

        factory = object()
        config = self._makeOne(root_factory=factory)
        self.assertEqual(config.registry.queryUtility(IRootFactory), None)
        config.commit()
        self.assertEqual(config.registry.queryUtility(IRootFactory), factory)

    def test_ctor_alternate_renderers(self):
        from pyramid.interfaces import IRendererFactory

        renderer = object()
        config = self._makeOne(renderers=[('yeah', renderer)])
        config.commit()
        self.assertEqual(
            config.registry.getUtility(IRendererFactory, 'yeah'), renderer
        )

    def test_ctor_default_renderers(self):
        from pyramid.interfaces import IRendererFactory
        from pyramid.renderers import json_renderer_factory

        config = self._makeOne()
        self.assertEqual(
            config.registry.getUtility(IRendererFactory, 'json'),
            json_renderer_factory,
        )

    def test_ctor_default_permission(self):
        from pyramid.interfaces import IDefaultPermission

        config = self._makeOne(default_permission='view')
        config.commit()
        self.assertEqual(
            config.registry.getUtility(IDefaultPermission), 'view'
        )

    def test_ctor_session_factory(self):
        from pyramid.interfaces import ISessionFactory

        factory = object()
        config = self._makeOne(session_factory=factory)
        self.assertEqual(config.registry.queryUtility(ISessionFactory), None)
        config.commit()
        self.assertEqual(config.registry.getUtility(ISessionFactory), factory)

    def test_ctor_default_view_mapper(self):
        from pyramid.interfaces import IViewMapperFactory

        mapper = object()
        config = self._makeOne(default_view_mapper=mapper)
        config.commit()
        self.assertEqual(
            config.registry.getUtility(IViewMapperFactory), mapper
        )

    def test_ctor_httpexception_view_default(self):
        from pyramid.httpexceptions import default_exceptionresponse_view
        from pyramid.interfaces import IExceptionResponse

        config = self._makeOne()
        view = self._getViewCallable(
            config, ctx_iface=IExceptionResponse, request_iface=IRequest
        )
        self.assertTrue(view.__wraps__ is default_exceptionresponse_view)

    def test_ctor_exceptionresponse_view_None(self):
        from pyramid.interfaces import IExceptionResponse

        config = self._makeOne(exceptionresponse_view=None)
        view = self._getViewCallable(
            config, ctx_iface=IExceptionResponse, request_iface=IRequest
        )
        self.assertTrue(view is None)

    def test_ctor_exceptionresponse_view_custom(self):
        from pyramid.interfaces import IExceptionResponse

        def exceptionresponse_view(context, request):  # pragma: no cover
            pass

        config = self._makeOne(exceptionresponse_view=exceptionresponse_view)
        view = self._getViewCallable(
            config, ctx_iface=IExceptionResponse, request_iface=IRequest
        )
        self.assertTrue(view.__wraps__ is exceptionresponse_view)

    def test_ctor_with_introspection(self):
        config = self._makeOne(introspection=False)
        self.assertEqual(config.introspection, False)

    def test_ctor_default_webob_response_adapter_registered(self):
        from webob import Response as WebobResponse

        response = WebobResponse()
        from pyramid.interfaces import IResponse

        config = self._makeOne(autocommit=True)
        result = config.registry.queryAdapter(response, IResponse)
        self.assertEqual(result, response)

    def test_with_package_module(self):
        from . import test_init

        config = self._makeOne()
        newconfig = config.with_package(test_init)
        import tests.test_config

        self.assertEqual(newconfig.package, tests.test_config)

    def test_with_package_package(self):
        from tests import test_config

        config = self._makeOne()
        newconfig = config.with_package(test_config)
        self.assertEqual(newconfig.package, test_config)

    def test_with_package(self):
        import tests

        config = self._makeOne()
        config.basepath = 'basepath'
        config.info = 'info'
        config.includepath = ('spec',)
        config.autocommit = True
        config.route_prefix = 'prefix'
        newconfig = config.with_package(tests)
        self.assertEqual(newconfig.package, tests)
        self.assertEqual(newconfig.registry, config.registry)
        self.assertEqual(newconfig.autocommit, True)
        self.assertEqual(newconfig.route_prefix, 'prefix')
        self.assertEqual(newconfig.info, 'info')
        self.assertEqual(newconfig.basepath, 'basepath')
        self.assertEqual(newconfig.includepath, ('spec',))

    def test_maybe_dotted_string_success(self):
        import tests.test_config

        config = self._makeOne()
        result = config.maybe_dotted('tests.test_config')
        self.assertEqual(result, tests.test_config)

    def test_maybe_dotted_string_fail(self):
        config = self._makeOne()
        self.assertRaises(ImportError, config.maybe_dotted, 'cant.be.found')

    def test_maybe_dotted_notstring_success(self):
        import tests.test_config

        config = self._makeOne()
        result = config.maybe_dotted(tests.test_config)
        self.assertEqual(result, tests.test_config)

    def test_absolute_asset_spec_already_absolute(self):
        import tests.test_config

        config = self._makeOne(package=tests.test_config)
        result = config.absolute_asset_spec('already:absolute')
        self.assertEqual(result, 'already:absolute')

    def test_absolute_asset_spec_notastring(self):
        import tests.test_config

        config = self._makeOne(package=tests.test_config)
        result = config.absolute_asset_spec(None)
        self.assertEqual(result, None)

    def test_absolute_asset_spec_relative(self):
        import tests.test_config

        config = self._makeOne(package=tests.test_config)
        result = config.absolute_asset_spec('files')
        self.assertEqual(result, 'tests.test_config:files')

    def test__fix_registry_has_listeners(self):
        reg = DummyRegistry()
        config = self._makeOne(reg)
        config._fix_registry()
        self.assertEqual(reg.has_listeners, True)

    def test__fix_registry_notify(self):
        reg = DummyRegistry()
        config = self._makeOne(reg)
        config._fix_registry()
        self.assertEqual(reg.notify(1), None)
        self.assertEqual(reg.events, (1,))

    def test__fix_registry_queryAdapterOrSelf(self):
        from zope.interface import Interface, implementer

        class IFoo(Interface):
            pass

        @implementer(IFoo)
        class Foo:
            pass

        class Bar:
            pass

        adaptation = ()
        foo = Foo()
        bar = Bar()
        reg = DummyRegistry(adaptation)
        config = self._makeOne(reg)
        config._fix_registry()
        self.assertTrue(reg.queryAdapterOrSelf(foo, IFoo) is foo)
        self.assertTrue(reg.queryAdapterOrSelf(bar, IFoo) is adaptation)

    def test__fix_registry_registerSelfAdapter(self):
        reg = DummyRegistry()
        config = self._makeOne(reg)
        config._fix_registry()
        reg.registerSelfAdapter('required', 'provided', name='abc')
        self.assertEqual(len(reg.adapters), 1)
        args, kw = reg.adapters[0]
        self.assertEqual(args[0]('abc'), 'abc')
        self.assertEqual(
            kw,
            {
                'info': '',
                'provided': 'provided',
                'required': 'required',
                'name': 'abc',
                'event': True,
            },
        )

    def test__fix_registry_adds__lock(self):
        reg = DummyRegistry()
        config = self._makeOne(reg)
        config._fix_registry()
        self.assertTrue(hasattr(reg, '_lock'))

    def test__fix_registry_adds_clear_view_lookup_cache(self):
        reg = DummyRegistry()
        config = self._makeOne(reg)
        self.assertFalse(hasattr(reg, '_clear_view_lookup_cache'))
        config._fix_registry()
        self.assertFalse(hasattr(reg, '_view_lookup_cache'))
        reg._clear_view_lookup_cache()
        self.assertEqual(reg._view_lookup_cache, {})

    def test_setup_registry_calls_fix_registry(self):
        reg = DummyRegistry()
        config = self._makeOne(reg)
        config.add_view = lambda *arg, **kw: False
        config._add_tween = lambda *arg, **kw: False
        config.setup_registry()
        self.assertEqual(reg.has_listeners, True)

    def test_setup_registry_registers_default_exceptionresponse_views(self):
        from webob.exc import WSGIHTTPException

        from pyramid.interfaces import IExceptionResponse
        from pyramid.view import default_exceptionresponse_view

        reg = DummyRegistry()
        config = self._makeOne(reg)
        views = []
        config.add_view = lambda *arg, **kw: views.append((arg, kw))
        config.add_default_view_predicates = lambda *arg: None
        config._add_tween = lambda *arg, **kw: False
        config.setup_registry()
        self.assertEqual(
            views[0],
            (
                (default_exceptionresponse_view,),
                {'context': IExceptionResponse},
            ),
        )
        self.assertEqual(
            views[1],
            (
                (default_exceptionresponse_view,),
                {'context': WSGIHTTPException},
            ),
        )

    def test_setup_registry_registers_default_view_predicates(self):
        reg = DummyRegistry()
        config = self._makeOne(reg)
        vp_called = []
        config.add_view = lambda *arg, **kw: None
        config.add_default_view_predicates = lambda *arg: vp_called.append(
            True
        )
        config._add_tween = lambda *arg, **kw: False
        config.setup_registry()
        self.assertTrue(vp_called)

    def test_setup_registry_registers_default_webob_iresponse_adapter(self):
        from webob import Response

        from pyramid.interfaces import IResponse

        config = self._makeOne()
        config.setup_registry()
        response = Response()
        self.assertTrue(
            config.registry.queryAdapter(response, IResponse) is response
        )

    def test_setup_registry_explicit_notfound_trumps_iexceptionresponse(self):
        from zope.interface import implementedBy

        from pyramid.httpexceptions import HTTPNotFound
        from pyramid.registry import Registry
        from pyramid.renderers import null_renderer

        reg = Registry()
        config = self._makeOne(reg, autocommit=True)
        config.setup_registry()  # registers IExceptionResponse default view

        def myview(context, request):
            return 'OK'

        config.add_view(myview, context=HTTPNotFound, renderer=null_renderer)
        request = self._makeRequest(config)
        view = self._getViewCallable(
            config,
            ctx_iface=implementedBy(HTTPNotFound),
            request_iface=IRequest,
        )
        result = view(None, request)
        self.assertEqual(result, 'OK')

    def test_setup_registry_custom_settings(self):
        from pyramid.interfaces import ISettings
        from pyramid.registry import Registry

        settings = {'reload_templates': True, 'mysetting': True}
        reg = Registry()
        config = self._makeOne(reg)
        config.setup_registry(settings=settings)
        settings = reg.getUtility(ISettings)
        self.assertEqual(settings['reload_templates'], True)
        self.assertEqual(settings['debug_authorization'], False)
        self.assertEqual(settings['mysetting'], True)

    def test_setup_registry_debug_logger_None_default(self):
        from pyramid.interfaces import IDebugLogger
        from pyramid.registry import Registry

        reg = Registry()
        config = self._makeOne(reg)
        config.setup_registry()
        logger = reg.getUtility(IDebugLogger)
        self.assertEqual(logger.name, 'tests.test_config')

    def test_setup_registry_debug_logger_non_None(self):
        from pyramid.interfaces import IDebugLogger
        from pyramid.registry import Registry

        logger = object()
        reg = Registry()
        config = self._makeOne(reg)
        config.setup_registry(debug_logger=logger)
        result = reg.getUtility(IDebugLogger)
        self.assertEqual(logger, result)

    def test_setup_registry_debug_logger_name(self):
        from pyramid.interfaces import IDebugLogger
        from pyramid.registry import Registry

        reg = Registry()
        config = self._makeOne(reg)
        config.setup_registry(debug_logger='foo')
        result = reg.getUtility(IDebugLogger)
        self.assertEqual(result.name, 'foo')

    def test_setup_registry_authentication_policy(self):
        from pyramid.interfaces import IAuthenticationPolicy
        from pyramid.registry import Registry

        policy = object()
        reg = Registry()
        config = self._makeOne(reg)
        config.setup_registry(authentication_policy=policy)
        config.commit()
        result = reg.getUtility(IAuthenticationPolicy)
        self.assertEqual(policy, result)

    def test_setup_registry_authentication_policy_dottedname(self):
        from pyramid.interfaces import IAuthenticationPolicy
        from pyramid.registry import Registry

        reg = Registry()
        config = self._makeOne(reg)
        config.setup_registry(authentication_policy='tests.test_config')
        config.commit()
        result = reg.getUtility(IAuthenticationPolicy)
        import tests.test_config

        self.assertEqual(result, tests.test_config)

    def test_setup_registry_authorization_policy_dottedname(self):
        from pyramid.interfaces import IAuthorizationPolicy
        from pyramid.registry import Registry

        reg = Registry()
        config = self._makeOne(reg)
        dummy = object()
        config.setup_registry(
            authentication_policy=dummy,
            authorization_policy='tests.test_config',
        )
        config.commit()
        result = reg.getUtility(IAuthorizationPolicy)
        import tests.test_config

        self.assertEqual(result, tests.test_config)

    def test_setup_registry_authorization_policy_only(self):
        from pyramid.registry import Registry

        policy = object()
        reg = Registry()
        config = self._makeOne(reg)
        config.setup_registry(authorization_policy=policy)
        config = self.assertRaises(ConfigurationExecutionError, config.commit)

    def test_setup_registry_no_default_root_factory(self):
        from pyramid.interfaces import IRootFactory
        from pyramid.registry import Registry

        reg = Registry()
        config = self._makeOne(reg)
        config.setup_registry()
        config.commit()
        self.assertEqual(reg.queryUtility(IRootFactory), None)

    def test_setup_registry_dottedname_root_factory(self):
        from pyramid.interfaces import IRootFactory
        from pyramid.registry import Registry

        reg = Registry()
        config = self._makeOne(reg)
        import tests.test_config

        config.setup_registry(root_factory='tests.test_config')
        self.assertEqual(reg.queryUtility(IRootFactory), None)
        config.commit()
        self.assertEqual(reg.getUtility(IRootFactory), tests.test_config)

    def test_setup_registry_locale_negotiator_dottedname(self):
        from pyramid.interfaces import ILocaleNegotiator
        from pyramid.registry import Registry

        reg = Registry()
        config = self._makeOne(reg)
        import tests.test_config

        config.setup_registry(locale_negotiator='tests.test_config')
        self.assertEqual(reg.queryUtility(ILocaleNegotiator), None)
        config.commit()
        utility = reg.getUtility(ILocaleNegotiator)
        self.assertEqual(utility, tests.test_config)

    def test_setup_registry_locale_negotiator(self):
        from pyramid.interfaces import ILocaleNegotiator
        from pyramid.registry import Registry

        reg = Registry()
        config = self._makeOne(reg)
        negotiator = object()
        config.setup_registry(locale_negotiator=negotiator)
        self.assertEqual(reg.queryUtility(ILocaleNegotiator), None)
        config.commit()
        utility = reg.getUtility(ILocaleNegotiator)
        self.assertEqual(utility, negotiator)

    def test_setup_registry_request_factory(self):
        from pyramid.interfaces import IRequestFactory
        from pyramid.registry import Registry

        reg = Registry()
        config = self._makeOne(reg)
        factory = object()
        config.setup_registry(request_factory=factory)
        self.assertEqual(reg.queryUtility(IRequestFactory), None)
        config.commit()
        utility = reg.getUtility(IRequestFactory)
        self.assertEqual(utility, factory)

    def test_setup_registry_response_factory(self):
        from pyramid.interfaces import IResponseFactory
        from pyramid.registry import Registry

        reg = Registry()
        config = self._makeOne(reg)
        factory = lambda r: object()
        config.setup_registry(response_factory=factory)
        self.assertEqual(reg.queryUtility(IResponseFactory), None)
        config.commit()
        utility = reg.getUtility(IResponseFactory)
        self.assertEqual(utility, factory)

    def test_setup_registry_request_factory_dottedname(self):
        from pyramid.interfaces import IRequestFactory
        from pyramid.registry import Registry

        reg = Registry()
        config = self._makeOne(reg)
        import tests.test_config

        config.setup_registry(request_factory='tests.test_config')
        self.assertEqual(reg.queryUtility(IRequestFactory), None)
        config.commit()
        utility = reg.getUtility(IRequestFactory)
        self.assertEqual(utility, tests.test_config)

    def test_setup_registry_alternate_renderers(self):
        from pyramid.interfaces import IRendererFactory
        from pyramid.registry import Registry

        renderer = object()
        reg = Registry()
        config = self._makeOne(reg)
        config.setup_registry(renderers=[('yeah', renderer)])
        config.commit()
        self.assertEqual(reg.getUtility(IRendererFactory, 'yeah'), renderer)

    def test_setup_registry_default_permission(self):
        from pyramid.interfaces import IDefaultPermission
        from pyramid.registry import Registry

        reg = Registry()
        config = self._makeOne(reg)
        config.setup_registry(default_permission='view')
        config.commit()
        self.assertEqual(reg.getUtility(IDefaultPermission), 'view')

    def test_setup_registry_includes(self):
        from pyramid.registry import Registry

        reg = Registry()
        config = self._makeOne(reg)
        settings = {
            'pyramid.includes': """tests.test_config.dummy_include
tests.test_config.dummy_include2"""
        }
        config.setup_registry(settings=settings)
        self.assertTrue(reg.included)
        self.assertTrue(reg.also_included)

    def test_setup_registry_includes_spaces(self):
        from pyramid.registry import Registry

        reg = Registry()
        config = self._makeOne(reg)
        settings = {
            'pyramid.includes': """tests.test_config.dummy_include tests.\
test_config.dummy_include2"""
        }
        config.setup_registry(settings=settings)
        self.assertTrue(reg.included)
        self.assertTrue(reg.also_included)

    def test_setup_registry_tweens(self):
        from pyramid.interfaces import ITweens
        from pyramid.registry import Registry

        reg = Registry()
        config = self._makeOne(reg)
        settings = {'pyramid.tweens': 'tests.test_config.dummy_tween_factory'}
        config.setup_registry(settings=settings)
        config.commit()
        tweens = config.registry.getUtility(ITweens)
        self.assertEqual(
            tweens.explicit,
            [('tests.test_config.dummy_tween_factory', dummy_tween_factory)],
        )

    def test_introspector_decorator(self):
        inst = self._makeOne()
        default = inst.introspector
        self.assertTrue(hasattr(default, 'add'))
        self.assertEqual(inst.introspector, inst.registry.introspector)
        introspector = object()
        inst.introspector = introspector
        new = inst.introspector
        self.assertTrue(new is introspector)
        self.assertEqual(inst.introspector, inst.registry.introspector)
        del inst.introspector
        default = inst.introspector
        self.assertFalse(default is new)
        self.assertTrue(hasattr(default, 'add'))

    def test_make_wsgi_app(self):
        import pyramid.config
        from pyramid.interfaces import IApplicationCreated
        from pyramid.router import Router

        manager = DummyThreadLocalManager()
        config = self._makeOne()
        subscriber = self._registerEventListener(config, IApplicationCreated)
        config.manager = manager
        app = config.make_wsgi_app()
        self.assertEqual(app.__class__, Router)
        self.assertEqual(manager.pushed['registry'], config.registry)
        self.assertEqual(manager.pushed['request'], None)
        self.assertTrue(manager.popped)
        self.assertEqual(pyramid.config.global_registries.last, app.registry)
        self.assertEqual(len(subscriber), 1)
        self.assertTrue(IApplicationCreated.providedBy(subscriber[0]))
        pyramid.config.global_registries.empty()

    def test_include_with_dotted_name(self):
        from tests import test_config

        config = self._makeOne()
        config.include('tests.test_config.dummy_include')
        after = config.action_state
        actions = after.actions
        self.assertEqual(len(actions), 1)
        action = after.actions[0]
        self.assertEqual(action['discriminator'], 'discrim')
        self.assertEqual(action['callable'], None)
        self.assertEqual(action['args'], test_config)

    def test_include_with_python_callable(self):
        from tests import test_config

        config = self._makeOne()
        config.include(dummy_include)
        after = config.action_state
        actions = after.actions
        self.assertEqual(len(actions), 1)
        action = actions[0]
        self.assertEqual(action['discriminator'], 'discrim')
        self.assertEqual(action['callable'], None)
        self.assertEqual(action['args'], test_config)

    def test_include_with_module_defaults_to_includeme(self):
        from tests import test_config

        config = self._makeOne()
        config.include('tests.test_config')
        after = config.action_state
        actions = after.actions
        self.assertEqual(len(actions), 1)
        action = actions[0]
        self.assertEqual(action['discriminator'], 'discrim')
        self.assertEqual(action['callable'], None)
        self.assertEqual(action['args'], test_config)

    def test_include_with_module_defaults_to_includeme_missing(self):
        from pyramid.exceptions import ConfigurationError

        config = self._makeOne()
        self.assertRaises(ConfigurationError, config.include, 'tests')

    def test_include_with_route_prefix(self):
        root_config = self._makeOne(autocommit=True)

        def dummy_subapp(config):
            self.assertEqual(config.route_prefix, 'root')

        root_config.include(dummy_subapp, route_prefix='root')

    def test_include_with_nested_route_prefix(self):
        root_config = self._makeOne(autocommit=True, route_prefix='root')

        def dummy_subapp2(config):
            self.assertEqual(config.route_prefix, 'root/nested')

        def dummy_subapp3(config):
            self.assertEqual(config.route_prefix, 'root/nested/nested2')
            config.include(dummy_subapp4)

        def dummy_subapp4(config):
            self.assertEqual(config.route_prefix, 'root/nested/nested2')

        def dummy_subapp(config):
            self.assertEqual(config.route_prefix, 'root/nested')
            config.include(dummy_subapp2)
            config.include(dummy_subapp3, route_prefix='nested2')

        root_config.include(dummy_subapp, route_prefix='nested')

    def test_include_with_missing_source_file(self):
        import inspect

        from pyramid.exceptions import ConfigurationError

        config = self._makeOne()

        class DummyInspect:
            def getmodule(self, c):
                return inspect.getmodule(c)

            def getsourcefile(self, c):
                return None

        config.inspect = DummyInspect()
        try:
            config.include('tests.test_config.dummy_include')
        except ConfigurationError as e:
            self.assertEqual(
                e.args[0],
                "No source file for module 'tests.test_config' (.py "
                "file must exist, refusing to use orphan .pyc or .pyo file).",
            )
        else:  # pragma: no cover
            raise AssertionError

    def test_include_constant_root_package(self):
        import tests
        from tests import test_config

        config = self._makeOne(root_package=tests)
        results = {}

        def include(config):
            results['package'] = config.package
            results['root_package'] = config.root_package

        config.include(include)
        self.assertEqual(results['root_package'], tests)
        self.assertEqual(results['package'], test_config)

    def test_include_threadlocals_active(self):
        from pyramid.threadlocal import get_current_registry

        stack = []

        def include(config):
            stack.append(get_current_registry())

        config = self._makeOne()
        config.include(include)
        self.assertTrue(stack[0] is config.registry)

    def test_scan_integration(self):
        from zope.interface import alsoProvides

        from pyramid.view import render_view_to_response
        from tests.test_config.pkgs import scannable as package

        config = self._makeOne(autocommit=True)
        config.scan(package)

        ctx = DummyContext()
        req = DummyRequest()
        alsoProvides(req, IRequest)
        req.registry = config.registry

        req.method = 'GET'
        result = render_view_to_response(ctx, req, '')
        self.assertEqual(result, 'grokked')

        req.method = 'POST'
        result = render_view_to_response(ctx, req, '')
        self.assertEqual(result, 'grokked_post')

        result = render_view_to_response(ctx, req, 'grokked_class')
        self.assertEqual(result, 'grokked_class')

        result = render_view_to_response(ctx, req, 'grokked_instance')
        self.assertEqual(result, 'grokked_instance')

        result = render_view_to_response(ctx, req, 'oldstyle_grokked_class')
        self.assertEqual(result, 'oldstyle_grokked_class')

        req.method = 'GET'
        result = render_view_to_response(ctx, req, 'another')
        self.assertEqual(result, 'another_grokked')

        req.method = 'POST'
        result = render_view_to_response(ctx, req, 'another')
        self.assertEqual(result, 'another_grokked_post')

        result = render_view_to_response(ctx, req, 'another_grokked_class')
        self.assertEqual(result, 'another_grokked_class')

        result = render_view_to_response(ctx, req, 'another_grokked_instance')
        self.assertEqual(result, 'another_grokked_instance')

        result = render_view_to_response(
            ctx, req, 'another_oldstyle_grokked_class'
        )
        self.assertEqual(result, 'another_oldstyle_grokked_class')

        result = render_view_to_response(ctx, req, 'stacked1')
        self.assertEqual(result, 'stacked')

        result = render_view_to_response(ctx, req, 'stacked2')
        self.assertEqual(result, 'stacked')

        result = render_view_to_response(ctx, req, 'another_stacked1')
        self.assertEqual(result, 'another_stacked')

        result = render_view_to_response(ctx, req, 'another_stacked2')
        self.assertEqual(result, 'another_stacked')

        result = render_view_to_response(ctx, req, 'stacked_class1')
        self.assertEqual(result, 'stacked_class')

        result = render_view_to_response(ctx, req, 'stacked_class2')
        self.assertEqual(result, 'stacked_class')

        result = render_view_to_response(ctx, req, 'another_stacked_class1')
        self.assertEqual(result, 'another_stacked_class')

        result = render_view_to_response(ctx, req, 'another_stacked_class2')
        self.assertEqual(result, 'another_stacked_class')

        # NB: on Jython, a class without an __init__ apparently accepts
        # any number of arguments without raising a TypeError, so the next
        # assertion may fail there.  We don't support Jython at the moment,
        # this is just a note to a future self.

        self.assertRaises(
            TypeError, render_view_to_response, ctx, req, 'basemethod'
        )

        result = render_view_to_response(ctx, req, 'method1')
        self.assertEqual(result, 'method1')

        result = render_view_to_response(ctx, req, 'method2')
        self.assertEqual(result, 'method2')

        result = render_view_to_response(ctx, req, 'stacked_method1')
        self.assertEqual(result, 'stacked_method')

        result = render_view_to_response(ctx, req, 'stacked_method2')
        self.assertEqual(result, 'stacked_method')

        result = render_view_to_response(ctx, req, 'subpackage_init')
        self.assertEqual(result, 'subpackage_init')

        result = render_view_to_response(ctx, req, 'subpackage_notinit')
        self.assertEqual(result, 'subpackage_notinit')

        result = render_view_to_response(ctx, req, 'subsubpackage_init')
        self.assertEqual(result, 'subsubpackage_init')

        result = render_view_to_response(ctx, req, 'pod_notinit')
        self.assertEqual(result, None)

    def test_scan_integration_with_ignore(self):
        from zope.interface import alsoProvides

        from pyramid.view import render_view_to_response
        from tests.test_config.pkgs import scannable as package

        config = self._makeOne(autocommit=True)
        config.scan(package, ignore='tests.test_config.pkgs.scannable.another')

        ctx = DummyContext()
        req = DummyRequest()
        alsoProvides(req, IRequest)
        req.registry = config.registry

        req.method = 'GET'
        result = render_view_to_response(ctx, req, '')
        self.assertEqual(result, 'grokked')

        # ignored
        v = render_view_to_response(ctx, req, 'another_stacked_class2')
        self.assertEqual(v, None)

    def test_scan_integration_dottedname_package(self):
        from zope.interface import alsoProvides

        from pyramid.view import render_view_to_response

        config = self._makeOne(autocommit=True)
        config.scan('tests.test_config.pkgs.scannable')

        ctx = DummyContext()
        req = DummyRequest()
        alsoProvides(req, IRequest)
        req.registry = config.registry

        req.method = 'GET'
        result = render_view_to_response(ctx, req, '')
        self.assertEqual(result, 'grokked')

    def test_scan_integration_with_extra_kw(self):
        config = self._makeOne(autocommit=True)
        config.scan('tests.test_config.pkgs.scanextrakw', a=1, categories=None)
        self.assertEqual(config.a, 1)

    def test_scan_integration_with_onerror(self):
        # fancy sys.path manipulation here to appease "setup.py test" which
        # fails miserably when it can't import something in the package
        import sys

        try:
            here = os.path.dirname(__file__)
            path = os.path.join(here, 'path')
            sys.path.append(path)
            config = self._makeOne(autocommit=True)

            class FooException(Exception):
                pass

            def onerror(name):
                raise FooException

            self.assertRaises(
                FooException, config.scan, 'scanerror', onerror=onerror
            )
        finally:
            sys.path.remove(path)

    def test_scan_integration_conflict(self):
        from pyramid.config import Configurator
        from tests.test_config.pkgs import selfscan

        c = Configurator()
        c.scan(selfscan)
        c.scan(selfscan)
        try:
            c.commit()
        except ConfigurationConflictError as why:

            def scanconflicts(e):
                conflicts = e._conflicts.values()
                for conflict in conflicts:
                    for confinst in conflict:
                        yield confinst.src

            which = list(scanconflicts(why))
            self.assertEqual(len(which), 4)
            self.assertTrue("@view_config(renderer='string')" in which)
            self.assertTrue(
                "@view_config(name='two', renderer='string')" in which
            )

    def test_hook_zca(self):
        from zope.component import getSiteManager

        def foo():
            '123'

        try:
            config = self._makeOne()
            config.hook_zca()
            config.begin()
            sm = getSiteManager()
            self.assertEqual(sm, config.registry)
        finally:
            getSiteManager.reset()

    def test_unhook_zca(self):
        from zope.component import getSiteManager

        def foo():
            '123'

        try:
            getSiteManager.sethook(foo)
            config = self._makeOne()
            config.unhook_zca()
            sm = getSiteManager()
            self.assertNotEqual(sm, '123')
        finally:
            getSiteManager.reset()

    def test___getattr__missing_when_directives_exist(self):
        config = self._makeOne()
        directives = {}
        config.registry._directives = directives
        self.assertRaises(AttributeError, config.__getattr__, 'wontexist')

    def test___getattr__missing_when_directives_dont_exist(self):
        config = self._makeOne()
        self.assertRaises(AttributeError, config.__getattr__, 'wontexist')

    def test___getattr__matches(self):
        config = self._makeOne()

        def foo(config):  # pragma: no cover
            pass

        directives = {'foo': (foo, True)}
        config.registry._directives = directives
        foo_meth = config.foo
        self.assertTrue(getattr(foo_meth, '__func__').__docobj__ is foo)

    def test___getattr__matches_no_action_wrap(self):
        config = self._makeOne()

        def foo(config):  # pragma: no cover
            pass

        directives = {'foo': (foo, False)}
        config.registry._directives = directives
        foo_meth = config.foo
        self.assertTrue(getattr(foo_meth, '__func__') is foo)


class TestConfigurator_add_directive(unittest.TestCase):
    def setUp(self):
        from pyramid.config import Configurator

        self.config = Configurator()

    def test_extend_with_dotted_name(self):
        from tests import test_config

        config = self.config
        config.add_directive('dummy_extend', 'tests.test_config.dummy_extend')
        self.assertTrue(hasattr(config, 'dummy_extend'))
        config.dummy_extend('discrim')
        after = config.action_state
        action = after.actions[-1]
        self.assertEqual(action['discriminator'], 'discrim')
        self.assertEqual(action['callable'], None)
        self.assertEqual(action['args'], test_config)

    def test_add_directive_with_partial(self):
        from tests import test_config

        config = self.config
        config.add_directive(
            'dummy_partial', 'tests.test_config.dummy_partial'
        )
        self.assertTrue(hasattr(config, 'dummy_partial'))
        config.dummy_partial()
        after = config.action_state
        action = after.actions[-1]
        self.assertEqual(action['discriminator'], 'partial')
        self.assertEqual(action['callable'], None)
        self.assertEqual(action['args'], test_config)

    def test_add_directive_with_custom_callable(self):
        from tests import test_config

        config = self.config
        config.add_directive(
            'dummy_callable', 'tests.test_config.dummy_callable'
        )
        self.assertTrue(hasattr(config, 'dummy_callable'))
        config.dummy_callable('discrim')
        after = config.action_state
        action = after.actions[-1]
        self.assertEqual(action['discriminator'], 'discrim')
        self.assertEqual(action['callable'], None)
        self.assertEqual(action['args'], test_config)

    def test_extend_with_python_callable(self):
        from tests import test_config

        config = self.config
        config.add_directive('dummy_extend', dummy_extend)
        self.assertTrue(hasattr(config, 'dummy_extend'))
        config.dummy_extend('discrim')
        after = config.action_state
        action = after.actions[-1]
        self.assertEqual(action['discriminator'], 'discrim')
        self.assertEqual(action['callable'], None)
        self.assertEqual(action['args'], test_config)

    def test_extend_same_name_doesnt_conflict(self):
        config = self.config
        config.add_directive('dummy_extend', dummy_extend)
        config.add_directive('dummy_extend', dummy_extend2)
        self.assertTrue(hasattr(config, 'dummy_extend'))
        config.dummy_extend('discrim')
        after = config.action_state
        action = after.actions[-1]
        self.assertEqual(action['discriminator'], 'discrim')
        self.assertEqual(action['callable'], None)
        self.assertEqual(action['args'], config.registry)

    def test_extend_action_method_successful(self):
        config = self.config
        config.add_directive('dummy_extend', dummy_extend)
        config.dummy_extend('discrim')
        config.dummy_extend('discrim')
        self.assertRaises(ConfigurationConflictError, config.commit)

    def test_directive_persists_across_configurator_creations(self):
        config = self.config
        config.add_directive('dummy_extend', dummy_extend)
        config2 = config.with_package('tests')
        config2.dummy_extend('discrim')
        after = config2.action_state
        actions = after.actions
        self.assertEqual(len(actions), 1)
        action = actions[0]
        self.assertEqual(action['discriminator'], 'discrim')
        self.assertEqual(action['callable'], None)
        self.assertEqual(action['args'], config2.package)


class TestConfigurator__add_predicate(unittest.TestCase):
    def _makeOne(self):
        from pyramid.config import Configurator

        return Configurator()

    def test_factory_as_object(self):
        config = self._makeOne()

        def _fakeAction(
            discriminator,
            callable=None,
            args=(),
            kw=None,
            order=0,
            introspectables=(),
            **extra
        ):
            self.assertEqual(len(introspectables), 1)
            self.assertEqual(introspectables[0]['name'], 'testing')
            self.assertEqual(introspectables[0]['factory'], DummyPredicate)

        config.action = _fakeAction
        config._add_predicate('route', 'testing', DummyPredicate)

    def test_factory_as_dotted_name(self):
        config = self._makeOne()

        def _fakeAction(
            discriminator,
            callable=None,
            args=(),
            kw=None,
            order=0,
            introspectables=(),
            **extra
        ):
            self.assertEqual(len(introspectables), 1)
            self.assertEqual(introspectables[0]['name'], 'testing')
            self.assertEqual(introspectables[0]['factory'], DummyPredicate)

        config.action = _fakeAction
        config._add_predicate(
            'route', 'testing', 'tests.test_config.test_init.DummyPredicate'
        )


class TestGlobalRegistriesIntegration(unittest.TestCase):
    def setUp(self):
        from pyramid.config import global_registries

        global_registries.empty()

    tearDown = setUp

    def _makeConfigurator(self, *arg, **kw):
        from pyramid.config import Configurator

        config = Configurator(*arg, **kw)
        return config

    def test_global_registries_empty(self):
        from pyramid.config import global_registries

        self.assertEqual(global_registries.last, None)

    def test_global_registries(self):
        from pyramid.config import global_registries

        config1 = self._makeConfigurator()
        config1.make_wsgi_app()
        self.assertEqual(global_registries.last, config1.registry)
        config2 = self._makeConfigurator()
        config2.make_wsgi_app()
        self.assertEqual(global_registries.last, config2.registry)
        self.assertEqual(
            list(global_registries), [config1.registry, config2.registry]
        )
        global_registries.remove(config2.registry)
        self.assertEqual(global_registries.last, config1.registry)


class DummyRequest:
    subpath = ()
    matchdict = None
    request_iface = IRequest

    def __init__(self, environ=None):
        if environ is None:
            environ = {}
        self.environ = environ
        self.params = {}
        self.cookies = {}


class DummyThreadLocalManager:
    def __init__(self):
        self.pushed = {'registry': None, 'request': None}
        self.popped = False

    def push(self, d):
        self.pushed = d

    def get(self):
        return self.pushed

    def pop(self):
        self.popped = True


class DummyRegistry:
    def __init__(self, adaptation=None, util=None):
        self.utilities = []
        self.adapters = []
        self.adaptation = adaptation
        self.util = util

    def subscribers(self, events, name):
        self.events = events
        return events

    def registerUtility(self, *arg, **kw):
        self.utilities.append((arg, kw))

    def registerAdapter(self, *arg, **kw):
        self.adapters.append((arg, kw))

    def queryAdapter(self, *arg, **kw):
        return self.adaptation

    def queryUtility(self, *arg, **kw):
        return self.util


class DummyPredicate:
    pass
