blob: 0116d4ef2e4fc2e5a9f7b388c123caca40a7227e [file] [log] [blame]
Wenzel Jakob06710022018-09-01 01:09:16 +02001from __future__ import division
Dean Moldovan83e328f2017-06-09 00:44:49 +02002import pytest
3import sys
4
5from pybind11_tests import pytypes as m
6from pybind11_tests import debug_enabled
7
8
9def test_list(capture, doc):
10 with capture:
Jason Rhinelander5c7a2902017-10-24 20:39:46 -030011 lst = m.get_list()
12 assert lst == ["overwritten"]
Dean Moldovan83e328f2017-06-09 00:44:49 +020013
Jason Rhinelander5c7a2902017-10-24 20:39:46 -030014 lst.append("value2")
15 m.print_list(lst)
Dean Moldovan83e328f2017-06-09 00:44:49 +020016 assert capture.unordered == """
17 Entry at position 0: value
18 list item 0: overwritten
19 list item 1: value2
20 """
21
22 assert doc(m.get_list) == "get_list() -> list"
23 assert doc(m.print_list) == "print_list(arg0: list) -> None"
24
25
26def test_set(capture, doc):
27 s = m.get_set()
28 assert s == {"key1", "key2", "key3"}
29
30 with capture:
31 s.add("key4")
32 m.print_set(s)
33 assert capture.unordered == """
34 key: key1
35 key: key2
36 key: key3
37 key: key4
38 """
39
40 assert doc(m.get_list) == "get_list() -> list"
41 assert doc(m.print_list) == "print_list(arg0: list) -> None"
42
43
44def test_dict(capture, doc):
45 d = m.get_dict()
46 assert d == {"key": "value"}
47
48 with capture:
49 d["key2"] = "value2"
50 m.print_dict(d)
51 assert capture.unordered == """
52 key: key, value=value
53 key: key2, value=value2
54 """
55
56 assert doc(m.get_dict) == "get_dict() -> dict"
57 assert doc(m.print_dict) == "print_dict(arg0: dict) -> None"
58
59 assert m.dict_keyword_constructor() == {"x": 1, "y": 2, "z": 3}
60
61
62def test_str(doc):
63 assert m.str_from_string().encode().decode() == "baz"
64 assert m.str_from_bytes().encode().decode() == "boo"
65
66 assert doc(m.str_from_bytes) == "str_from_bytes() -> str"
67
68 class A(object):
69 def __str__(self):
70 return "this is a str"
71
72 def __repr__(self):
73 return "this is a repr"
74
75 assert m.str_from_object(A()) == "this is a str"
76 assert m.repr_from_object(A()) == "this is a repr"
77
78 s1, s2 = m.str_format()
79 assert s1 == "1 + 2 = 3"
80 assert s1 == s2
81
82
83def test_bytes(doc):
84 assert m.bytes_from_string().decode() == "foo"
85 assert m.bytes_from_str().decode() == "bar"
86
87 assert doc(m.bytes_from_str) == "bytes_from_str() -> {}".format(
88 "bytes" if sys.version_info[0] == 3 else "str"
89 )
90
91
92def test_capsule(capture):
93 pytest.gc_collect()
94 with capture:
95 a = m.return_capsule_with_destructor()
96 del a
97 pytest.gc_collect()
98 assert capture.unordered == """
99 creating capsule
100 destructing capsule
101 """
102
103 with capture:
104 a = m.return_capsule_with_destructor_2()
105 del a
106 pytest.gc_collect()
107 assert capture.unordered == """
108 creating capsule
109 destructing capsule: 1234
110 """
111
112 with capture:
113 a = m.return_capsule_with_name_and_destructor()
114 del a
115 pytest.gc_collect()
116 assert capture.unordered == """
117 created capsule (1234, 'pointer type description')
118 destructing capsule (1234, 'pointer type description')
119 """
120
121
122def test_accessors():
123 class SubTestObject:
124 attr_obj = 1
125 attr_char = 2
126
127 class TestObject:
128 basic_attr = 1
129 begin_end = [1, 2, 3]
130 d = {"operator[object]": 1, "operator[char *]": 2}
131 sub = SubTestObject()
132
133 def func(self, x, *args):
134 return self.basic_attr + x + sum(args)
135
136 d = m.accessor_api(TestObject())
137 assert d["basic_attr"] == 1
138 assert d["begin_end"] == [1, 2, 3]
139 assert d["operator[object]"] == 1
140 assert d["operator[char *]"] == 2
141 assert d["attr(object)"] == 1
142 assert d["attr(char *)"] == 2
143 assert d["missing_attr_ptr"] == "raised"
144 assert d["missing_attr_chain"] == "raised"
145 assert d["is_none"] is False
146 assert d["operator()"] == 2
147 assert d["operator*"] == 7
Dean Moldovan2cf87a52017-09-10 12:21:21 +0200148 assert d["implicit_list"] == [1, 2, 3]
149 assert all(x in TestObject.__dict__ for x in d["implicit_dict"])
Dean Moldovan83e328f2017-06-09 00:44:49 +0200150
151 assert m.tuple_accessor(tuple()) == (0, 1, 2)
152
153 d = m.accessor_assignment()
154 assert d["get"] == 0
155 assert d["deferred_get"] == 0
156 assert d["set"] == 1
157 assert d["deferred_set"] == 1
158 assert d["var"] == 99
159
160
161def test_constructors():
162 """C++ default and converting constructors are equivalent to type calls in Python"""
163 types = [str, bool, int, float, tuple, list, dict, set]
164 expected = {t.__name__: t() for t in types}
165 assert m.default_constructors() == expected
166
167 data = {
168 str: 42,
169 bool: "Not empty",
170 int: "42",
171 float: "+1e3",
172 tuple: range(3),
173 list: range(3),
174 dict: [("two", 2), ("one", 1), ("three", 3)],
175 set: [4, 4, 5, 6, 6, 6],
176 memoryview: b'abc'
177 }
178 inputs = {k.__name__: v for k, v in data.items()}
179 expected = {k.__name__: k(v) for k, v in data.items()}
Jason Rhinelander373da822017-08-03 19:27:04 -0400180
Dean Moldovan83e328f2017-06-09 00:44:49 +0200181 assert m.converting_constructors(inputs) == expected
182 assert m.cast_functions(inputs) == expected
183
Jason Rhinelander373da822017-08-03 19:27:04 -0400184 # Converting constructors and cast functions should just reference rather
185 # than copy when no conversion is needed:
186 noconv1 = m.converting_constructors(expected)
187 for k in noconv1:
188 assert noconv1[k] is expected[k]
189
190 noconv2 = m.cast_functions(expected)
191 for k in noconv2:
192 assert noconv2[k] is expected[k]
193
Dean Moldovan83e328f2017-06-09 00:44:49 +0200194
195def test_implicit_casting():
196 """Tests implicit casting when assigning or appending to dicts and lists."""
197 z = m.get_implicit_casting()
198 assert z['d'] == {
199 'char*_i1': 'abc', 'char*_i2': 'abc', 'char*_e': 'abc', 'char*_p': 'abc',
200 'str_i1': 'str', 'str_i2': 'str1', 'str_e': 'str2', 'str_p': 'str3',
201 'int_i1': 42, 'int_i2': 42, 'int_e': 43, 'int_p': 44
202 }
203 assert z['l'] == [3, 6, 9, 12, 15]
204
205
206def test_print(capture):
207 with capture:
208 m.print_function()
209 assert capture == """
210 Hello, World!
211 1 2.0 three True -- multiple args
212 *args-and-a-custom-separator
213 no new line here -- next print
214 flush
215 py::print + str.format = this
216 """
217 assert capture.stderr == "this goes to stderr"
218
219 with pytest.raises(RuntimeError) as excinfo:
220 m.print_failure()
221 assert str(excinfo.value) == "make_tuple(): unable to convert " + (
222 "argument of type 'UnregisteredType' to Python object"
223 if debug_enabled else
224 "arguments to Python object (compile in debug mode for details)"
225 )
Bruce Merry37de2da2017-08-30 14:22:00 +0200226
227
228def test_hash():
229 class Hashable(object):
230 def __init__(self, value):
231 self.value = value
232
233 def __hash__(self):
234 return self.value
235
236 class Unhashable(object):
237 __hash__ = None
238
239 assert m.hash_function(Hashable(42)) == 42
240 with pytest.raises(TypeError):
241 m.hash_function(Unhashable())
Wenzel Jakob06710022018-09-01 01:09:16 +0200242
243
244def test_number_protocol():
245 for a, b in [(1, 1), (3, 5)]:
246 li = [a == b, a != b, a < b, a <= b, a > b, a >= b, a + b,
247 a - b, a * b, a / b, a | b, a & b, a ^ b, a >> b, a << b]
248 assert m.test_number_protocol(a, b) == li
Wenzel Jakobb4b22922018-09-01 01:19:16 +0200249
250
251def test_list_slicing():
252 li = list(range(100))
253 assert li[::2] == m.test_list_slicing(li)