FAQ Search Today's Posts Mark Forums Read
» Video Reviews

» Linux Archive

Linux-archive is a website aiming to archive linux email lists and to make them easily accessible for linux users/developers.


» Sponsor

» Partners

» Sponsor

Go Back   Linux Archive > Redhat > Fedora User

 
 
LinkBack Thread Tools
 
Old 06-16-2011, 01:39 PM
Ales Kozumplik
 
Default Add the tests/mock framework to rhel6-branch.

Related: rhbz#709653
---
tests/mock/Makefile.am | 21 ++++
tests/mock/__init__.py | 72 +++++++++++++
tests/mock/disk.py | 116 +++++++++++++++++++++
tests/mock/mock.py | 271 ++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 480 insertions(+), 0 deletions(-)
create mode 100644 tests/mock/Makefile.am
create mode 100644 tests/mock/__init__.py
create mode 100644 tests/mock/disk.py
create mode 100644 tests/mock/mock.py

diff --git a/tests/mock/Makefile.am b/tests/mock/Makefile.am
new file mode 100644
index 0000000..87ebd00
--- /dev/null
+++ b/tests/mock/Makefile.am
@@ -0,0 +1,21 @@
+# tests/Makefile.am for anaconda
+#
+# Copyright (C) 2009 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: David Cantrell <dcantrell@redhat.com>
+
+EXTRA_DIST = *.py
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/tests/mock/__init__.py b/tests/mock/__init__.py
new file mode 100644
index 0000000..fb9dd07
--- /dev/null
+++ b/tests/mock/__init__.py
@@ -0,0 +1,72 @@
+# Mocking library for module and code injection, replay tests and other
+# unit testing purposes
+#
+# Copyright (C) 2010
+# Red Hat, Inc. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Author(s): Martin Sivak <msivak@redhat.com>
+
+
+from disk import *
+from mock import *
+import unittest
+
+def slow(f):
+ """Decorates a test method as being slow, usefull for python-nose filtering"""
+ f.slow = True
+ return f
+
+def acceptance(f):
+ """Decorates test as belonging to acceptance testing and not useable in common devellopment unit testing. To be used with python-nose filtering."""
+ f.acceptance = True
+ return f
+
+class TestCase(unittest.TestCase):
+ def __init__(self, *args, **kwargs):
+ unittest.TestCase.__init__(self, *args, **kwargs)
+ self.injectedModules = {}
+
+ def setupModules(self, a):
+ """Mock specified list of modules and store the list so it can be
+ properly unloaded during tearDown"""
+
+ import sys
+ self.preexistingModules = set(sys.modules.keys())
+
+ for m in a:
+ sys.modules[m] = Mock()
+ self.injectedModules[m] = sys.modules[m]
+
+ def modifiedModule(self, mname, mod = None):
+ """Mark module (and all it's parents) as tainted"""
+
+ oldname=""
+ for m in mname.split("."):
+ self.injectedModules[oldname+m] = mod
+ oldname += m + "."
+ self.injectedModules[mname] = mod
+
+ def tearDownModules(self):
+ """Unload previously Mocked modules"""
+
+ import sys
+
+ for m in sys.modules.keys():
+ if m in self.preexistingModules and not m in self.injectedModules:
+ continue
+
+ del sys.modules[m]
+
diff --git a/tests/mock/disk.py b/tests/mock/disk.py
new file mode 100644
index 0000000..af2fcb4
--- /dev/null
+++ b/tests/mock/disk.py
@@ -0,0 +1,116 @@
+# Copyright (C) 2010
+# Red Hat, Inc. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Author(s): Martin Sivak <msivak@redhat.com>
+
+from StringIO import StringIO
+import os.path
+
+class DiskIO(object):
+ """Simple object to simplify mocking of file operations in Mock
+ based testing"""
+
+ class TestFile(StringIO):
+ def __init__(self, store, path, content = ""):
+ StringIO.__init__(self, content)
+ self._store = store
+ self._path = path
+ self._ro = False
+
+ def flush(self):
+ self._store[self._path] = self.getvalue()
+
+ def close(self):
+ self.flush()
+ return StringIO.close(self)
+
+ def __del__(self):
+ try:
+ self.close()
+ except (AttributeError):
+ pass
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *_):
+ self.close()
+
+ class Dir(object):
+ pass
+
+ class Link(object):
+ pass
+
+ def __init__(self):
+ self.reset()
+
+ def __getitem__(self, key):
+ return self.fs[key]
+
+ def __setitem__(self, key, value):
+ self.fs[key] = value
+
+ def reset(self):
+ self.fs = {
+ "/proc": self.Dir,
+ "/proc/cmdline": "linux",
+ }
+ self._pwd = "/"
+
+ #Emulate file objects
+ def open(self, filename, mode = "r"):
+ path = os.path.join(self._pwd, filename)
+ content = self.fs.get(path, None)
+ if content == self.Dir:
+ raise IOError("[Errno 21] Is a directory: '%s'" % (path))
+ elif mode.startswith("w"):
+ self.fs[path] = ""
+ f = self.TestFile(self.fs, path, self.fs[path])
+ elif mode.endswith("a"):
+ if not path in self.fs:
+ self.fs[path] = ""
+ f = self.TestFile(self.fs, path, self.fs[path])
+ f.seek(0, os.SEEK_END)
+ elif content == None:
+ raise IOError("[Errno 2] No such file or directory: '%s'" % (path,))
+ elif mode.endswith("+"):
+ f = self.TestFile(self.fs, path, content)
+ if mode.startswith('r'):
+ f.seek(0, os.SEEK_SET)
+ else:
+ f.seek(0, os.SEEK_END)
+ else:
+ f = self.TestFile(self.fs, path, content)
+
+ return f
+
+ #Emulate os.path calls
+ def os_path_exists(self, path):
+ path = os.path.join(self._pwd, path)
+ return self.fs.has_key(path)
+
+ #Emulate os calls
+ def os_remove(self, path):
+ path = os.path.join(self._pwd, path)
+ try:
+ del self.fs[path]
+ except KeyError:
+ raise OSError("[Errno 2] No such file or directory: '%s'" % (path,))
+
+ def os_access(self, path, mode):
+ return self.path_exists(path)
+
diff --git a/tests/mock/mock.py b/tests/mock/mock.py
new file mode 100644
index 0000000..9053e81
--- /dev/null
+++ b/tests/mock/mock.py
@@ -0,0 +1,271 @@
+# mock.py
+# Test tools for mocking and patching.
+# Copyright (C) 2007-2009 Michael Foord
+# E-mail: fuzzyman AT voidspace DOT org DOT uk
+
+# mock 0.6.0
+# http://www.voidspace.org.uk/python/mock/
+
+# Released subject to the BSD License
+# Please see http://www.voidspace.org.uk/python/license.shtml
+
+# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
+# Comments, suggestions and bug reports welcome.
+
+
+__all__ = (
+ 'Mock',
+ 'patch',
+ 'patch_object',
+ 'sentinel',
+ 'DEFAULT'
+)
+
+__version__ = '0.6.0'
+
+class SentinelObject(object):
+ def __init__(self, name):
+ self.name = name
+
+ def __repr__(self):
+ return '<SentinelObject "%s">' % self.name
+
+
+class Sentinel(object):
+ def __init__(self):
+ self._sentinels = {}
+
+ def __getattr__(self, name):
+ return self._sentinels.setdefault(name, SentinelObject(name))
+
+
+sentinel = Sentinel()
+
+DEFAULT = sentinel.DEFAULT
+
+class OldStyleClass:
+ pass
+ClassType = type(OldStyleClass)
+
+def _is_magic(name):
+ return '__%s__' % name[2:-2] == name
+
+def _copy(value):
+ if type(value) in (dict, list, tuple, set):
+ return type(value)(value)
+ return value
+
+
+class Mock(object):
+
+ def __init__(self, spec=None, side_effect=None, return_value=DEFAULT,
+ name=None, parent=None, wraps=None):
+ self._parent = parent
+ self._name = name
+ if spec is not None and not isinstance(spec, list):
+ spec = [member for member in dir(spec) if not _is_magic(member)]
+
+ self._methods = spec
+ self._children = {}
+ self._return_value = return_value
+ self.side_effect = side_effect
+ self._wraps = wraps
+
+ self.reset_mock()
+
+
+ def reset_mock(self):
+ self.called = False
+ self.call_args = None
+ self.call_count = 0
+ self.call_args_list = []
+ self.method_calls = []
+ for child in self._children.itervalues():
+ child.reset_mock()
+ if isinstance(self._return_value, Mock):
+ self._return_value.reset_mock()
+
+
+ def __get_return_value(self):
+ if self._return_value is DEFAULT:
+ self._return_value = Mock()
+ return self._return_value
+
+ def __set_return_value(self, value):
+ self._return_value = value
+
+ return_value = property(__get_return_value, __set_return_value)
+
+
+ def __call__(self, *args, **kwargs):
+ self.called = True
+ self.call_count += 1
+ self.call_args = (args, kwargs)
+ self.call_args_list.append((args, kwargs))
+
+ parent = self._parent
+ name = self._name
+ while parent is not None:
+ parent.method_calls.append((name, args, kwargs))
+ if parent._parent is None:
+ break
+ name = parent._name + '.' + name
+ parent = parent._parent
+
+ ret_val = DEFAULT
+ if self.side_effect is not None:
+ if (isinstance(self.side_effect, Exception) or
+ isinstance(self.side_effect, (type, ClassType)) and
+ issubclass(self.side_effect, Exception)):
+ raise self.side_effect
+
+ ret_val = self.side_effect(*args, **kwargs)
+ if ret_val is DEFAULT:
+ ret_val = self.return_value
+
+ if self._wraps is not None and self._return_value is DEFAULT:
+ return self._wraps(*args, **kwargs)
+ if ret_val is DEFAULT:
+ ret_val = self.return_value
+ return ret_val
+
+
+ def __getattr__(self, name):
+ if self._methods is not None:
+ if name not in self._methods:
+ raise AttributeError("Mock object has no attribute '%s'" % name)
+ elif _is_magic(name):
+ raise AttributeError(name)
+
+ if name not in self._children:
+ wraps = None
+ if self._wraps is not None:
+ wraps = getattr(self._wraps, name)
+ self._children[name] = Mock(parent=self, name=name, wraps=wraps)
+
+ return self._children[name]
+
+
+ def assert_called_with(self, *args, **kwargs):
+ assert self.call_args == (args, kwargs), 'Expected: %s
Called with: %s' % ((args, kwargs), self.call_args)
+
+
+def _dot_lookup(thing, comp, import_path):
+ try:
+ return getattr(thing, comp)
+ except AttributeError:
+ __import__(import_path)
+ return getattr(thing, comp)
+
+
+def _importer(target):
+ components = target.split('.')
+ import_path = components.pop(0)
+ thing = __import__(import_path)
+
+ for comp in components:
+ import_path += ".%s" % comp
+ thing = _dot_lookup(thing, comp, import_path)
+ return thing
+
+
+class _patch(object):
+ def __init__(self, target, attribute, new, spec, create):
+ self.target = target
+ self.attribute = attribute
+ self.new = new
+ self.spec = spec
+ self.create = create
+ self.has_local = False
+
+
+ def __call__(self, func):
+ if hasattr(func, 'patchings'):
+ func.patchings.append(self)
+ return func
+
+ def patched(*args, **keywargs):
+ # don't use a with here (backwards compatability with 2.5)
+ extra_args = []
+ for patching in patched.patchings:
+ arg = patching.__enter__()
+ if patching.new is DEFAULT:
+ extra_args.append(arg)
+ args += tuple(extra_args)
+ try:
+ return func(*args, **keywargs)
+ finally:
+ for patching in getattr(patched, 'patchings', []):
+ patching.__exit__()
+
+ patched.patchings = [self]
+ patched.__name__ = func.__name__
+ patched.compat_co_firstlineno = getattr(func, "compat_co_firstlineno",
+ func.func_code.co_firstlineno)
+ return patched
+
+
+ def get_original(self):
+ target = self.target
+ name = self.attribute
+ create = self.create
+
+ original = DEFAULT
+ if _has_local_attr(target, name):
+ try:
+ original = target.__dict__[name]
+ except AttributeError:
+ # for instances of classes with slots, they have no __dict__
+ original = getattr(target, name)
+ elif not create and not hasattr(target, name):
+ raise AttributeError("%s does not have the attribute %r" % (target, name))
+ return original
+
+
+ def __enter__(self):
+ new, spec, = self.new, self.spec
+ original = self.get_original()
+ if new is DEFAULT:
+ # XXXX what if original is DEFAULT - shouldn't use it as a spec
+ inherit = False
+ if spec == True:
+ # set spec to the object we are replacing
+ spec = original
+ if isinstance(spec, (type, ClassType)):
+ inherit = True
+ new = Mock(spec=spec)
+ if inherit:
+ new.return_value = Mock(spec=spec)
+ self.temp_original = original
+ setattr(self.target, self.attribute, new)
+ return new
+
+
+ def __exit__(self, *_):
+ if self.temp_original is not DEFAULT:
+ setattr(self.target, self.attribute, self.temp_original)
+ else:
+ delattr(self.target, self.attribute)
+ del self.temp_original
+
+
+def patch_object(target, attribute, new=DEFAULT, spec=None, create=False):
+ return _patch(target, attribute, new, spec, create)
+
+
+def patch(target, new=DEFAULT, spec=None, create=False):
+ try:
+ target, attribute = target.rsplit('.', 1)
+ except (TypeError, ValueError):
+ raise TypeError("Need a valid target to patch. You supplied: %r" % (target,))
+ target = _importer(target)
+ return _patch(target, attribute, new, spec, create)
+
+
+
+def _has_local_attr(obj, name):
+ try:
+ return name in vars(obj)
+ except TypeError:
+ # objects without a __dict__
+ return hasattr(obj, name)
--
1.7.5.2

_______________________________________________
Anaconda-devel-list mailing list
Anaconda-devel-list@redhat.com
https://www.redhat.com/mailman/listinfo/anaconda-devel-list
 

Thread Tools




All times are GMT. The time now is 06:16 AM.

VBulletin, Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Content Relevant URLs by vBSEO ©2007, Crawlability, Inc.
Copyright 2007 - 2008, www.linux-archive.org