1from _pytest.outcomes import Failed
2import pytest
3import sys
4
5
6class TestRaises(object):
7
8    def test_raises(self):
9        source = "int('qwe')"
10        excinfo = pytest.raises(ValueError, source)
11        code = excinfo.traceback[-1].frame.code
12        s = str(code.fullsource)
13        assert s == source
14
15    def test_raises_exec(self):
16        pytest.raises(ValueError, "a,x = []")
17
18    def test_raises_syntax_error(self):
19        pytest.raises(SyntaxError, "qwe qwe qwe")
20
21    def test_raises_function(self):
22        pytest.raises(ValueError, int, "hello")
23
24    def test_raises_callable_no_exception(self):
25
26        class A(object):
27
28            def __call__(self):
29                pass
30
31        try:
32            pytest.raises(ValueError, A())
33        except pytest.raises.Exception:
34            pass
35
36    def test_raises_as_contextmanager(self, testdir):
37        testdir.makepyfile(
38            """
39            from __future__ import with_statement
40            import py, pytest
41            import _pytest._code
42
43            def test_simple():
44                with pytest.raises(ZeroDivisionError) as excinfo:
45                    assert isinstance(excinfo, _pytest._code.ExceptionInfo)
46                    1/0
47                print (excinfo)
48                assert excinfo.type == ZeroDivisionError
49                assert isinstance(excinfo.value, ZeroDivisionError)
50
51            def test_noraise():
52                with pytest.raises(pytest.raises.Exception):
53                    with pytest.raises(ValueError):
54                           int()
55
56            def test_raise_wrong_exception_passes_by():
57                with pytest.raises(ZeroDivisionError):
58                    with pytest.raises(ValueError):
59                           1/0
60        """
61        )
62        result = testdir.runpytest()
63        result.stdout.fnmatch_lines(["*3 passed*"])
64
65    def test_noclass(self):
66        with pytest.raises(TypeError):
67            pytest.raises("wrong", lambda: None)
68
69    def test_invalid_arguments_to_raises(self):
70        with pytest.raises(TypeError, match="unknown"):
71            with pytest.raises(TypeError, unknown="bogus"):
72                raise ValueError()
73
74    def test_tuple(self):
75        with pytest.raises((KeyError, ValueError)):
76            raise KeyError("oops")
77
78    def test_no_raise_message(self):
79        try:
80            pytest.raises(ValueError, int, "0")
81        except pytest.raises.Exception as e:
82            assert e.msg == "DID NOT RAISE {}".format(repr(ValueError))
83        else:
84            assert False, "Expected pytest.raises.Exception"
85
86        try:
87            with pytest.raises(ValueError):
88                pass
89        except pytest.raises.Exception as e:
90            assert e.msg == "DID NOT RAISE {}".format(repr(ValueError))
91        else:
92            assert False, "Expected pytest.raises.Exception"
93
94    def test_custom_raise_message(self):
95        message = "TEST_MESSAGE"
96        try:
97            with pytest.raises(ValueError, message=message):
98                pass
99        except pytest.raises.Exception as e:
100            assert e.msg == message
101        else:
102            assert False, "Expected pytest.raises.Exception"
103
104    @pytest.mark.parametrize("method", ["function", "with"])
105    def test_raises_cyclic_reference(self, method):
106        """
107        Ensure pytest.raises does not leave a reference cycle (#1965).
108        """
109        import gc
110
111        class T(object):
112
113            def __call__(self):
114                raise ValueError
115
116        t = T()
117        if method == "function":
118            pytest.raises(ValueError, t)
119        else:
120            with pytest.raises(ValueError):
121                t()
122
123        # ensure both forms of pytest.raises don't leave exceptions in sys.exc_info()
124        assert sys.exc_info() == (None, None, None)
125
126        del t
127
128        # ensure the t instance is not stuck in a cyclic reference
129        for o in gc.get_objects():
130            assert type(o) is not T
131
132    def test_raises_match(self):
133        msg = r"with base \d+"
134        with pytest.raises(ValueError, match=msg):
135            int("asdf")
136
137        msg = "with base 10"
138        with pytest.raises(ValueError, match=msg):
139            int("asdf")
140
141        msg = "with base 16"
142        expr = r"Pattern '{}' not found in 'invalid literal for int\(\) with base 10: 'asdf''".format(
143            msg
144        )
145        with pytest.raises(AssertionError, match=expr):
146            with pytest.raises(ValueError, match=msg):
147                int("asdf", base=10)
148
149    def test_raises_match_wrong_type(self):
150        """Raising an exception with the wrong type and match= given.
151
152        pytest should throw the unexpected exception - the pattern match is not
153        really relevant if we got a different exception.
154        """
155        with pytest.raises(ValueError):
156            with pytest.raises(IndexError, match="nomatch"):
157                int("asdf")
158
159    def test_raises_exception_looks_iterable(self):
160        from six import add_metaclass
161
162        class Meta(type(object)):
163
164            def __getitem__(self, item):
165                return 1 / 0
166
167            def __len__(self):
168                return 1
169
170        @add_metaclass(Meta)
171        class ClassLooksIterableException(Exception):
172            pass
173
174        with pytest.raises(
175            Failed, match="DID NOT RAISE <class 'raises.ClassLooksIterableException'>"
176        ):
177            pytest.raises(ClassLooksIterableException, lambda: None)
178