summaryrefslogtreecommitdiffstats
path: root/third_party/python/pytest/testing/test_recwarn.py
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/python/pytest/testing/test_recwarn.py')
-rw-r--r--third_party/python/pytest/testing/test_recwarn.py347
1 files changed, 347 insertions, 0 deletions
diff --git a/third_party/python/pytest/testing/test_recwarn.py b/third_party/python/pytest/testing/test_recwarn.py
new file mode 100644
index 0000000000..a8e2fb8037
--- /dev/null
+++ b/third_party/python/pytest/testing/test_recwarn.py
@@ -0,0 +1,347 @@
+from __future__ import absolute_import, division, print_function
+import warnings
+import re
+
+import pytest
+from _pytest.recwarn import WarningsRecorder
+
+
+def test_recwarn_functional(testdir):
+ reprec = testdir.inline_runsource(
+ """
+ import warnings
+ def test_method(recwarn):
+ warnings.warn("hello")
+ warn = recwarn.pop()
+ assert isinstance(warn.message, UserWarning)
+ """
+ )
+ res = reprec.countoutcomes()
+ assert tuple(res) == (1, 0, 0), res
+
+
+class TestWarningsRecorderChecker(object):
+
+ def test_recording(self):
+ rec = WarningsRecorder()
+ with rec:
+ assert not rec.list
+ warnings.warn_explicit("hello", UserWarning, "xyz", 13)
+ assert len(rec.list) == 1
+ warnings.warn(DeprecationWarning("hello"))
+ assert len(rec.list) == 2
+ warn = rec.pop()
+ assert str(warn.message) == "hello"
+ values = rec.list
+ rec.clear()
+ assert len(rec.list) == 0
+ assert values is rec.list
+ pytest.raises(AssertionError, "rec.pop()")
+
+ def test_typechecking(self):
+ from _pytest.recwarn import WarningsChecker
+
+ with pytest.raises(TypeError):
+ WarningsChecker(5)
+ with pytest.raises(TypeError):
+ WarningsChecker(("hi", RuntimeWarning))
+ with pytest.raises(TypeError):
+ WarningsChecker([DeprecationWarning, RuntimeWarning])
+
+ def test_invalid_enter_exit(self):
+ # wrap this test in WarningsRecorder to ensure warning state gets reset
+ with WarningsRecorder():
+ with pytest.raises(RuntimeError):
+ rec = WarningsRecorder()
+ rec.__exit__(None, None, None) # can't exit before entering
+
+ with pytest.raises(RuntimeError):
+ rec = WarningsRecorder()
+ with rec:
+ with rec:
+ pass # can't enter twice
+
+
+class TestDeprecatedCall(object):
+ """test pytest.deprecated_call()"""
+
+ def dep(self, i, j=None):
+ if i == 0:
+ warnings.warn("is deprecated", DeprecationWarning, stacklevel=1)
+ return 42
+
+ def dep_explicit(self, i):
+ if i == 0:
+ warnings.warn_explicit(
+ "dep_explicit", category=DeprecationWarning, filename="hello", lineno=3
+ )
+
+ def test_deprecated_call_raises(self):
+ with pytest.raises(AssertionError) as excinfo:
+ pytest.deprecated_call(self.dep, 3, 5)
+ assert "Did not produce" in str(excinfo)
+
+ def test_deprecated_call(self):
+ pytest.deprecated_call(self.dep, 0, 5)
+
+ def test_deprecated_call_ret(self):
+ ret = pytest.deprecated_call(self.dep, 0)
+ assert ret == 42
+
+ def test_deprecated_call_preserves(self):
+ onceregistry = warnings.onceregistry.copy()
+ filters = warnings.filters[:]
+ warn = warnings.warn
+ warn_explicit = warnings.warn_explicit
+ self.test_deprecated_call_raises()
+ self.test_deprecated_call()
+ assert onceregistry == warnings.onceregistry
+ assert filters == warnings.filters
+ assert warn is warnings.warn
+ assert warn_explicit is warnings.warn_explicit
+
+ def test_deprecated_explicit_call_raises(self):
+ with pytest.raises(AssertionError):
+ pytest.deprecated_call(self.dep_explicit, 3)
+
+ def test_deprecated_explicit_call(self):
+ pytest.deprecated_call(self.dep_explicit, 0)
+ pytest.deprecated_call(self.dep_explicit, 0)
+
+ @pytest.mark.parametrize("mode", ["context_manager", "call"])
+ def test_deprecated_call_no_warning(self, mode):
+ """Ensure deprecated_call() raises the expected failure when its block/function does
+ not raise a deprecation warning.
+ """
+
+ def f():
+ pass
+
+ msg = "Did not produce DeprecationWarning or PendingDeprecationWarning"
+ with pytest.raises(AssertionError, match=msg):
+ if mode == "call":
+ pytest.deprecated_call(f)
+ else:
+ with pytest.deprecated_call():
+ f()
+
+ @pytest.mark.parametrize(
+ "warning_type", [PendingDeprecationWarning, DeprecationWarning]
+ )
+ @pytest.mark.parametrize("mode", ["context_manager", "call"])
+ @pytest.mark.parametrize("call_f_first", [True, False])
+ @pytest.mark.filterwarnings("ignore")
+ def test_deprecated_call_modes(self, warning_type, mode, call_f_first):
+ """Ensure deprecated_call() captures a deprecation warning as expected inside its
+ block/function.
+ """
+
+ def f():
+ warnings.warn(warning_type("hi"))
+ return 10
+
+ # ensure deprecated_call() can capture the warning even if it has already been triggered
+ if call_f_first:
+ assert f() == 10
+ if mode == "call":
+ assert pytest.deprecated_call(f) == 10
+ else:
+ with pytest.deprecated_call():
+ assert f() == 10
+
+ @pytest.mark.parametrize("mode", ["context_manager", "call"])
+ def test_deprecated_call_exception_is_raised(self, mode):
+ """If the block of the code being tested by deprecated_call() raises an exception,
+ it must raise the exception undisturbed.
+ """
+
+ def f():
+ raise ValueError("some exception")
+
+ with pytest.raises(ValueError, match="some exception"):
+ if mode == "call":
+ pytest.deprecated_call(f)
+ else:
+ with pytest.deprecated_call():
+ f()
+
+ def test_deprecated_call_specificity(self):
+ other_warnings = [
+ Warning,
+ UserWarning,
+ SyntaxWarning,
+ RuntimeWarning,
+ FutureWarning,
+ ImportWarning,
+ UnicodeWarning,
+ ]
+ for warning in other_warnings:
+
+ def f():
+ warnings.warn(warning("hi"))
+
+ with pytest.raises(AssertionError):
+ pytest.deprecated_call(f)
+ with pytest.raises(AssertionError):
+ with pytest.deprecated_call():
+ f()
+
+
+class TestWarns(object):
+
+ def test_strings(self):
+ # different messages, b/c Python suppresses multiple identical warnings
+ source1 = "warnings.warn('w1', RuntimeWarning)"
+ source2 = "warnings.warn('w2', RuntimeWarning)"
+ source3 = "warnings.warn('w3', RuntimeWarning)"
+ pytest.warns(RuntimeWarning, source1)
+ pytest.raises(pytest.fail.Exception, lambda: pytest.warns(UserWarning, source2))
+ pytest.warns(RuntimeWarning, source3)
+
+ def test_function(self):
+ pytest.warns(
+ SyntaxWarning, lambda msg: warnings.warn(msg, SyntaxWarning), "syntax"
+ )
+
+ def test_warning_tuple(self):
+ pytest.warns(
+ (RuntimeWarning, SyntaxWarning), lambda: warnings.warn("w1", RuntimeWarning)
+ )
+ pytest.warns(
+ (RuntimeWarning, SyntaxWarning), lambda: warnings.warn("w2", SyntaxWarning)
+ )
+ pytest.raises(
+ pytest.fail.Exception,
+ lambda: pytest.warns(
+ (RuntimeWarning, SyntaxWarning),
+ lambda: warnings.warn("w3", UserWarning),
+ ),
+ )
+
+ def test_as_contextmanager(self):
+ with pytest.warns(RuntimeWarning):
+ warnings.warn("runtime", RuntimeWarning)
+
+ with pytest.warns(UserWarning):
+ warnings.warn("user", UserWarning)
+
+ with pytest.raises(pytest.fail.Exception) as excinfo:
+ with pytest.warns(RuntimeWarning):
+ warnings.warn("user", UserWarning)
+ excinfo.match(
+ r"DID NOT WARN. No warnings of type \(.+RuntimeWarning.+,\) was emitted. "
+ r"The list of emitted warnings is: \[UserWarning\('user',?\)\]."
+ )
+
+ with pytest.raises(pytest.fail.Exception) as excinfo:
+ with pytest.warns(UserWarning):
+ warnings.warn("runtime", RuntimeWarning)
+ excinfo.match(
+ r"DID NOT WARN. No warnings of type \(.+UserWarning.+,\) was emitted. "
+ r"The list of emitted warnings is: \[RuntimeWarning\('runtime',?\)\]."
+ )
+
+ with pytest.raises(pytest.fail.Exception) as excinfo:
+ with pytest.warns(UserWarning):
+ pass
+ excinfo.match(
+ r"DID NOT WARN. No warnings of type \(.+UserWarning.+,\) was emitted. "
+ r"The list of emitted warnings is: \[\]."
+ )
+
+ warning_classes = (UserWarning, FutureWarning)
+ with pytest.raises(pytest.fail.Exception) as excinfo:
+ with pytest.warns(warning_classes) as warninfo:
+ warnings.warn("runtime", RuntimeWarning)
+ warnings.warn("import", ImportWarning)
+
+ message_template = (
+ "DID NOT WARN. No warnings of type {0} was emitted. "
+ "The list of emitted warnings is: {1}."
+ )
+ excinfo.match(
+ re.escape(
+ message_template.format(
+ warning_classes, [each.message for each in warninfo]
+ )
+ )
+ )
+
+ def test_record(self):
+ with pytest.warns(UserWarning) as record:
+ warnings.warn("user", UserWarning)
+
+ assert len(record) == 1
+ assert str(record[0].message) == "user"
+
+ def test_record_only(self):
+ with pytest.warns(None) as record:
+ warnings.warn("user", UserWarning)
+ warnings.warn("runtime", RuntimeWarning)
+
+ assert len(record) == 2
+ assert str(record[0].message) == "user"
+ assert str(record[1].message) == "runtime"
+
+ def test_record_by_subclass(self):
+ with pytest.warns(Warning) as record:
+ warnings.warn("user", UserWarning)
+ warnings.warn("runtime", RuntimeWarning)
+
+ assert len(record) == 2
+ assert str(record[0].message) == "user"
+ assert str(record[1].message) == "runtime"
+
+ class MyUserWarning(UserWarning):
+ pass
+
+ class MyRuntimeWarning(RuntimeWarning):
+ pass
+
+ with pytest.warns((UserWarning, RuntimeWarning)) as record:
+ warnings.warn("user", MyUserWarning)
+ warnings.warn("runtime", MyRuntimeWarning)
+
+ assert len(record) == 2
+ assert str(record[0].message) == "user"
+ assert str(record[1].message) == "runtime"
+
+ def test_double_test(self, testdir):
+ """If a test is run again, the warning should still be raised"""
+ testdir.makepyfile(
+ """
+ import pytest
+ import warnings
+
+ @pytest.mark.parametrize('run', [1, 2])
+ def test(run):
+ with pytest.warns(RuntimeWarning):
+ warnings.warn("runtime", RuntimeWarning)
+ """
+ )
+ result = testdir.runpytest()
+ result.stdout.fnmatch_lines(["*2 passed in*"])
+
+ def test_match_regex(self):
+ with pytest.warns(UserWarning, match=r"must be \d+$"):
+ warnings.warn("value must be 42", UserWarning)
+
+ with pytest.raises(pytest.fail.Exception):
+ with pytest.warns(UserWarning, match=r"must be \d+$"):
+ warnings.warn("this is not here", UserWarning)
+
+ with pytest.raises(pytest.fail.Exception):
+ with pytest.warns(FutureWarning, match=r"must be \d+$"):
+ warnings.warn("value must be 42", UserWarning)
+
+ def test_one_from_multiple_warns(self):
+ with pytest.warns(UserWarning, match=r"aaa"):
+ warnings.warn("cccccccccc", UserWarning)
+ warnings.warn("bbbbbbbbbb", UserWarning)
+ warnings.warn("aaaaaaaaaa", UserWarning)
+
+ def test_none_of_multiple_warns(self):
+ with pytest.raises(pytest.fail.Exception):
+ with pytest.warns(UserWarning, match=r"aaa"):
+ warnings.warn("bbbbbbbbbb", UserWarning)
+ warnings.warn("cccccccccc", UserWarning)