440 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			440 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
| from __future__ import absolute_import
 | |
| from __future__ import division
 | |
| from __future__ import print_function
 | |
| 
 | |
| import os
 | |
| import re
 | |
| import sys
 | |
| import textwrap
 | |
| 
 | |
| import six
 | |
| 
 | |
| import pytest
 | |
| from _pytest.monkeypatch import MonkeyPatch
 | |
| 
 | |
| 
 | |
| @pytest.fixture
 | |
| def mp():
 | |
|     cwd = os.getcwd()
 | |
|     sys_path = list(sys.path)
 | |
|     yield MonkeyPatch()
 | |
|     sys.path[:] = sys_path
 | |
|     os.chdir(cwd)
 | |
| 
 | |
| 
 | |
| def test_setattr():
 | |
|     class A(object):
 | |
|         x = 1
 | |
| 
 | |
|     monkeypatch = MonkeyPatch()
 | |
|     pytest.raises(AttributeError, monkeypatch.setattr, A, "notexists", 2)
 | |
|     monkeypatch.setattr(A, "y", 2, raising=False)
 | |
|     assert A.y == 2
 | |
|     monkeypatch.undo()
 | |
|     assert not hasattr(A, "y")
 | |
| 
 | |
|     monkeypatch = MonkeyPatch()
 | |
|     monkeypatch.setattr(A, "x", 2)
 | |
|     assert A.x == 2
 | |
|     monkeypatch.setattr(A, "x", 3)
 | |
|     assert A.x == 3
 | |
|     monkeypatch.undo()
 | |
|     assert A.x == 1
 | |
| 
 | |
|     A.x = 5
 | |
|     monkeypatch.undo()  # double-undo makes no modification
 | |
|     assert A.x == 5
 | |
| 
 | |
| 
 | |
| class TestSetattrWithImportPath(object):
 | |
|     def test_string_expression(self, monkeypatch):
 | |
|         monkeypatch.setattr("os.path.abspath", lambda x: "hello2")
 | |
|         assert os.path.abspath("123") == "hello2"
 | |
| 
 | |
|     def test_string_expression_class(self, monkeypatch):
 | |
|         monkeypatch.setattr("_pytest.config.Config", 42)
 | |
|         import _pytest
 | |
| 
 | |
|         assert _pytest.config.Config == 42
 | |
| 
 | |
|     def test_unicode_string(self, monkeypatch):
 | |
|         monkeypatch.setattr("_pytest.config.Config", 42)
 | |
|         import _pytest
 | |
| 
 | |
|         assert _pytest.config.Config == 42
 | |
|         monkeypatch.delattr("_pytest.config.Config")
 | |
| 
 | |
|     def test_wrong_target(self, monkeypatch):
 | |
|         pytest.raises(TypeError, lambda: monkeypatch.setattr(None, None))
 | |
| 
 | |
|     def test_unknown_import(self, monkeypatch):
 | |
|         pytest.raises(ImportError, lambda: monkeypatch.setattr("unkn123.classx", None))
 | |
| 
 | |
|     def test_unknown_attr(self, monkeypatch):
 | |
|         pytest.raises(
 | |
|             AttributeError, lambda: monkeypatch.setattr("os.path.qweqwe", None)
 | |
|         )
 | |
| 
 | |
|     def test_unknown_attr_non_raising(self, monkeypatch):
 | |
|         # https://github.com/pytest-dev/pytest/issues/746
 | |
|         monkeypatch.setattr("os.path.qweqwe", 42, raising=False)
 | |
|         assert os.path.qweqwe == 42
 | |
| 
 | |
|     def test_delattr(self, monkeypatch):
 | |
|         monkeypatch.delattr("os.path.abspath")
 | |
|         assert not hasattr(os.path, "abspath")
 | |
|         monkeypatch.undo()
 | |
|         assert os.path.abspath
 | |
| 
 | |
| 
 | |
| def test_delattr():
 | |
|     class A(object):
 | |
|         x = 1
 | |
| 
 | |
|     monkeypatch = MonkeyPatch()
 | |
|     monkeypatch.delattr(A, "x")
 | |
|     assert not hasattr(A, "x")
 | |
|     monkeypatch.undo()
 | |
|     assert A.x == 1
 | |
| 
 | |
|     monkeypatch = MonkeyPatch()
 | |
|     monkeypatch.delattr(A, "x")
 | |
|     pytest.raises(AttributeError, monkeypatch.delattr, A, "y")
 | |
|     monkeypatch.delattr(A, "y", raising=False)
 | |
|     monkeypatch.setattr(A, "x", 5, raising=False)
 | |
|     assert A.x == 5
 | |
|     monkeypatch.undo()
 | |
|     assert A.x == 1
 | |
| 
 | |
| 
 | |
| def test_setitem():
 | |
|     d = {"x": 1}
 | |
|     monkeypatch = MonkeyPatch()
 | |
|     monkeypatch.setitem(d, "x", 2)
 | |
|     monkeypatch.setitem(d, "y", 1700)
 | |
|     monkeypatch.setitem(d, "y", 1700)
 | |
|     assert d["x"] == 2
 | |
|     assert d["y"] == 1700
 | |
|     monkeypatch.setitem(d, "x", 3)
 | |
|     assert d["x"] == 3
 | |
|     monkeypatch.undo()
 | |
|     assert d["x"] == 1
 | |
|     assert "y" not in d
 | |
|     d["x"] = 5
 | |
|     monkeypatch.undo()
 | |
|     assert d["x"] == 5
 | |
| 
 | |
| 
 | |
| def test_setitem_deleted_meanwhile():
 | |
|     d = {}
 | |
|     monkeypatch = MonkeyPatch()
 | |
|     monkeypatch.setitem(d, "x", 2)
 | |
|     del d["x"]
 | |
|     monkeypatch.undo()
 | |
|     assert not d
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize("before", [True, False])
 | |
| def test_setenv_deleted_meanwhile(before):
 | |
|     key = "qwpeoip123"
 | |
|     if before:
 | |
|         os.environ[key] = "world"
 | |
|     monkeypatch = MonkeyPatch()
 | |
|     monkeypatch.setenv(key, "hello")
 | |
|     del os.environ[key]
 | |
|     monkeypatch.undo()
 | |
|     if before:
 | |
|         assert os.environ[key] == "world"
 | |
|         del os.environ[key]
 | |
|     else:
 | |
|         assert key not in os.environ
 | |
| 
 | |
| 
 | |
| def test_delitem():
 | |
|     d = {"x": 1}
 | |
|     monkeypatch = MonkeyPatch()
 | |
|     monkeypatch.delitem(d, "x")
 | |
|     assert "x" not in d
 | |
|     monkeypatch.delitem(d, "y", raising=False)
 | |
|     pytest.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.undo()
 | |
|     assert d == {"hello": "world", "x": 1}
 | |
| 
 | |
| 
 | |
| def test_setenv():
 | |
|     monkeypatch = MonkeyPatch()
 | |
|     with pytest.warns(pytest.PytestWarning):
 | |
|         monkeypatch.setenv("XYZ123", 2)
 | |
|     import os
 | |
| 
 | |
|     assert os.environ["XYZ123"] == "2"
 | |
|     monkeypatch.undo()
 | |
|     assert "XYZ123" not in os.environ
 | |
| 
 | |
| 
 | |
| def test_delenv():
 | |
|     name = "xyz1234"
 | |
|     assert name not in os.environ
 | |
|     monkeypatch = MonkeyPatch()
 | |
|     pytest.raises(KeyError, monkeypatch.delenv, name, raising=True)
 | |
|     monkeypatch.delenv(name, raising=False)
 | |
|     monkeypatch.undo()
 | |
|     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.undo()
 | |
|         assert os.environ[name] == "1"
 | |
|     finally:
 | |
|         if name in os.environ:
 | |
|             del os.environ[name]
 | |
| 
 | |
| 
 | |
| class TestEnvironWarnings(object):
 | |
|     """
 | |
|     os.environ keys and values should be native strings, otherwise it will cause problems with other modules (notably
 | |
|     subprocess). On Python 2 os.environ accepts anything without complaining, while Python 3 does the right thing
 | |
|     and raises an error.
 | |
|     """
 | |
| 
 | |
|     VAR_NAME = u"PYTEST_INTERNAL_MY_VAR"
 | |
| 
 | |
|     @pytest.mark.skipif(six.PY3, reason="Python 2 only test")
 | |
|     def test_setenv_unicode_key(self, monkeypatch):
 | |
|         with pytest.warns(
 | |
|             pytest.PytestWarning,
 | |
|             match="Environment variable name {!r} should be str".format(self.VAR_NAME),
 | |
|         ):
 | |
|             monkeypatch.setenv(self.VAR_NAME, "2")
 | |
| 
 | |
|     @pytest.mark.skipif(six.PY3, reason="Python 2 only test")
 | |
|     def test_delenv_unicode_key(self, monkeypatch):
 | |
|         with pytest.warns(
 | |
|             pytest.PytestWarning,
 | |
|             match="Environment variable name {!r} should be str".format(self.VAR_NAME),
 | |
|         ):
 | |
|             monkeypatch.delenv(self.VAR_NAME, raising=False)
 | |
| 
 | |
|     def test_setenv_non_str_warning(self, monkeypatch):
 | |
|         value = 2
 | |
|         msg = (
 | |
|             "Value of environment variable PYTEST_INTERNAL_MY_VAR type should be str, "
 | |
|             "but got 2 (type: int); converted to str implicitly"
 | |
|         )
 | |
|         with pytest.warns(pytest.PytestWarning, match=re.escape(msg)):
 | |
|             monkeypatch.setenv(str(self.VAR_NAME), value)
 | |
| 
 | |
| 
 | |
| def test_setenv_prepend():
 | |
|     import os
 | |
| 
 | |
|     monkeypatch = MonkeyPatch()
 | |
|     with pytest.warns(pytest.PytestWarning):
 | |
|         monkeypatch.setenv("XYZ123", 2, prepend="-")
 | |
|     assert os.environ["XYZ123"] == "2"
 | |
|     with pytest.warns(pytest.PytestWarning):
 | |
|         monkeypatch.setenv("XYZ123", 3, prepend="-")
 | |
|     assert os.environ["XYZ123"] == "3-2"
 | |
|     monkeypatch.undo()
 | |
|     assert "XYZ123" not in os.environ
 | |
| 
 | |
| 
 | |
| def test_monkeypatch_plugin(testdir):
 | |
|     reprec = testdir.inline_runsource(
 | |
|         """
 | |
|         def test_method(monkeypatch):
 | |
|             assert monkeypatch.__class__.__name__ == "MonkeyPatch"
 | |
|     """
 | |
|     )
 | |
|     res = reprec.countoutcomes()
 | |
|     assert tuple(res) == (1, 0, 0), res
 | |
| 
 | |
| 
 | |
| def test_syspath_prepend(mp):
 | |
|     old = list(sys.path)
 | |
|     mp.syspath_prepend("world")
 | |
|     mp.syspath_prepend("hello")
 | |
|     assert sys.path[0] == "hello"
 | |
|     assert sys.path[1] == "world"
 | |
|     mp.undo()
 | |
|     assert sys.path == old
 | |
|     mp.undo()
 | |
|     assert sys.path == old
 | |
| 
 | |
| 
 | |
| def test_syspath_prepend_double_undo(mp):
 | |
|     old_syspath = sys.path[:]
 | |
|     try:
 | |
|         mp.syspath_prepend("hello world")
 | |
|         mp.undo()
 | |
|         sys.path.append("more hello world")
 | |
|         mp.undo()
 | |
|         assert sys.path[-1] == "more hello world"
 | |
|     finally:
 | |
|         sys.path[:] = old_syspath
 | |
| 
 | |
| 
 | |
| def test_chdir_with_path_local(mp, tmpdir):
 | |
|     mp.chdir(tmpdir)
 | |
|     assert os.getcwd() == tmpdir.strpath
 | |
| 
 | |
| 
 | |
| def test_chdir_with_str(mp, tmpdir):
 | |
|     mp.chdir(tmpdir.strpath)
 | |
|     assert os.getcwd() == tmpdir.strpath
 | |
| 
 | |
| 
 | |
| def test_chdir_undo(mp, tmpdir):
 | |
|     cwd = os.getcwd()
 | |
|     mp.chdir(tmpdir)
 | |
|     mp.undo()
 | |
|     assert os.getcwd() == cwd
 | |
| 
 | |
| 
 | |
| def test_chdir_double_undo(mp, tmpdir):
 | |
|     mp.chdir(tmpdir.strpath)
 | |
|     mp.undo()
 | |
|     tmpdir.chdir()
 | |
|     mp.undo()
 | |
|     assert os.getcwd() == tmpdir.strpath
 | |
| 
 | |
| 
 | |
| def test_issue185_time_breaks(testdir):
 | |
|     testdir.makepyfile(
 | |
|         """
 | |
|         import time
 | |
|         def test_m(monkeypatch):
 | |
|             def f():
 | |
|                 raise Exception
 | |
|             monkeypatch.setattr(time, "time", f)
 | |
|     """
 | |
|     )
 | |
|     result = testdir.runpytest()
 | |
|     result.stdout.fnmatch_lines(
 | |
|         """
 | |
|         *1 passed*
 | |
|     """
 | |
|     )
 | |
| 
 | |
| 
 | |
| def test_importerror(testdir):
 | |
|     p = testdir.mkpydir("package")
 | |
|     p.join("a.py").write(
 | |
|         textwrap.dedent(
 | |
|             """\
 | |
|         import doesnotexist
 | |
| 
 | |
|         x = 1
 | |
|     """
 | |
|         )
 | |
|     )
 | |
|     testdir.tmpdir.join("test_importerror.py").write(
 | |
|         textwrap.dedent(
 | |
|             """\
 | |
|         def test_importerror(monkeypatch):
 | |
|             monkeypatch.setattr('package.a.x', 2)
 | |
|     """
 | |
|         )
 | |
|     )
 | |
|     result = testdir.runpytest()
 | |
|     result.stdout.fnmatch_lines(
 | |
|         """
 | |
|         *import error in package.a: No module named {0}doesnotexist{0}*
 | |
|     """.format(
 | |
|             "'" if sys.version_info > (3, 0) else ""
 | |
|         )
 | |
|     )
 | |
| 
 | |
| 
 | |
| class SampleNew(object):
 | |
|     @staticmethod
 | |
|     def hello():
 | |
|         return True
 | |
| 
 | |
| 
 | |
| class SampleNewInherit(SampleNew):
 | |
|     pass
 | |
| 
 | |
| 
 | |
| class SampleOld(object):
 | |
|     # oldstyle on python2
 | |
|     @staticmethod
 | |
|     def hello():
 | |
|         return True
 | |
| 
 | |
| 
 | |
| class SampleOldInherit(SampleOld):
 | |
|     pass
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize(
 | |
|     "Sample",
 | |
|     [SampleNew, SampleNewInherit, SampleOld, SampleOldInherit],
 | |
|     ids=["new", "new-inherit", "old", "old-inherit"],
 | |
| )
 | |
| def test_issue156_undo_staticmethod(Sample):
 | |
|     monkeypatch = MonkeyPatch()
 | |
| 
 | |
|     monkeypatch.setattr(Sample, "hello", None)
 | |
|     assert Sample.hello is None
 | |
| 
 | |
|     monkeypatch.undo()
 | |
|     assert Sample.hello()
 | |
| 
 | |
| 
 | |
| def test_undo_class_descriptors_delattr():
 | |
|     class SampleParent(object):
 | |
|         @classmethod
 | |
|         def hello(_cls):
 | |
|             pass
 | |
| 
 | |
|         @staticmethod
 | |
|         def world():
 | |
|             pass
 | |
| 
 | |
|     class SampleChild(SampleParent):
 | |
|         pass
 | |
| 
 | |
|     monkeypatch = MonkeyPatch()
 | |
| 
 | |
|     original_hello = SampleChild.hello
 | |
|     original_world = SampleChild.world
 | |
|     monkeypatch.delattr(SampleParent, "hello")
 | |
|     monkeypatch.delattr(SampleParent, "world")
 | |
|     assert getattr(SampleParent, "hello", None) is None
 | |
|     assert getattr(SampleParent, "world", None) is None
 | |
| 
 | |
|     monkeypatch.undo()
 | |
|     assert original_hello == SampleChild.hello
 | |
|     assert original_world == SampleChild.world
 | |
| 
 | |
| 
 | |
| def test_issue1338_name_resolving():
 | |
|     pytest.importorskip("requests")
 | |
|     monkeypatch = MonkeyPatch()
 | |
|     try:
 | |
|         monkeypatch.delattr("requests.sessions.Session.request")
 | |
|     finally:
 | |
|         monkeypatch.undo()
 | |
| 
 | |
| 
 | |
| def test_context():
 | |
|     monkeypatch = MonkeyPatch()
 | |
| 
 | |
|     import functools
 | |
|     import inspect
 | |
| 
 | |
|     with monkeypatch.context() as m:
 | |
|         m.setattr(functools, "partial", 3)
 | |
|         assert not inspect.isclass(functools.partial)
 | |
|     assert inspect.isclass(functools.partial)
 |