1# -*- coding: utf-8 -*- 2import pytest 3 4import env # noqa: F401 5 6from pybind11_tests import builtin_casters as m 7from pybind11_tests import UserType, IncType 8 9 10def test_simple_string(): 11 assert m.string_roundtrip("const char *") == "const char *" 12 13 14def test_unicode_conversion(): 15 """Tests unicode conversion and error reporting.""" 16 assert m.good_utf8_string() == u"Say utf8‽ " 17 assert m.good_utf16_string() == u"b‽z" 18 assert m.good_utf32_string() == u"a‽z" 19 assert m.good_wchar_string() == u"a⸘z" 20 if hasattr(m, "has_u8string"): 21 assert m.good_utf8_u8string() == u"Say utf8‽ " 22 23 with pytest.raises(UnicodeDecodeError): 24 m.bad_utf8_string() 25 26 with pytest.raises(UnicodeDecodeError): 27 m.bad_utf16_string() 28 29 # These are provided only if they actually fail (they don't when 32-bit and under Python 2.7) 30 if hasattr(m, "bad_utf32_string"): 31 with pytest.raises(UnicodeDecodeError): 32 m.bad_utf32_string() 33 if hasattr(m, "bad_wchar_string"): 34 with pytest.raises(UnicodeDecodeError): 35 m.bad_wchar_string() 36 if hasattr(m, "has_u8string"): 37 with pytest.raises(UnicodeDecodeError): 38 m.bad_utf8_u8string() 39 40 assert m.u8_Z() == "Z" 41 assert m.u8_eacute() == u"é" 42 assert m.u16_ibang() == u"‽" 43 assert m.u32_mathbfA() == u"" 44 assert m.wchar_heart() == u"♥" 45 if hasattr(m, "has_u8string"): 46 assert m.u8_char8_Z() == "Z" 47 48 49def test_single_char_arguments(): 50 """Tests failures for passing invalid inputs to char-accepting functions""" 51 52 def toobig_message(r): 53 return "Character code point not in range({0:#x})".format(r) 54 55 toolong_message = "Expected a character, but multi-character string found" 56 57 assert m.ord_char(u"a") == 0x61 # simple ASCII 58 assert m.ord_char_lv(u"b") == 0x62 59 assert ( 60 m.ord_char(u"é") == 0xE9 61 ) # requires 2 bytes in utf-8, but can be stuffed in a char 62 with pytest.raises(ValueError) as excinfo: 63 assert m.ord_char(u"Ā") == 0x100 # requires 2 bytes, doesn't fit in a char 64 assert str(excinfo.value) == toobig_message(0x100) 65 with pytest.raises(ValueError) as excinfo: 66 assert m.ord_char(u"ab") 67 assert str(excinfo.value) == toolong_message 68 69 assert m.ord_char16(u"a") == 0x61 70 assert m.ord_char16(u"é") == 0xE9 71 assert m.ord_char16_lv(u"ê") == 0xEA 72 assert m.ord_char16(u"Ā") == 0x100 73 assert m.ord_char16(u"‽") == 0x203D 74 assert m.ord_char16(u"♥") == 0x2665 75 assert m.ord_char16_lv(u"♡") == 0x2661 76 with pytest.raises(ValueError) as excinfo: 77 assert m.ord_char16(u"") == 0x1F382 # requires surrogate pair 78 assert str(excinfo.value) == toobig_message(0x10000) 79 with pytest.raises(ValueError) as excinfo: 80 assert m.ord_char16(u"aa") 81 assert str(excinfo.value) == toolong_message 82 83 assert m.ord_char32(u"a") == 0x61 84 assert m.ord_char32(u"é") == 0xE9 85 assert m.ord_char32(u"Ā") == 0x100 86 assert m.ord_char32(u"‽") == 0x203D 87 assert m.ord_char32(u"♥") == 0x2665 88 assert m.ord_char32(u"") == 0x1F382 89 with pytest.raises(ValueError) as excinfo: 90 assert m.ord_char32(u"aa") 91 assert str(excinfo.value) == toolong_message 92 93 assert m.ord_wchar(u"a") == 0x61 94 assert m.ord_wchar(u"é") == 0xE9 95 assert m.ord_wchar(u"Ā") == 0x100 96 assert m.ord_wchar(u"‽") == 0x203D 97 assert m.ord_wchar(u"♥") == 0x2665 98 if m.wchar_size == 2: 99 with pytest.raises(ValueError) as excinfo: 100 assert m.ord_wchar(u"") == 0x1F382 # requires surrogate pair 101 assert str(excinfo.value) == toobig_message(0x10000) 102 else: 103 assert m.ord_wchar(u"") == 0x1F382 104 with pytest.raises(ValueError) as excinfo: 105 assert m.ord_wchar(u"aa") 106 assert str(excinfo.value) == toolong_message 107 108 if hasattr(m, "has_u8string"): 109 assert m.ord_char8(u"a") == 0x61 # simple ASCII 110 assert m.ord_char8_lv(u"b") == 0x62 111 assert ( 112 m.ord_char8(u"é") == 0xE9 113 ) # requires 2 bytes in utf-8, but can be stuffed in a char 114 with pytest.raises(ValueError) as excinfo: 115 assert m.ord_char8(u"Ā") == 0x100 # requires 2 bytes, doesn't fit in a char 116 assert str(excinfo.value) == toobig_message(0x100) 117 with pytest.raises(ValueError) as excinfo: 118 assert m.ord_char8(u"ab") 119 assert str(excinfo.value) == toolong_message 120 121 122def test_bytes_to_string(): 123 """Tests the ability to pass bytes to C++ string-accepting functions. Note that this is 124 one-way: the only way to return bytes to Python is via the pybind11::bytes class.""" 125 # Issue #816 126 127 def to_bytes(s): 128 b = s if env.PY2 else s.encode("utf8") 129 assert isinstance(b, bytes) 130 return b 131 132 assert m.strlen(to_bytes("hi")) == 2 133 assert m.string_length(to_bytes("world")) == 5 134 assert m.string_length(to_bytes("a\x00b")) == 3 135 assert m.strlen(to_bytes("a\x00b")) == 1 # C-string limitation 136 137 # passing in a utf8 encoded string should work 138 assert m.string_length(u"".encode("utf8")) == 4 139 140 141@pytest.mark.skipif(not hasattr(m, "has_string_view"), reason="no <string_view>") 142def test_string_view(capture): 143 """Tests support for C++17 string_view arguments and return values""" 144 assert m.string_view_chars("Hi") == [72, 105] 145 assert m.string_view_chars("Hi ") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82] 146 assert m.string_view16_chars(u"Hi ") == [72, 105, 32, 0xD83C, 0xDF82] 147 assert m.string_view32_chars(u"Hi ") == [72, 105, 32, 127874] 148 if hasattr(m, "has_u8string"): 149 assert m.string_view8_chars("Hi") == [72, 105] 150 assert m.string_view8_chars(u"Hi ") == [72, 105, 32, 0xF0, 0x9F, 0x8E, 0x82] 151 152 assert m.string_view_return() == u"utf8 secret " 153 assert m.string_view16_return() == u"utf16 secret " 154 assert m.string_view32_return() == u"utf32 secret " 155 if hasattr(m, "has_u8string"): 156 assert m.string_view8_return() == u"utf8 secret " 157 158 with capture: 159 m.string_view_print("Hi") 160 m.string_view_print("utf8 ") 161 m.string_view16_print(u"utf16 ") 162 m.string_view32_print(u"utf32 ") 163 assert ( 164 capture 165 == u""" 166 Hi 2 167 utf8 9 168 utf16 8 169 utf32 7 170 """ 171 ) 172 if hasattr(m, "has_u8string"): 173 with capture: 174 m.string_view8_print("Hi") 175 m.string_view8_print(u"utf8 ") 176 assert ( 177 capture 178 == u""" 179 Hi 2 180 utf8 9 181 """ 182 ) 183 184 with capture: 185 m.string_view_print("Hi, ascii") 186 m.string_view_print("Hi, utf8 ") 187 m.string_view16_print(u"Hi, utf16 ") 188 m.string_view32_print(u"Hi, utf32 ") 189 assert ( 190 capture 191 == u""" 192 Hi, ascii 9 193 Hi, utf8 13 194 Hi, utf16 12 195 Hi, utf32 11 196 """ 197 ) 198 if hasattr(m, "has_u8string"): 199 with capture: 200 m.string_view8_print("Hi, ascii") 201 m.string_view8_print(u"Hi, utf8 ") 202 assert ( 203 capture 204 == u""" 205 Hi, ascii 9 206 Hi, utf8 13 207 """ 208 ) 209 210 211def test_integer_casting(): 212 """Issue #929 - out-of-range integer values shouldn't be accepted""" 213 assert m.i32_str(-1) == "-1" 214 assert m.i64_str(-1) == "-1" 215 assert m.i32_str(2000000000) == "2000000000" 216 assert m.u32_str(2000000000) == "2000000000" 217 if env.PY2: 218 assert m.i32_str(long(-1)) == "-1" # noqa: F821 undefined name 'long' 219 assert m.i64_str(long(-1)) == "-1" # noqa: F821 undefined name 'long' 220 assert ( 221 m.i64_str(long(-999999999999)) # noqa: F821 undefined name 'long' 222 == "-999999999999" 223 ) 224 assert ( 225 m.u64_str(long(999999999999)) # noqa: F821 undefined name 'long' 226 == "999999999999" 227 ) 228 else: 229 assert m.i64_str(-999999999999) == "-999999999999" 230 assert m.u64_str(999999999999) == "999999999999" 231 232 with pytest.raises(TypeError) as excinfo: 233 m.u32_str(-1) 234 assert "incompatible function arguments" in str(excinfo.value) 235 with pytest.raises(TypeError) as excinfo: 236 m.u64_str(-1) 237 assert "incompatible function arguments" in str(excinfo.value) 238 with pytest.raises(TypeError) as excinfo: 239 m.i32_str(-3000000000) 240 assert "incompatible function arguments" in str(excinfo.value) 241 with pytest.raises(TypeError) as excinfo: 242 m.i32_str(3000000000) 243 assert "incompatible function arguments" in str(excinfo.value) 244 245 if env.PY2: 246 with pytest.raises(TypeError) as excinfo: 247 m.u32_str(long(-1)) # noqa: F821 undefined name 'long' 248 assert "incompatible function arguments" in str(excinfo.value) 249 with pytest.raises(TypeError) as excinfo: 250 m.u64_str(long(-1)) # noqa: F821 undefined name 'long' 251 assert "incompatible function arguments" in str(excinfo.value) 252 253 254def test_tuple(doc): 255 """std::pair <-> tuple & std::tuple <-> tuple""" 256 assert m.pair_passthrough((True, "test")) == ("test", True) 257 assert m.tuple_passthrough((True, "test", 5)) == (5, "test", True) 258 # Any sequence can be cast to a std::pair or std::tuple 259 assert m.pair_passthrough([True, "test"]) == ("test", True) 260 assert m.tuple_passthrough([True, "test", 5]) == (5, "test", True) 261 assert m.empty_tuple() == () 262 263 assert ( 264 doc(m.pair_passthrough) 265 == """ 266 pair_passthrough(arg0: Tuple[bool, str]) -> Tuple[str, bool] 267 268 Return a pair in reversed order 269 """ 270 ) 271 assert ( 272 doc(m.tuple_passthrough) 273 == """ 274 tuple_passthrough(arg0: Tuple[bool, str, int]) -> Tuple[int, str, bool] 275 276 Return a triple in reversed order 277 """ 278 ) 279 280 assert m.rvalue_pair() == ("rvalue", "rvalue") 281 assert m.lvalue_pair() == ("lvalue", "lvalue") 282 assert m.rvalue_tuple() == ("rvalue", "rvalue", "rvalue") 283 assert m.lvalue_tuple() == ("lvalue", "lvalue", "lvalue") 284 assert m.rvalue_nested() == ("rvalue", ("rvalue", ("rvalue", "rvalue"))) 285 assert m.lvalue_nested() == ("lvalue", ("lvalue", ("lvalue", "lvalue"))) 286 287 assert m.int_string_pair() == (2, "items") 288 289 290def test_builtins_cast_return_none(): 291 """Casters produced with PYBIND11_TYPE_CASTER() should convert nullptr to None""" 292 assert m.return_none_string() is None 293 assert m.return_none_char() is None 294 assert m.return_none_bool() is None 295 assert m.return_none_int() is None 296 assert m.return_none_float() is None 297 assert m.return_none_pair() is None 298 299 300def test_none_deferred(): 301 """None passed as various argument types should defer to other overloads""" 302 assert not m.defer_none_cstring("abc") 303 assert m.defer_none_cstring(None) 304 assert not m.defer_none_custom(UserType()) 305 assert m.defer_none_custom(None) 306 assert m.nodefer_none_void(None) 307 308 309def test_void_caster(): 310 assert m.load_nullptr_t(None) is None 311 assert m.cast_nullptr_t() is None 312 313 314def test_reference_wrapper(): 315 """std::reference_wrapper for builtin and user types""" 316 assert m.refwrap_builtin(42) == 420 317 assert m.refwrap_usertype(UserType(42)) == 42 318 319 with pytest.raises(TypeError) as excinfo: 320 m.refwrap_builtin(None) 321 assert "incompatible function arguments" in str(excinfo.value) 322 323 with pytest.raises(TypeError) as excinfo: 324 m.refwrap_usertype(None) 325 assert "incompatible function arguments" in str(excinfo.value) 326 327 a1 = m.refwrap_list(copy=True) 328 a2 = m.refwrap_list(copy=True) 329 assert [x.value for x in a1] == [2, 3] 330 assert [x.value for x in a2] == [2, 3] 331 assert not a1[0] is a2[0] and not a1[1] is a2[1] 332 333 b1 = m.refwrap_list(copy=False) 334 b2 = m.refwrap_list(copy=False) 335 assert [x.value for x in b1] == [1, 2] 336 assert [x.value for x in b2] == [1, 2] 337 assert b1[0] is b2[0] and b1[1] is b2[1] 338 339 assert m.refwrap_iiw(IncType(5)) == 5 340 assert m.refwrap_call_iiw(IncType(10), m.refwrap_iiw) == [10, 10, 10, 10] 341 342 343def test_complex_cast(): 344 """std::complex casts""" 345 assert m.complex_cast(1) == "1.0" 346 assert m.complex_cast(2j) == "(0.0, 2.0)" 347 348 349def test_bool_caster(): 350 """Test bool caster implicit conversions.""" 351 convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert 352 353 def require_implicit(v): 354 pytest.raises(TypeError, noconvert, v) 355 356 def cant_convert(v): 357 pytest.raises(TypeError, convert, v) 358 359 # straight up bool 360 assert convert(True) is True 361 assert convert(False) is False 362 assert noconvert(True) is True 363 assert noconvert(False) is False 364 365 # None requires implicit conversion 366 require_implicit(None) 367 assert convert(None) is False 368 369 class A(object): 370 def __init__(self, x): 371 self.x = x 372 373 def __nonzero__(self): 374 return self.x 375 376 def __bool__(self): 377 return self.x 378 379 class B(object): 380 pass 381 382 # Arbitrary objects are not accepted 383 cant_convert(object()) 384 cant_convert(B()) 385 386 # Objects with __nonzero__ / __bool__ defined can be converted 387 require_implicit(A(True)) 388 assert convert(A(True)) is True 389 assert convert(A(False)) is False 390 391 392def test_numpy_bool(): 393 np = pytest.importorskip("numpy") 394 395 convert, noconvert = m.bool_passthrough, m.bool_passthrough_noconvert 396 397 def cant_convert(v): 398 pytest.raises(TypeError, convert, v) 399 400 # np.bool_ is not considered implicit 401 assert convert(np.bool_(True)) is True 402 assert convert(np.bool_(False)) is False 403 assert noconvert(np.bool_(True)) is True 404 assert noconvert(np.bool_(False)) is False 405 cant_convert(np.zeros(2, dtype="int")) 406 407 408def test_int_long(): 409 """In Python 2, a C++ int should return a Python int rather than long 410 if possible: longs are not always accepted where ints are used (such 411 as the argument to sys.exit()). A C++ long long is always a Python 412 long.""" 413 414 import sys 415 416 must_be_long = type(getattr(sys, "maxint", 1) + 1) 417 assert isinstance(m.int_cast(), int) 418 assert isinstance(m.long_cast(), int) 419 assert isinstance(m.longlong_cast(), must_be_long) 420 421 422def test_void_caster_2(): 423 assert m.test_void_caster() 424