blob: 4eb292443627d697c4a659713b28d7e58981253f [file] [log] [blame]
# -*- coding: utf-8 -*-
#
# Copyright (C)2005-2009 Edgewall Software
# Copyright (C) 2005 Christopher Lenz <cmlenz@gmx.de>
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://trac.edgewall.org/wiki/TracLicense.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://trac.edgewall.org/log/.
#
# Author: Christopher Lenz <cmlenz@gmx.de>
from trac.core import *
import unittest
class ITest(Interface):
def test():
"""Dummy function."""
class IOtherTest(Interface):
def other_test():
"""Other dummy function."""
class ComponentTestCase(unittest.TestCase):
def setUp(self):
from trac.core import ComponentManager, ComponentMeta
self.compmgr = ComponentManager()
# Make sure we have no external components hanging around in the
# component registry
self.old_registry = ComponentMeta._registry
ComponentMeta._registry = {}
def tearDown(self):
# Restore the original component registry
from trac.core import ComponentMeta
ComponentMeta._registry = self.old_registry
def test_base_class_not_registered(self):
"""
Make sure that the Component base class does not appear in the component
registry.
"""
from trac.core import ComponentMeta
assert Component not in ComponentMeta._components
self.assertRaises(TracError, self.compmgr.__getitem__, Component)
def test_abstract_component_not_registered(self):
"""
Make sure that a Component class marked as abstract does not appear in
the component registry.
"""
from trac.core import ComponentMeta
class AbstractComponent(Component):
abstract = True
assert AbstractComponent not in ComponentMeta._components
self.assertRaises(TracError, self.compmgr.__getitem__,
AbstractComponent)
def test_unregistered_component(self):
"""
Make sure the component manager refuses to manage classes not derived
from `Component`.
"""
class NoComponent(object):
pass
self.assertRaises(TracError, self.compmgr.__getitem__, NoComponent)
def test_component_registration(self):
"""
Verify that classes derived from `Component` are managed by the
component manager.
"""
class ComponentA(Component):
pass
assert self.compmgr[ComponentA]
assert ComponentA(self.compmgr)
def test_component_identity(self):
"""
Make sure instantiating a component multiple times just returns the
same instance again.
"""
class ComponentA(Component):
pass
c1 = ComponentA(self.compmgr)
c2 = ComponentA(self.compmgr)
assert c1 is c2, 'Expected same component instance'
c2 = self.compmgr[ComponentA]
assert c1 is c2, 'Expected same component instance'
def test_component_initializer(self):
"""
Makes sure that a components' `__init__` method gets called.
"""
class ComponentA(Component):
def __init__(self):
self.data = 'test'
self.assertEqual('test', ComponentA(self.compmgr).data)
ComponentA(self.compmgr).data = 'newtest'
self.assertEqual('newtest', ComponentA(self.compmgr).data)
def test_inherited_component_initializer(self):
"""
Makes sure that a the `__init__` method of a components' super-class
gets called if the component doesn't override it.
"""
class ComponentA(Component):
def __init__(self):
self.data = 'foo'
class ComponentB(ComponentA):
def __init__(self):
self.data = 'bar'
class ComponentC(ComponentB):
pass
self.assertEqual('bar', ComponentC(self.compmgr).data)
ComponentC(self.compmgr).data = 'baz'
self.assertEqual('baz', ComponentC(self.compmgr).data)
def test_implements_called_outside_classdef(self):
"""
Verify that calling implements() outside a class definition raises an
`AssertionError`.
"""
try:
implements()
except AssertionError:
pass
else:
self.fail('Expected AssertionError')
def test_implements_multiple(self):
"""
Verify that a component "implementing" an interface more than once
(e.g. through inheritance) is not called more than once from an
extension point.
"""
log = []
class Parent(Component):
abstract = True
implements(ITest)
class Child(Parent):
implements(ITest)
def test(self):
log.append("call")
class Other(Component):
tests = ExtensionPoint(ITest)
for test in Other(self.compmgr).tests:
test.test()
self.assertEqual(["call"], log)
def test_attribute_access(self):
"""
Verify that accessing undefined attributes on components raises an
`AttributeError`.
"""
class ComponentA(Component):
pass
comp = ComponentA(self.compmgr)
try:
comp.foo
self.fail('Expected AttributeError')
except AttributeError:
pass
def test_nonconforming_extender(self):
"""
Verify that accessing a method of a declared extension point interface
raises a normal `AttributeError` if the component does not implement
the method.
"""
class ComponentA(Component):
tests = ExtensionPoint(ITest)
class ComponentB(Component):
implements(ITest)
tests = iter(ComponentA(self.compmgr).tests)
try:
tests.next().test()
self.fail('Expected AttributeError')
except AttributeError:
pass
def test_extension_point_with_no_extension(self):
"""
Verify that accessing an extension point with no extenders returns an
empty list.
"""
class ComponentA(Component):
tests = ExtensionPoint(ITest)
tests = iter(ComponentA(self.compmgr).tests)
self.assertRaises(StopIteration, tests.next)
def test_extension_point_with_one_extension(self):
"""
Verify that a single component extending an extension point can be
accessed through the extension point attribute of the declaring
component.
"""
class ComponentA(Component):
tests = ExtensionPoint(ITest)
class ComponentB(Component):
implements(ITest)
def test(self):
return 'x'
tests = iter(ComponentA(self.compmgr).tests)
self.assertEquals('x', tests.next().test())
self.assertRaises(StopIteration, tests.next)
def test_extension_point_with_two_extensions(self):
"""
Verify that two components extending an extension point can be accessed
through the extension point attribute of the declaring component.
"""
class ComponentA(Component):
tests = ExtensionPoint(ITest)
class ComponentB(Component):
implements(ITest)
def test(self):
return 'x'
class ComponentC(Component):
implements(ITest)
def test(self):
return 'y'
results = [test.test() for test in ComponentA(self.compmgr).tests]
self.assertEquals(['x', 'y'], sorted(results))
def test_inherited_extension_point(self):
"""
Verify that extension points are inherited to sub-classes.
"""
class BaseComponent(Component):
tests = ExtensionPoint(ITest)
class ConcreteComponent(BaseComponent):
pass
class ExtendingComponent(Component):
implements(ITest)
def test(self):
return 'x'
tests = iter(ConcreteComponent(self.compmgr).tests)
self.assertEquals('x', tests.next().test())
self.assertRaises(StopIteration, tests.next)
def test_inherited_implements(self):
"""
Verify that a component with a super-class implementing an extension
point interface is also registered as implementing that interface.
"""
class BaseComponent(Component):
implements(ITest)
abstract = True
class ConcreteComponent(BaseComponent):
pass
from trac.core import ComponentMeta
assert ConcreteComponent in ComponentMeta._registry.get(ITest, [])
def test_inherited_implements_multilevel(self):
"""
Verify that extension point interfaces are inherited for more than
one level of inheritance.
"""
class BaseComponent(Component):
implements(ITest)
abstract = True
class ChildComponent(BaseComponent):
implements(IOtherTest)
abstract = True
class ConcreteComponent(ChildComponent):
pass
from trac.core import ComponentMeta
assert ConcreteComponent in ComponentMeta._registry.get(ITest, [])
assert ConcreteComponent in ComponentMeta._registry.get(IOtherTest, [])
def test_component_manager_component(self):
"""
Verify that a component manager can itself be a component with its own
extension points.
"""
from trac.core import ComponentManager
class ManagerComponent(ComponentManager, Component):
tests = ExtensionPoint(ITest)
def __init__(self, foo, bar):
ComponentManager.__init__(self)
self.foo, self.bar = foo, bar
class Extender(Component):
implements(ITest)
def test(self):
return 'x'
mgr = ManagerComponent('Test', 42)
assert id(mgr) == id(mgr[ManagerComponent])
tests = iter(mgr.tests)
self.assertEquals('x', tests.next().test())
self.assertRaises(StopIteration, tests.next)
def test_instantiation_doesnt_enable(self):
"""
Make sure that a component disabled by the ComponentManager is not
implicitly enabled by instantiating it directly.
"""
from trac.core import ComponentManager
class DisablingComponentManager(ComponentManager):
def is_component_enabled(self, cls):
return False
class ComponentA(Component):
pass
mgr = DisablingComponentManager()
instance = ComponentA(mgr)
self.assertEqual(None, mgr[ComponentA])
def suite():
return unittest.makeSuite(ComponentTestCase, 'test')
if __name__ == '__main__':
unittest.main()