From 58a9e71e812e6ed09843127ffbe143dafc74b63f Mon Sep 17 00:00:00 2001 From: holger krekel Date: Sat, 22 Aug 2009 12:45:58 +0200 Subject: [PATCH] add delattr/delenv/delitem methods and tests, enhance terminalwriter tests --HG-- branch : trunk --- doc/changelog.txt | 5 +- py/io/testing/test_terminalwriter.py | 23 +++++-- py/test/plugin/pytest_monkeypatch.py | 94 +++++++++++++++++++++++++--- 3 files changed, 106 insertions(+), 16 deletions(-) diff --git a/doc/changelog.txt b/doc/changelog.txt index 2aca64fe6..2f6f9daed 100644 --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -1,11 +1,10 @@ Changes between 1.0.x and 'trunk' ===================================== +* introduce delattr/delitem/delenv methods to py.test's monkeypatch funcarg + * consolidate py.log implementation, remove old approach. -* introduce py.io.TextIO and py.io.BytesIO for distinguishing between - text/unicode and byte-streams (uses underlying standard lib io.* - if available) * introduce py.io.TextIO and py.io.BytesIO for distinguishing between text/unicode and byte-streams (uses underlying standard lib io.* if available) diff --git a/py/io/testing/test_terminalwriter.py b/py/io/testing/test_terminalwriter.py index 80c0942df..ddc18981b 100644 --- a/py/io/testing/test_terminalwriter.py +++ b/py/io/testing/test_terminalwriter.py @@ -6,15 +6,28 @@ def skip_win32(): if sys.platform == 'win32': py.test.skip('Not relevant on win32') +import os +import py + +def test_terminal_width_COLUMNS(monkeypatch): + """ Dummy test for get_terminal_width + """ + fcntl = py.test.importorskip("fcntl") + monkeypatch.setattr(fcntl, 'ioctl', lambda *args: int('x')) + monkeypatch.setenv('COLUMNS', '42') + assert terminalwriter.get_terminal_width() == 41 + monkeypatch.delenv('COLUMNS', raising=False) + +def test_terminalwriter_defaultwidth_80(monkeypatch): + monkeypatch.setattr(terminalwriter, '_getdimensions', lambda: 0/0) + monkeypatch.delenv('COLUMNS', raising=False) + tw = py.io.TerminalWriter() + assert tw.fullwidth == 80-1 + def test_terminalwriter_computes_width(monkeypatch): monkeypatch.setattr(terminalwriter, 'get_terminal_width', lambda: 42) tw = py.io.TerminalWriter() assert tw.fullwidth == 42 - -def test_terminalwriter_defaultwidth_80(monkeypatch): - monkeypatch.setattr(terminalwriter, '_getdimensions', lambda: 0/0) - tw = py.io.TerminalWriter() - assert tw.fullwidth == int(os.environ.get('COLUMNS', 80)) -1 def test_terminalwriter_default_instantiation(): tw = py.io.TerminalWriter(stringio=True) diff --git a/py/test/plugin/pytest_monkeypatch.py b/py/test/plugin/pytest_monkeypatch.py index 80984b6f0..9403fe9a6 100644 --- a/py/test/plugin/pytest_monkeypatch.py +++ b/py/test/plugin/pytest_monkeypatch.py @@ -34,18 +34,24 @@ can use this example: .. _`monkeypatch blog post`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/ """ -import os +import py, os def pytest_funcarg__monkeypatch(request): - """The returned ``monkeypatch`` funcarg provides three + """The returned ``monkeypatch`` funcarg provides these helper methods to modify objects, dictionaries or os.environ:: monkeypatch.setattr(obj, name, value) + monkeypatch.delattr(obj, name, raising=True) monkeypatch.setitem(mapping, name, value) - monkeypatch.setenv(name, value) + monkeypatch.delitem(obj, name, raising=True) + monkeypatch.setenv(name, value, prepend=False) + monkeypatch.delenv(name, value, raising=True) - All such modifications will be undone when the requesting - test function finished its execution. + All modifications will be undone when the requesting + test function finished its execution. For the ``del`` + methods the ``raising`` parameter determines if a + KeyError or AttributeError will be raised if the + deletion has no target. """ monkeypatch = MonkeyPatch() request.addfinalizer(monkeypatch.finalize) @@ -62,9 +68,25 @@ class MonkeyPatch: self._setattr.insert(0, (obj, name, getattr(obj, name, notset))) setattr(obj, name, value) - def setitem(self, dictionary, name, value): - self._setitem.insert(0, (dictionary, name, dictionary.get(name, notset))) - dictionary[name] = value + def delattr(self, obj, name, raising=True): + if not hasattr(obj, name): + if raising: + raise AttributeError(name) + else: + self._setattr.insert(0, (obj, name, getattr(obj, name, notset))) + delattr(obj, name) + + def setitem(self, dic, name, value): + self._setitem.insert(0, (dic, name, dic.get(name, notset))) + dic[name] = value + + def delitem(self, dic, name, raising=True): + if name not in dic: + if raising: + raise KeyError(name) + else: + self._setitem.insert(0, (dic, name, dic.get(name, notset))) + del dic[name] def setenv(self, name, value, prepend=None): value = str(value) @@ -72,6 +94,9 @@ class MonkeyPatch: value = value + prepend + os.environ[name] self.setitem(os.environ, name, value) + def delenv(self, name, raising=True): + self.delitem(os.environ, name, raising=raising) + def finalize(self): for obj, name, value in self._setattr: if value is not notset: @@ -101,6 +126,23 @@ def test_setattr(): monkeypatch.finalize() assert not hasattr(A, 'y') +def test_delattr(): + class A: + x = 1 + monkeypatch = MonkeyPatch() + monkeypatch.delattr(A, 'x') + assert not hasattr(A, 'x') + monkeypatch.finalize() + assert A.x == 1 + + monkeypatch = MonkeyPatch() + monkeypatch.delattr(A, 'x') + py.test.raises(AttributeError, "monkeypatch.delattr(A, 'y')") + monkeypatch.delattr(A, 'y', raising=False) + monkeypatch.setattr(A, 'x', 5) + assert A.x == 5 + monkeypatch.finalize() + assert A.x == 1 def test_setitem(): d = {'x': 1} @@ -115,6 +157,22 @@ def test_setitem(): assert d['x'] == 1 assert 'y' not in d +def test_delitem(): + d = {'x': 1} + monkeypatch = MonkeyPatch() + monkeypatch.delitem(d, 'x') + assert 'x' not in d + monkeypatch.delitem(d, 'y', raising=False) + py.test.raises(KeyError, "monkeypatch.delitem(d, 'y')") + assert not d + monkeypatch.setitem(d, 'y', 1700) + assert d['y'] == 1700 + d['hello'] = 'world' + monkeypatch.setitem(d, 'x', 1500) + assert d['x'] == 1500 + monkeypatch.finalize() + assert d == {'hello': 'world', 'x': 1} + def test_setenv(): monkeypatch = MonkeyPatch() monkeypatch.setenv('XYZ123', 2) @@ -123,6 +181,26 @@ def test_setenv(): monkeypatch.finalize() assert 'XYZ123' not in os.environ +def test_delenv(): + name = 'xyz1234' + assert name not in os.environ + monkeypatch = MonkeyPatch() + py.test.raises(KeyError, "monkeypatch.delenv(%r, raising=True)" % name) + monkeypatch.delenv(name, raising=False) + monkeypatch.finalize() + os.environ[name] = "1" + try: + monkeypatch = MonkeyPatch() + monkeypatch.delenv(name) + assert name not in os.environ + monkeypatch.setenv(name, "3") + assert os.environ[name] == "3" + monkeypatch.finalize() + assert os.environ[name] == "1" + finally: + if name in os.environ: + del os.environ[name] + def test_setenv_prepend(): import os monkeypatch = MonkeyPatch()