You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
5.0 KiB

3 months ago
  1. import pytest
  2. from pybind11_tests import has_optional
  3. def test_lacking_copy_ctor():
  4. from pybind11_tests import lacking_copy_ctor
  5. with pytest.raises(RuntimeError) as excinfo:
  6. lacking_copy_ctor.get_one()
  7. assert "the object is non-copyable!" in str(excinfo.value)
  8. def test_lacking_move_ctor():
  9. from pybind11_tests import lacking_move_ctor
  10. with pytest.raises(RuntimeError) as excinfo:
  11. lacking_move_ctor.get_one()
  12. assert "the object is neither movable nor copyable!" in str(excinfo.value)
  13. def test_move_and_copy_casts():
  14. """Cast some values in C++ via custom type casters and count the number of moves/copies."""
  15. from pybind11_tests import move_and_copy_casts, move_and_copy_cstats
  16. cstats = move_and_copy_cstats()
  17. c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"]
  18. # The type move constructions/assignments below each get incremented: the move assignment comes
  19. # from the type_caster load; the move construction happens when extracting that via a cast or
  20. # loading into an argument.
  21. assert move_and_copy_casts(3) == 18
  22. assert c_m.copy_assignments + c_m.copy_constructions == 0
  23. assert c_m.move_assignments == 2
  24. assert c_m.move_constructions == 2
  25. assert c_mc.alive() == 0
  26. assert c_mc.copy_assignments + c_mc.copy_constructions == 0
  27. assert c_mc.move_assignments == 2
  28. assert c_mc.move_constructions == 2
  29. assert c_c.alive() == 0
  30. assert c_c.copy_assignments == 2
  31. assert c_c.copy_constructions == 2
  32. assert c_m.alive() + c_mc.alive() + c_c.alive() == 0
  33. def test_move_and_copy_loads():
  34. """Call some functions that load arguments via custom type casters and count the number of
  35. moves/copies."""
  36. from pybind11_tests import (move_and_copy_cstats, move_only, move_or_copy, copy_only,
  37. move_pair, move_tuple, copy_tuple, move_copy_nested)
  38. cstats = move_and_copy_cstats()
  39. c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"]
  40. assert move_only(10) == 10 # 1 move, c_m
  41. assert move_or_copy(11) == 11 # 1 move, c_mc
  42. assert copy_only(12) == 12 # 1 copy, c_c
  43. assert move_pair((13, 14)) == 27 # 1 c_m move, 1 c_mc move
  44. assert move_tuple((15, 16, 17)) == 48 # 2 c_m moves, 1 c_mc move
  45. assert copy_tuple((18, 19)) == 37 # 2 c_c copies
  46. # Direct constructions: 2 c_m moves, 2 c_mc moves, 1 c_c copy
  47. # Extra moves/copies when moving pairs/tuples: 3 c_m, 3 c_mc, 2 c_c
  48. assert move_copy_nested((1, ((2, 3, (4,)), 5))) == 15
  49. assert c_m.copy_assignments + c_m.copy_constructions == 0
  50. assert c_m.move_assignments == 6
  51. assert c_m.move_constructions == 9
  52. assert c_mc.copy_assignments + c_mc.copy_constructions == 0
  53. assert c_mc.move_assignments == 5
  54. assert c_mc.move_constructions == 8
  55. assert c_c.copy_assignments == 4
  56. assert c_c.copy_constructions == 6
  57. assert c_m.alive() + c_mc.alive() + c_c.alive() == 0
  58. @pytest.mark.skipif(not has_optional, reason='no <optional>')
  59. def test_move_and_copy_load_optional():
  60. """Tests move/copy loads of std::optional arguments"""
  61. from pybind11_tests import (move_and_copy_cstats, move_optional, move_or_copy_optional,
  62. copy_optional, move_optional_tuple)
  63. cstats = move_and_copy_cstats()
  64. c_m, c_mc, c_c = cstats["MoveOnlyInt"], cstats["MoveOrCopyInt"], cstats["CopyOnlyInt"]
  65. # The extra move/copy constructions below come from the std::optional move (which has to move
  66. # its arguments):
  67. assert move_optional(10) == 10 # c_m: 1 move assign, 2 move construct
  68. assert move_or_copy_optional(11) == 11 # c_mc: 1 move assign, 2 move construct
  69. assert copy_optional(12) == 12 # c_c: 1 copy assign, 2 copy construct
  70. # 1 move assign + move construct moves each of c_m, c_mc, 1 c_c copy
  71. # +1 move/copy construct each from moving the tuple
  72. # +1 move/copy construct each from moving the optional (which moves the tuple again)
  73. assert move_optional_tuple((3, 4, 5)) == 12
  74. assert c_m.copy_assignments + c_m.copy_constructions == 0
  75. assert c_m.move_assignments == 2
  76. assert c_m.move_constructions == 5
  77. assert c_mc.copy_assignments + c_mc.copy_constructions == 0
  78. assert c_mc.move_assignments == 2
  79. assert c_mc.move_constructions == 5
  80. assert c_c.copy_assignments == 2
  81. assert c_c.copy_constructions == 5
  82. assert c_m.alive() + c_mc.alive() + c_c.alive() == 0
  83. def test_private_op_new():
  84. """An object with a private `operator new` cannot be returned by value"""
  85. import pybind11_tests as m
  86. with pytest.raises(RuntimeError) as excinfo:
  87. m.private_op_new_value()
  88. assert "the object is neither movable nor copyable" in str(excinfo.value)
  89. assert m.private_op_new_reference().value == 1
  90. def test_move_fallback():
  91. """#389: rvp::move should fall-through to copy on non-movable objects"""
  92. from pybind11_tests import get_moveissue1, get_moveissue2
  93. m2 = get_moveissue2(2)
  94. assert m2.value == 2
  95. m1 = get_moveissue1(1)
  96. assert m1.value == 1