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