~justas.sadzevicius/schooltool/traversers

« back to all changes in this revision

Viewing changes to src/schooltool/testing/mock.py

  • Committer: Justas Sadzevicius
  • Date: 2011-03-01 14:16:23 UTC
  • Revision ID: justas@pov.lt-20110301141623-umrbsn1hyzzffi3b
Testing helpers to create and populate fake modules.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
2
# SchoolTool - common information systems platform for school administration
 
3
# Copyright (c) 2010 Shuttleworth Foundation
 
4
#
 
5
# This program is free software; you can redistribute it and/or modify
 
6
# it under the terms of the GNU General Public License as published by
 
7
# the Free Software Foundation; either version 2 of the License, or
 
8
# (at your option) any later version.
 
9
#
 
10
# This program is distributed in the hope that it will be useful,
 
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
# GNU General Public License for more details.
 
14
#
 
15
# You should have received a copy of the GNU General Public License
 
16
# along with this program; if not, write to the Free Software
 
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
#
 
19
 
 
20
import sys, imp
 
21
 
 
22
from zope.testing import cleanup
 
23
 
 
24
 
 
25
class ModulesSnapshot(object):
 
26
 
 
27
    def __init__(self):
 
28
        self.originals = dict(sys.modules)
 
29
        self.faked_attrs = {}
 
30
 
 
31
    def mock(self, values):
 
32
        """Usage:
 
33
        mock({'my.module.Foo': FooClass,
 
34
              'my.module.another.GLOBAL_VAL': 1,
 
35
              })
 
36
        """
 
37
        for full_name in sorted(values):
 
38
            names = full_name.split('.')
 
39
            attr_name = names[-1]
 
40
            module_name = '.'.join(names[:-1])
 
41
            assert module_name
 
42
            self.mock_attr(module_name, attr_name, fake=values[full_name])
 
43
 
 
44
    def mock_attr(self, modulename, name, fake=None):
 
45
        module = self.get_module(modulename)
 
46
        if modulename not in self.faked_attrs:
 
47
            self.faked_attrs[modulename] = {
 
48
                'injected': [],
 
49
                'replaced': {},
 
50
                }
 
51
        faked = self.faked_attrs[modulename]
 
52
        if hasattr(module, name):
 
53
            if (name not in faked['injected'] and
 
54
                name not in faked['replaced']):
 
55
                faked['replaced'][name] = getattr(module, name)
 
56
        else:
 
57
            faked['injected'].append(name)
 
58
        setattr(module, name, fake)
 
59
 
 
60
    def mock_module(self, modulename, fake=None):
 
61
        if fake is None:
 
62
            fake = imp.new_module(modulename)
 
63
        names = modulename.split('.')
 
64
        this_name = names[-1]
 
65
        parent_name = '.'.join(names[:-1])
 
66
        if parent_name:
 
67
            self.mock_attr(parent_name, this_name, fake)
 
68
        sys.modules[modulename] = fake
 
69
 
 
70
    def get_module(self, modulename):
 
71
        try:
 
72
            sys.modules[modulename]
 
73
        except:
 
74
            self.mock_module(modulename)
 
75
        return sys.modules[modulename]
 
76
 
 
77
    def restore(self):
 
78
        for module_name, faked in self.faked_attrs.items():
 
79
            try:
 
80
                module = sys.modules[module_name]
 
81
            except:
 
82
                continue
 
83
            for name in faked['injected']:
 
84
                del module.__dict__[name]
 
85
            for name, old_value in faked['replaced'].items():
 
86
                setattr(module, name, old_value)
 
87
 
 
88
        for name in list(sys.modules):
 
89
            if name not in self.originals:
 
90
                del sys.modules[name]
 
91
            else:
 
92
                sys.modules[name] = self.originals[name]
 
93
 
 
94
 
 
95
_snapshot = None
 
96
 
 
97
def getSnapshot():
 
98
    global _snapshot
 
99
    if _snapshot is None:
 
100
        _snapshot = ModulesSnapshot()
 
101
    return _snapshot
 
102
 
 
103
def restoreModules():
 
104
    global _snapshot
 
105
    if _snapshot is not None:
 
106
        _snapshot.restore()
 
107
        _snapshot = None
 
108
 
 
109
 
 
110
cleanup.addCleanUp(restoreModules)
 
111
 
 
112
 
 
113
def module(module_name):
 
114
    """A decorator to put method or class to the given module."""
 
115
    snapshot = getSnapshot()
 
116
    if type(module_name) == type(sys):
 
117
        module_name = module_name.__name__
 
118
    def mock_something(something):
 
119
        name = getattr(something, '__name__', None)
 
120
        snapshot.mock_attr(module_name, name, fake=something)
 
121
        return something
 
122
    return mock_something
 
123
 
 
124
 
 
125
def fake_global(module_name, name, value):
 
126
    """Set a global variable to a module."""
 
127
    snapshot = getSnapshot()
 
128
    if type(module_name) == type(sys):
 
129
        module_name = module_name.__name__
 
130
    snapshot.mock_attr(module_name, name, fake=value)
 
131
 
 
132
 
 
133
def fake_module(module_name, other=None):
 
134
    """Replace a module with a fake one."""
 
135
    snapshot = getSnapshot()
 
136
    if type(module_name) == type(sys):
 
137
        module_name = module_name.__name__
 
138
    snapshot.mock_module(module_name, fake=other)