~bzr-pqm/bzr/bzr.dev

3948.3.3 by Martin Pool
merge trunk
1
# Copyright (C) 2007, 2009 Canonical Ltd
2553.1.1 by Robert Collins
Give Hooks names.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2553.1.1 by Robert Collins
Give Hooks names.
16
17
"""Tests for the core Hooks logic."""
18
4119.3.1 by Robert Collins
Create a single registry of all Hooks classes, removing the test suite knowledge of such hooks and allowing plugins to sensibly and safely define new hooks.
19
from bzrlib import branch, errors
2553.1.1 by Robert Collins
Give Hooks names.
20
from bzrlib.hooks import (
4098.2.2 by Robert Collins
Review feedback.
21
    HookPoint,
2553.1.1 by Robert Collins
Give Hooks names.
22
    Hooks,
4119.3.1 by Robert Collins
Create a single registry of all Hooks classes, removing the test suite knowledge of such hooks and allowing plugins to sensibly and safely define new hooks.
23
    known_hooks,
24
    known_hooks_key_to_object,
25
    known_hooks_key_to_parent_and_attribute,
2553.1.1 by Robert Collins
Give Hooks names.
26
    )
27
from bzrlib.errors import (
28
    UnknownHook,
29
    )
30
31
from bzrlib.tests import TestCase
32
33
34
class TestHooks(TestCase):
35
4098.2.1 by Robert Collins
Allow self documenting hooks.
36
    def test_create_hook_first(self):
37
        hooks = Hooks()
38
        doc = ("Invoked after changing the tip of a branch object. Called with"
39
            "a bzrlib.branch.PostChangeBranchTipParams object")
4098.2.2 by Robert Collins
Review feedback.
40
        hook = HookPoint("post_tip_change", doc, (0, 15), None)
4098.2.1 by Robert Collins
Allow self documenting hooks.
41
        hooks.create_hook(hook)
42
        self.assertEqual(hook, hooks['post_tip_change'])
43
44
    def test_create_hook_name_collision_errors(self):
45
        hooks = Hooks()
46
        doc = ("Invoked after changing the tip of a branch object. Called with"
47
            "a bzrlib.branch.PostChangeBranchTipParams object")
4098.2.2 by Robert Collins
Review feedback.
48
        hook = HookPoint("post_tip_change", doc, (0, 15), None)
49
        hook2 = HookPoint("post_tip_change", None, None, None)
4098.2.1 by Robert Collins
Allow self documenting hooks.
50
        hooks.create_hook(hook)
51
        self.assertRaises(errors.DuplicateKey, hooks.create_hook, hook2)
52
        self.assertEqual(hook, hooks['post_tip_change'])
53
54
    def test_docs(self):
55
        """docs() should return something reasonable about the Hooks."""
4108.3.1 by Robert Collins
Include the Hooks class in the Hooks docs.
56
        class MyHooks(Hooks):
57
            pass
58
        hooks = MyHooks()
4098.2.1 by Robert Collins
Allow self documenting hooks.
59
        hooks['legacy'] = []
4098.2.2 by Robert Collins
Review feedback.
60
        hook1 = HookPoint('post_tip_change',
4098.2.1 by Robert Collins
Allow self documenting hooks.
61
            "Invoked after the tip of a branch changes. Called with "
62
            "a ChangeBranchTipParams object.", (1, 4), None)
4098.2.2 by Robert Collins
Review feedback.
63
        hook2 = HookPoint('pre_tip_change',
4098.2.1 by Robert Collins
Allow self documenting hooks.
64
            "Invoked before the tip of a branch changes. Called with "
65
            "a ChangeBranchTipParams object. Hooks should raise "
66
            "TipChangeRejected to signal that a tip change is not permitted.",
67
            (1, 6), None)
68
        hooks.create_hook(hook1)
69
        hooks.create_hook(hook2)
4108.3.1 by Robert Collins
Include the Hooks class in the Hooks docs.
70
        self.assertEqualDiff(
71
            "MyHooks\n"
4119.3.2 by Robert Collins
Migrate existing hooks over to the new HookPoint infrastructure.
72
            "-------\n"
4108.3.1 by Robert Collins
Include the Hooks class in the Hooks docs.
73
            "\n"
4098.2.1 by Robert Collins
Allow self documenting hooks.
74
            "legacy\n"
4119.3.2 by Robert Collins
Migrate existing hooks over to the new HookPoint infrastructure.
75
            "~~~~~~\n"
4098.2.1 by Robert Collins
Allow self documenting hooks.
76
            "\n"
4108.3.1 by Robert Collins
Include the Hooks class in the Hooks docs.
77
            "An old-style hook. For documentation see the __init__ method of 'MyHooks'\n"
4098.2.1 by Robert Collins
Allow self documenting hooks.
78
            "\n"
79
            "post_tip_change\n"
4119.3.2 by Robert Collins
Migrate existing hooks over to the new HookPoint infrastructure.
80
            "~~~~~~~~~~~~~~~\n"
4098.2.1 by Robert Collins
Allow self documenting hooks.
81
            "\n"
82
            "Introduced in: 1.4\n"
83
            "\n"
84
            "Invoked after the tip of a branch changes. Called with a\n"
85
            "ChangeBranchTipParams object.\n"
86
            "\n"
87
            "pre_tip_change\n"
4119.3.2 by Robert Collins
Migrate existing hooks over to the new HookPoint infrastructure.
88
            "~~~~~~~~~~~~~~\n"
4098.2.1 by Robert Collins
Allow self documenting hooks.
89
            "\n"
90
            "Introduced in: 1.6\n"
91
            "\n"
92
            "Invoked before the tip of a branch changes. Called with a\n"
93
            "ChangeBranchTipParams object. Hooks should raise TipChangeRejected to\n"
94
            "signal that a tip change is not permitted.\n", hooks.docs())
95
3256.2.4 by Daniel Watkins
Modified tests to reflect install_named_hook becoming a separate method.
96
    def test_install_named_hook_raises_unknown_hook(self):
97
        hooks = Hooks()
98
        self.assertRaises(UnknownHook, hooks.install_named_hook, 'silly',
99
                          None, "")
100
101
    def test_install_named_hook_appends_known_hook(self):
102
        hooks = Hooks()
3256.2.32 by Ian Clatworthy
tweak hook tests to init the set_rh test when needed
103
        hooks['set_rh'] = []
3256.2.4 by Daniel Watkins
Modified tests to reflect install_named_hook becoming a separate method.
104
        hooks.install_named_hook('set_rh', None, "demo")
105
        self.assertEqual(hooks['set_rh'], [None])
106
107
    def test_install_named_hook_and_retrieve_name(self):
108
        hooks = Hooks()
3256.2.32 by Ian Clatworthy
tweak hook tests to init the set_rh test when needed
109
        hooks['set_rh'] = []
3256.2.4 by Daniel Watkins
Modified tests to reflect install_named_hook becoming a separate method.
110
        hooks.install_named_hook('set_rh', None, "demo")
3256.2.1 by Daniel Watkins
Added tests from Hooks.install_hook with an optional name parameter.
111
        self.assertEqual("demo", hooks.get_hook_name(None))
112
4098.2.1 by Robert Collins
Allow self documenting hooks.
113
114
class TestHook(TestCase):
115
116
    def test___init__(self):
117
        doc = ("Invoked after changing the tip of a branch object. Called with"
118
            "a bzrlib.branch.PostChangeBranchTipParams object")
4098.2.2 by Robert Collins
Review feedback.
119
        hook = HookPoint("post_tip_change", doc, (0, 15), None)
4098.2.1 by Robert Collins
Allow self documenting hooks.
120
        self.assertEqual(doc, hook.__doc__)
121
        self.assertEqual("post_tip_change", hook.name)
122
        self.assertEqual((0, 15), hook.introduced)
123
        self.assertEqual(None, hook.deprecated)
124
        self.assertEqual([], list(hook))
125
126
    def test_docs(self):
127
        doc = ("Invoked after changing the tip of a branch object. Called with"
128
            " a bzrlib.branch.PostChangeBranchTipParams object")
4098.2.2 by Robert Collins
Review feedback.
129
        hook = HookPoint("post_tip_change", doc, (0, 15), None)
4098.2.1 by Robert Collins
Allow self documenting hooks.
130
        self.assertEqual("post_tip_change\n"
4119.3.2 by Robert Collins
Migrate existing hooks over to the new HookPoint infrastructure.
131
            "~~~~~~~~~~~~~~~\n"
4098.2.1 by Robert Collins
Allow self documenting hooks.
132
            "\n"
133
            "Introduced in: 0.15\n"
134
            "\n"
135
            "Invoked after changing the tip of a branch object. Called with a\n"
136
            "bzrlib.branch.PostChangeBranchTipParams object\n", hook.docs())
137
138
    def test_hook(self):
4098.2.2 by Robert Collins
Review feedback.
139
        hook = HookPoint("foo", "no docs", None, None)
4098.2.1 by Robert Collins
Allow self documenting hooks.
140
        def callback():
141
            pass
142
        hook.hook(callback, "my callback")
143
        self.assertEqual([callback], list(hook))
144
145
    def test___repr(self):
146
        # The repr should list all the callbacks, with names.
4098.2.2 by Robert Collins
Review feedback.
147
        hook = HookPoint("foo", "no docs", None, None)
4098.2.1 by Robert Collins
Allow self documenting hooks.
148
        def callback():
149
            pass
150
        hook.hook(callback, "my callback")
151
        callback_repr = repr(callback)
152
        self.assertEqual(
4098.2.2 by Robert Collins
Review feedback.
153
            '<HookPoint(foo), callbacks=[%s(my callback)]>' %
4098.2.1 by Robert Collins
Allow self documenting hooks.
154
            callback_repr, repr(hook))
4119.3.1 by Robert Collins
Create a single registry of all Hooks classes, removing the test suite knowledge of such hooks and allowing plugins to sensibly and safely define new hooks.
155
156
157
class TestHookRegistry(TestCase):
158
159
    def test_items_are_reasonable_keys(self):
160
        # All the items in the known_hooks registry need to map from
161
        # (module_name, member_name) tuples to the callable used to get an
4230.1.2 by James Westby
Update the comments based on those in the test.
162
        # empty Hooks for that attribute. This is used to support the test
4119.3.1 by Robert Collins
Create a single registry of all Hooks classes, removing the test suite knowledge of such hooks and allowing plugins to sensibly and safely define new hooks.
163
        # suite which needs to generate empty hooks (and HookPoints) to ensure
164
        # isolation and prevent tests failing spuriously.
165
        for key, factory in known_hooks.items():
166
            self.assertTrue(callable(factory),
167
                "The factory(%r) for %r is not callable" % (factory, key))
168
            obj = known_hooks_key_to_object(key)
169
            self.assertIsInstance(obj, Hooks)
170
            new_hooks = factory()
171
            self.assertIsInstance(obj, Hooks)
172
            self.assertEqual(type(obj), type(new_hooks))
173
174
    def test_known_hooks_key_to_object(self):
175
        self.assertIs(branch.Branch.hooks,
176
            known_hooks_key_to_object(('bzrlib.branch', 'Branch.hooks')))
177
178
    def test_known_hooks_key_to_parent_and_attribute(self):
179
        self.assertEqual((branch.Branch, 'hooks'),
180
            known_hooks_key_to_parent_and_attribute(
181
            ('bzrlib.branch', 'Branch.hooks')))
182
        self.assertEqual((branch, 'Branch'),
183
            known_hooks_key_to_parent_and_attribute(
184
            ('bzrlib.branch', 'Branch')))