Dean Moldovan | 83e328f | 2017-06-09 00:44:49 +0200 | [diff] [blame] | 1 | import pytest |
| 2 | |
| 3 | from pybind11_tests import class_ as m |
| 4 | from pybind11_tests import UserType, ConstructorStats |
| 5 | |
| 6 | |
| 7 | def test_repr(): |
| 8 | # In Python 3.3+, repr() accesses __qualname__ |
| 9 | assert "pybind11_type" in repr(type(UserType)) |
| 10 | assert "UserType" in repr(UserType) |
| 11 | |
| 12 | |
| 13 | def test_instance(msg): |
| 14 | with pytest.raises(TypeError) as excinfo: |
| 15 | m.NoConstructor() |
| 16 | assert msg(excinfo.value) == "m.class_.NoConstructor: No constructor defined!" |
| 17 | |
| 18 | instance = m.NoConstructor.new_instance() |
| 19 | |
| 20 | cstats = ConstructorStats.get(m.NoConstructor) |
| 21 | assert cstats.alive() == 1 |
| 22 | del instance |
| 23 | assert cstats.alive() == 0 |
| 24 | |
| 25 | |
| 26 | def test_docstrings(doc): |
| 27 | assert doc(UserType) == "A `py::class_` type for testing" |
| 28 | assert UserType.__name__ == "UserType" |
| 29 | assert UserType.__module__ == "pybind11_tests" |
| 30 | assert UserType.get_value.__name__ == "get_value" |
| 31 | assert UserType.get_value.__module__ == "pybind11_tests" |
| 32 | |
| 33 | assert doc(UserType.get_value) == """ |
| 34 | get_value(self: m.UserType) -> int |
| 35 | |
| 36 | Get value using a method |
| 37 | """ |
| 38 | assert doc(UserType.value) == "Get value using a property" |
| 39 | |
| 40 | assert doc(m.NoConstructor.new_instance) == """ |
| 41 | new_instance() -> m.class_.NoConstructor |
| 42 | |
| 43 | Return an instance |
| 44 | """ |
Dean Moldovan | 0bc272b | 2017-06-22 23:42:11 +0200 | [diff] [blame] | 45 | |
| 46 | |
| 47 | def test_inheritance(msg): |
| 48 | roger = m.Rabbit('Rabbit') |
| 49 | assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot" |
| 50 | assert m.pet_name_species(roger) == "Rabbit is a parrot" |
| 51 | |
| 52 | polly = m.Pet('Polly', 'parrot') |
| 53 | assert polly.name() + " is a " + polly.species() == "Polly is a parrot" |
| 54 | assert m.pet_name_species(polly) == "Polly is a parrot" |
| 55 | |
| 56 | molly = m.Dog('Molly') |
| 57 | assert molly.name() + " is a " + molly.species() == "Molly is a dog" |
| 58 | assert m.pet_name_species(molly) == "Molly is a dog" |
| 59 | |
| 60 | fred = m.Hamster('Fred') |
| 61 | assert fred.name() + " is a " + fred.species() == "Fred is a rodent" |
| 62 | |
| 63 | assert m.dog_bark(molly) == "Woof!" |
| 64 | |
| 65 | with pytest.raises(TypeError) as excinfo: |
| 66 | m.dog_bark(polly) |
| 67 | assert msg(excinfo.value) == """ |
| 68 | dog_bark(): incompatible function arguments. The following argument types are supported: |
| 69 | 1. (arg0: m.class_.Dog) -> str |
| 70 | |
| 71 | Invoked with: <m.class_.Pet object at 0> |
| 72 | """ |
| 73 | |
| 74 | with pytest.raises(TypeError) as excinfo: |
| 75 | m.Chimera("lion", "goat") |
| 76 | assert "No constructor defined!" in str(excinfo.value) |
| 77 | |
| 78 | |
| 79 | def test_automatic_upcasting(): |
| 80 | assert type(m.return_class_1()).__name__ == "DerivedClass1" |
| 81 | assert type(m.return_class_2()).__name__ == "DerivedClass2" |
| 82 | assert type(m.return_none()).__name__ == "NoneType" |
| 83 | # Repeat these a few times in a random order to ensure no invalid caching is applied |
| 84 | assert type(m.return_class_n(1)).__name__ == "DerivedClass1" |
| 85 | assert type(m.return_class_n(2)).__name__ == "DerivedClass2" |
| 86 | assert type(m.return_class_n(0)).__name__ == "BaseClass" |
| 87 | assert type(m.return_class_n(2)).__name__ == "DerivedClass2" |
| 88 | assert type(m.return_class_n(2)).__name__ == "DerivedClass2" |
| 89 | assert type(m.return_class_n(0)).__name__ == "BaseClass" |
| 90 | assert type(m.return_class_n(1)).__name__ == "DerivedClass1" |
| 91 | |
| 92 | |
| 93 | def test_isinstance(): |
| 94 | objects = [tuple(), dict(), m.Pet("Polly", "parrot")] + [m.Dog("Molly")] * 4 |
| 95 | expected = (True, True, True, True, True, False, False) |
| 96 | assert m.check_instances(objects) == expected |
| 97 | |
| 98 | |
| 99 | def test_mismatched_holder(): |
| 100 | import re |
| 101 | |
| 102 | with pytest.raises(RuntimeError) as excinfo: |
| 103 | m.mismatched_holder_1() |
| 104 | assert re.match('generic_type: type ".*MismatchDerived1" does not have a non-default ' |
| 105 | 'holder type while its base ".*MismatchBase1" does', str(excinfo.value)) |
| 106 | |
| 107 | with pytest.raises(RuntimeError) as excinfo: |
| 108 | m.mismatched_holder_2() |
| 109 | assert re.match('generic_type: type ".*MismatchDerived2" has a non-default holder type ' |
| 110 | 'while its base ".*MismatchBase2" does not', str(excinfo.value)) |
| 111 | |
| 112 | |
| 113 | def test_override_static(): |
| 114 | """#511: problem with inheritance + overwritten def_static""" |
| 115 | b = m.MyBase.make() |
| 116 | d1 = m.MyDerived.make2() |
| 117 | d2 = m.MyDerived.make() |
| 118 | |
| 119 | assert isinstance(b, m.MyBase) |
| 120 | assert isinstance(d1, m.MyDerived) |
| 121 | assert isinstance(d2, m.MyDerived) |
Dean Moldovan | af2dda3 | 2017-06-26 20:34:06 +0200 | [diff] [blame] | 122 | |
| 123 | |
| 124 | def test_implicit_conversion_life_support(): |
| 125 | """Ensure the lifetime of temporary objects created for implicit conversions""" |
| 126 | assert m.implicitly_convert_argument(UserType(5)) == 5 |
| 127 | assert m.implicitly_convert_variable(UserType(5)) == 5 |
| 128 | |
| 129 | assert "outside a bound function" in m.implicitly_convert_variable_fail(UserType(5)) |