test_exceptions.py 3.9 KB
Newer Older
Dean Moldovan's avatar
Dean Moldovan committed
1
2
import pytest

3
from pybind11_tests import exceptions as m
Dean Moldovan's avatar
Dean Moldovan committed
4

5

6
def test_std_exception(msg):
7
    with pytest.raises(RuntimeError) as excinfo:
8
        m.throw_std_exception()
9
10
11
    assert msg(excinfo.value) == "This exception was intentionally thrown."


12
13
def test_error_already_set(msg):
    with pytest.raises(RuntimeError) as excinfo:
14
        m.throw_already_set(False)
15
16
17
    assert msg(excinfo.value) == "Unknown internal error occurred"

    with pytest.raises(ValueError) as excinfo:
18
        m.throw_already_set(True)
19
20
21
    assert msg(excinfo.value) == "foo"


22
23
def test_python_call_in_catch():
    d = {}
24
    assert m.python_call_in_destructor(d) is True
25
26
27
    assert d["good"] is True


28
def test_exception_matches():
29
    m.exception_matches()
30
31


Dean Moldovan's avatar
Dean Moldovan committed
32
def test_custom(msg):
33
34
35
    # Can we catch a MyException?
    with pytest.raises(m.MyException) as excinfo:
        m.throws1()
Dean Moldovan's avatar
Dean Moldovan committed
36
37
38
39
    assert msg(excinfo.value) == "this error should go to a custom type"

    # Can we translate to standard Python exceptions?
    with pytest.raises(RuntimeError) as excinfo:
40
        m.throws2()
Dean Moldovan's avatar
Dean Moldovan committed
41
42
43
44
    assert msg(excinfo.value) == "this error should go to a standard Python exception"

    # Can we handle unknown exceptions?
    with pytest.raises(RuntimeError) as excinfo:
45
        m.throws3()
Dean Moldovan's avatar
Dean Moldovan committed
46
47
48
    assert msg(excinfo.value) == "Caught an unknown exception!"

    # Can we delegate to another handler by rethrowing?
49
50
    with pytest.raises(m.MyException) as excinfo:
        m.throws4()
Dean Moldovan's avatar
Dean Moldovan committed
51
52
    assert msg(excinfo.value) == "this error is rethrown"

53
    # Can we fall-through to the default handler?
Dean Moldovan's avatar
Dean Moldovan committed
54
    with pytest.raises(RuntimeError) as excinfo:
55
        m.throws_logic_error()
Dean Moldovan's avatar
Dean Moldovan committed
56
    assert msg(excinfo.value) == "this error should fall through to the standard handler"
57
58

    # Can we handle a helper-declared exception?
59
60
    with pytest.raises(m.MyException5) as excinfo:
        m.throws5()
61
62
63
    assert msg(excinfo.value) == "this is a helper-defined translated exception"

    # Exception subclassing:
64
65
    with pytest.raises(m.MyException5) as excinfo:
        m.throws5_1()
66
    assert msg(excinfo.value) == "MyException5 subclass"
67
    assert isinstance(excinfo.value, m.MyException5_1)
68

69
70
    with pytest.raises(m.MyException5_1) as excinfo:
        m.throws5_1()
71
72
    assert msg(excinfo.value) == "MyException5 subclass"

73
    with pytest.raises(m.MyException5) as excinfo:
74
        try:
75
76
            m.throws5()
        except m.MyException5_1:
77
78
            raise RuntimeError("Exception error: caught child from parent")
    assert msg(excinfo.value) == "this is a helper-defined translated exception"
Jason Rhinelander's avatar
Jason Rhinelander committed
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122


def test_nested_throws(capture):
    """Tests nested (e.g. C++ -> Python -> C++) exception handling"""

    def throw_myex():
        raise m.MyException("nested error")

    def throw_myex5():
        raise m.MyException5("nested error 5")

    # In the comments below, the exception is caught in the first step, thrown in the last step

    # C++ -> Python
    with capture:
        m.try_catch(m.MyException5, throw_myex5)
    assert str(capture).startswith("MyException5: nested error 5")

    # Python -> C++ -> Python
    with pytest.raises(m.MyException) as excinfo:
        m.try_catch(m.MyException5, throw_myex)
    assert str(excinfo.value) == "nested error"

    def pycatch(exctype, f, *args):
        try:
            f(*args)
        except m.MyException as e:
            print(e)

    # C++ -> Python -> C++ -> Python
    with capture:
        m.try_catch(
            m.MyException5, pycatch, m.MyException, m.try_catch, m.MyException, throw_myex5)
    assert str(capture).startswith("MyException5: nested error 5")

    # C++ -> Python -> C++
    with capture:
        m.try_catch(m.MyException, pycatch, m.MyException5, m.throws4)
    assert capture == "this error is rethrown"

    # Python -> C++ -> Python -> C++
    with pytest.raises(m.MyException5) as excinfo:
        m.try_catch(m.MyException, pycatch, m.MyException, m.throws5)
    assert str(excinfo.value) == "this is a helper-defined translated exception"