Commits

Virgil Dupras  committed 942122c

Initial commit.

  • Participants

Comments (0)

Files changed (4)

+Copyright (c) 2011, Virgil Dupras
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+    * Neither the name of Virgil Dupras nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+===========================================
+pytest-monkeyplus - monkeypatch with extras
+===========================================
+
+The ``monkkeyplus`` plugin is a funcarg that subclasses ``monkeypatch`` and adds 
+a few extra features to it.
+
+Extra features
+--------------
+
+``monkeyplus`` has two extra methods: ``patch_osstat`` and ``patch_today``.
+
+``patch_osstat(path, **osstat_attrs)``
+
+Patching ``os.stat`` is tricky because you usually want to patch only one file,
+not the whole filesystem. Moreover, to patch it properly, you have to return a
+full ``stat_result`` structure. ``patch_osstat`` takes care of this stuff.
+Just call it with a path to patch and keyword arguments for the stat attributes
+you want, for example::
+
+    monkeyplus.patch_osstat('foo/bar', st_mtime=42)
+
+Arguments that are not specified will be assigned a default value.
+
+``patch_today(year, month, day)``
+
+Patching dates can be tricky because there's a couple of time relates modules,
+namely ``datetime`` and ``time``. If you want your patch to affect the whole app
+uniformly, you have to patch the ``time`` module, not the ``datetime`` module.
+The arithmetics to transform a year/month/day value in a suitable ``time.time``
+value are non-trivial, so it can get boring to repeat. Call ``patch_today`` with
+the date you'd like the app to be patched to, example::
+
+    monkeyplus.patch_today(2011, 2, 16)
+
+Replacing monkeypatch
+---------------------
+
+``monkeyplus`` is a subclass of ``monkeypatch``, so it can be used everywhere
+``monkeypatch`` is used. Instead of having to use a different funcarg, you can
+replace ``monkeypatch`` by putting this in your ``conftest.py`` file::
+
+    def pytest_funcarg__monkeypatch(request):
+        monkeyplus = request.getfuncargvalue('monkeyplus')
+        return monkeyplus
+
+Contributions welcome
+---------------------
+
+For now, ``monkeyplus`` is a plugin that reflect my own needs, but if you'd like
+to contribute new features to it, they're welcome. The source is hosted at http://bitbucket.org/hsoft/pytest-monkeyplus

File pytest_monkeyplus.py

+import os
+import datetime
+import time
+
+from _pytest.monkeypatch import monkeypatch
+
+def pytest_funcarg__monkeyplus(request):
+    result = monkeyplus()
+    request.addfinalizer(result.undo)
+    return result
+
+class monkeyplus(monkeypatch):
+    def patch_osstat(self, path, st_mode=16877, st_ino=742635, st_dev=234881026, st_nlink=51,
+            st_uid=501, st_gid=20, st_size=1734, st_atime=1257942648, st_mtime=1257873561, 
+            st_ctime=1257873561):
+        """ Patches os.stat for `path`.
+    
+        Patching os.stat can be tricky, because it can mess much more than what you're trying to test.
+        Also, it can be cumbersome to do it. This method lets you do it easily. Just specify a path
+        for which you want to patch os.stat, and specify the values through **kwargs. The defaults
+        here are just some stats (that make sense) to fill up.
+    
+        Example call: monkeyplus.patch_osstat('foo/bar', st_mtime=42)
+        """
+        if not hasattr(self, '_patched_osstat'): # first osstat mock, actually install the mock
+            self._patched_osstat = {} # path: os.stat_result
+            old_osstat = os.stat
+            def fake_osstat(path):
+                try:
+                    return self._patched_osstat[path]
+                except KeyError:
+                    return old_osstat(path)
+            self.setattr(os, 'stat', fake_osstat)
+        st_seq = [st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid, st_size, st_atime, st_mtime, st_ctime]
+        self._patched_osstat[path] = os.stat_result(st_seq)
+    
+    def patch_today(self, year, month, day):
+        """Patches today's date to date(year, month, day)
+        """
+        # For the patching to work system wide, time.time() must be patched. However, there is no way
+        # to get a time.time() value out of a datetime, so a timedelta must be used
+        new_today = datetime.date(year, month, day)
+        today = datetime.date.today()
+        time_now = time.time()
+        delta = today - new_today
+        self.setattr(time, 'time', lambda: time_now - (delta.days * 24 * 60 * 60))
+    
+from setuptools import setup
+
+CLASSIFIERS = [
+    'Development Status :: 5 - Production/Stable',
+    'Intended Audience :: Developers',
+    'License :: OSI Approved :: BSD License',
+    'Programming Language :: Python :: 3',
+]
+
+setup(
+    name='pytest-monkeyplus',
+    description="pytest's monkeypatch subclass with extra functionalities",
+    long_description=open('README').read(),
+    classifiers=CLASSIFIERS,
+    version='1.0.0',
+    author='Virgil Dupras',
+    author_email='hsoft@hardcoded.net',
+    url='http://bitbucket.org/hsoft/pytest-monkeyplus/',
+    py_modules=['pytest_monkeyplus'],
+    entry_points={'pytest11': ['monkeyplus = pytest_monkeyplus']},
+    install_requires=['pytest>=2.0'],
+)