111986Sandreas.sandberg@arm.comimport pytest
212391Sjason@lowepower.comfrom pybind11_tests import smart_ptr as m
311986Sandreas.sandberg@arm.comfrom pybind11_tests import ConstructorStats
411986Sandreas.sandberg@arm.com
511986Sandreas.sandberg@arm.com
611986Sandreas.sandberg@arm.comdef test_smart_ptr(capture):
711986Sandreas.sandberg@arm.com    # Object1
812391Sjason@lowepower.com    for i, o in enumerate([m.make_object_1(), m.make_object_2(), m.MyObject1(3)], start=1):
911986Sandreas.sandberg@arm.com        assert o.getRefCount() == 1
1011986Sandreas.sandberg@arm.com        with capture:
1112391Sjason@lowepower.com            m.print_object_1(o)
1212391Sjason@lowepower.com            m.print_object_2(o)
1312391Sjason@lowepower.com            m.print_object_3(o)
1412391Sjason@lowepower.com            m.print_object_4(o)
1511986Sandreas.sandberg@arm.com        assert capture == "MyObject1[{i}]\n".format(i=i) * 4
1611986Sandreas.sandberg@arm.com
1712391Sjason@lowepower.com    for i, o in enumerate([m.make_myobject1_1(), m.make_myobject1_2(), m.MyObject1(6), 7],
1812391Sjason@lowepower.com                          start=4):
1911986Sandreas.sandberg@arm.com        print(o)
2011986Sandreas.sandberg@arm.com        with capture:
2111986Sandreas.sandberg@arm.com            if not isinstance(o, int):
2212391Sjason@lowepower.com                m.print_object_1(o)
2312391Sjason@lowepower.com                m.print_object_2(o)
2412391Sjason@lowepower.com                m.print_object_3(o)
2512391Sjason@lowepower.com                m.print_object_4(o)
2612391Sjason@lowepower.com            m.print_myobject1_1(o)
2712391Sjason@lowepower.com            m.print_myobject1_2(o)
2812391Sjason@lowepower.com            m.print_myobject1_3(o)
2912391Sjason@lowepower.com            m.print_myobject1_4(o)
3011986Sandreas.sandberg@arm.com        assert capture == "MyObject1[{i}]\n".format(i=i) * (4 if isinstance(o, int) else 8)
3111986Sandreas.sandberg@arm.com
3212391Sjason@lowepower.com    cstats = ConstructorStats.get(m.MyObject1)
3311986Sandreas.sandberg@arm.com    assert cstats.alive() == 0
3411986Sandreas.sandberg@arm.com    expected_values = ['MyObject1[{}]'.format(i) for i in range(1, 7)] + ['MyObject1[7]'] * 4
3511986Sandreas.sandberg@arm.com    assert cstats.values() == expected_values
3611986Sandreas.sandberg@arm.com    assert cstats.default_constructions == 0
3711986Sandreas.sandberg@arm.com    assert cstats.copy_constructions == 0
3811986Sandreas.sandberg@arm.com    # assert cstats.move_constructions >= 0 # Doesn't invoke any
3911986Sandreas.sandberg@arm.com    assert cstats.copy_assignments == 0
4011986Sandreas.sandberg@arm.com    assert cstats.move_assignments == 0
4111986Sandreas.sandberg@arm.com
4211986Sandreas.sandberg@arm.com    # Object2
4312391Sjason@lowepower.com    for i, o in zip([8, 6, 7], [m.MyObject2(8), m.make_myobject2_1(), m.make_myobject2_2()]):
4411986Sandreas.sandberg@arm.com        print(o)
4511986Sandreas.sandberg@arm.com        with capture:
4612391Sjason@lowepower.com            m.print_myobject2_1(o)
4712391Sjason@lowepower.com            m.print_myobject2_2(o)
4812391Sjason@lowepower.com            m.print_myobject2_3(o)
4912391Sjason@lowepower.com            m.print_myobject2_4(o)
5011986Sandreas.sandberg@arm.com        assert capture == "MyObject2[{i}]\n".format(i=i) * 4
5111986Sandreas.sandberg@arm.com
5212391Sjason@lowepower.com    cstats = ConstructorStats.get(m.MyObject2)
5311986Sandreas.sandberg@arm.com    assert cstats.alive() == 1
5411986Sandreas.sandberg@arm.com    o = None
5511986Sandreas.sandberg@arm.com    assert cstats.alive() == 0
5611986Sandreas.sandberg@arm.com    assert cstats.values() == ['MyObject2[8]', 'MyObject2[6]', 'MyObject2[7]']
5711986Sandreas.sandberg@arm.com    assert cstats.default_constructions == 0
5811986Sandreas.sandberg@arm.com    assert cstats.copy_constructions == 0
5911986Sandreas.sandberg@arm.com    # assert cstats.move_constructions >= 0 # Doesn't invoke any
6011986Sandreas.sandberg@arm.com    assert cstats.copy_assignments == 0
6111986Sandreas.sandberg@arm.com    assert cstats.move_assignments == 0
6211986Sandreas.sandberg@arm.com
6311986Sandreas.sandberg@arm.com    # Object3
6412391Sjason@lowepower.com    for i, o in zip([9, 8, 9], [m.MyObject3(9), m.make_myobject3_1(), m.make_myobject3_2()]):
6511986Sandreas.sandberg@arm.com        print(o)
6611986Sandreas.sandberg@arm.com        with capture:
6712391Sjason@lowepower.com            m.print_myobject3_1(o)
6812391Sjason@lowepower.com            m.print_myobject3_2(o)
6912391Sjason@lowepower.com            m.print_myobject3_3(o)
7012391Sjason@lowepower.com            m.print_myobject3_4(o)
7111986Sandreas.sandberg@arm.com        assert capture == "MyObject3[{i}]\n".format(i=i) * 4
7211986Sandreas.sandberg@arm.com
7312391Sjason@lowepower.com    cstats = ConstructorStats.get(m.MyObject3)
7411986Sandreas.sandberg@arm.com    assert cstats.alive() == 1
7511986Sandreas.sandberg@arm.com    o = None
7611986Sandreas.sandberg@arm.com    assert cstats.alive() == 0
7711986Sandreas.sandberg@arm.com    assert cstats.values() == ['MyObject3[9]', 'MyObject3[8]', 'MyObject3[9]']
7811986Sandreas.sandberg@arm.com    assert cstats.default_constructions == 0
7911986Sandreas.sandberg@arm.com    assert cstats.copy_constructions == 0
8011986Sandreas.sandberg@arm.com    # assert cstats.move_constructions >= 0 # Doesn't invoke any
8111986Sandreas.sandberg@arm.com    assert cstats.copy_assignments == 0
8211986Sandreas.sandberg@arm.com    assert cstats.move_assignments == 0
8311986Sandreas.sandberg@arm.com
8412391Sjason@lowepower.com    # Object
8512391Sjason@lowepower.com    cstats = ConstructorStats.get(m.Object)
8611986Sandreas.sandberg@arm.com    assert cstats.alive() == 0
8711986Sandreas.sandberg@arm.com    assert cstats.values() == []
8811986Sandreas.sandberg@arm.com    assert cstats.default_constructions == 10
8911986Sandreas.sandberg@arm.com    assert cstats.copy_constructions == 0
9011986Sandreas.sandberg@arm.com    # assert cstats.move_constructions >= 0 # Doesn't invoke any
9111986Sandreas.sandberg@arm.com    assert cstats.copy_assignments == 0
9211986Sandreas.sandberg@arm.com    assert cstats.move_assignments == 0
9311986Sandreas.sandberg@arm.com
9412391Sjason@lowepower.com    # ref<>
9512391Sjason@lowepower.com    cstats = m.cstats_ref()
9611986Sandreas.sandberg@arm.com    assert cstats.alive() == 0
9711986Sandreas.sandberg@arm.com    assert cstats.values() == ['from pointer'] * 10
9811986Sandreas.sandberg@arm.com    assert cstats.default_constructions == 30
9911986Sandreas.sandberg@arm.com    assert cstats.copy_constructions == 12
10011986Sandreas.sandberg@arm.com    # assert cstats.move_constructions >= 0 # Doesn't invoke any
10111986Sandreas.sandberg@arm.com    assert cstats.copy_assignments == 30
10211986Sandreas.sandberg@arm.com    assert cstats.move_assignments == 0
10311986Sandreas.sandberg@arm.com
10411986Sandreas.sandberg@arm.com
10512037Sandreas.sandberg@arm.comdef test_smart_ptr_refcounting():
10612391Sjason@lowepower.com    assert m.test_object1_refcounting()
10712037Sandreas.sandberg@arm.com
10812037Sandreas.sandberg@arm.com
10911986Sandreas.sandberg@arm.comdef test_unique_nodelete():
11012391Sjason@lowepower.com    o = m.MyObject4(23)
11111986Sandreas.sandberg@arm.com    assert o.value == 23
11212391Sjason@lowepower.com    cstats = ConstructorStats.get(m.MyObject4)
11311986Sandreas.sandberg@arm.com    assert cstats.alive() == 1
11411986Sandreas.sandberg@arm.com    del o
11511986Sandreas.sandberg@arm.com    assert cstats.alive() == 1  # Leak, but that's intentional
11611986Sandreas.sandberg@arm.com
11711986Sandreas.sandberg@arm.com
11814299Sbbruce@ucdavis.edudef test_unique_nodelete4a():
11914299Sbbruce@ucdavis.edu    o = m.MyObject4a(23)
12014299Sbbruce@ucdavis.edu    assert o.value == 23
12114299Sbbruce@ucdavis.edu    cstats = ConstructorStats.get(m.MyObject4a)
12214299Sbbruce@ucdavis.edu    assert cstats.alive() == 1
12314299Sbbruce@ucdavis.edu    del o
12414299Sbbruce@ucdavis.edu    assert cstats.alive() == 1  # Leak, but that's intentional
12514299Sbbruce@ucdavis.edu
12614299Sbbruce@ucdavis.edu
12714299Sbbruce@ucdavis.edudef test_unique_deleter():
12814299Sbbruce@ucdavis.edu    o = m.MyObject4b(23)
12914299Sbbruce@ucdavis.edu    assert o.value == 23
13014299Sbbruce@ucdavis.edu    cstats4a = ConstructorStats.get(m.MyObject4a)
13114299Sbbruce@ucdavis.edu    assert cstats4a.alive() == 2  # Two because of previous test
13214299Sbbruce@ucdavis.edu    cstats4b = ConstructorStats.get(m.MyObject4b)
13314299Sbbruce@ucdavis.edu    assert cstats4b.alive() == 1
13414299Sbbruce@ucdavis.edu    del o
13514299Sbbruce@ucdavis.edu    assert cstats4a.alive() == 1  # Should now only be one leftover from previous test
13614299Sbbruce@ucdavis.edu    assert cstats4b.alive() == 0  # Should be deleted
13714299Sbbruce@ucdavis.edu
13814299Sbbruce@ucdavis.edu
13912391Sjason@lowepower.comdef test_large_holder():
14012391Sjason@lowepower.com    o = m.MyObject5(5)
14112391Sjason@lowepower.com    assert o.value == 5
14212391Sjason@lowepower.com    cstats = ConstructorStats.get(m.MyObject5)
14312391Sjason@lowepower.com    assert cstats.alive() == 1
14412391Sjason@lowepower.com    del o
14512391Sjason@lowepower.com    assert cstats.alive() == 0
14612391Sjason@lowepower.com
14712391Sjason@lowepower.com
14811986Sandreas.sandberg@arm.comdef test_shared_ptr_and_references():
14912391Sjason@lowepower.com    s = m.SharedPtrRef()
15012391Sjason@lowepower.com    stats = ConstructorStats.get(m.A)
15111986Sandreas.sandberg@arm.com    assert stats.alive() == 2
15211986Sandreas.sandberg@arm.com
15311986Sandreas.sandberg@arm.com    ref = s.ref  # init_holder_helper(holder_ptr=false, owned=false)
15411986Sandreas.sandberg@arm.com    assert stats.alive() == 2
15511986Sandreas.sandberg@arm.com    assert s.set_ref(ref)
15611986Sandreas.sandberg@arm.com    with pytest.raises(RuntimeError) as excinfo:
15711986Sandreas.sandberg@arm.com        assert s.set_holder(ref)
15811986Sandreas.sandberg@arm.com    assert "Unable to cast from non-held to held instance" in str(excinfo.value)
15911986Sandreas.sandberg@arm.com
16011986Sandreas.sandberg@arm.com    copy = s.copy  # init_holder_helper(holder_ptr=false, owned=true)
16111986Sandreas.sandberg@arm.com    assert stats.alive() == 3
16211986Sandreas.sandberg@arm.com    assert s.set_ref(copy)
16311986Sandreas.sandberg@arm.com    assert s.set_holder(copy)
16411986Sandreas.sandberg@arm.com
16511986Sandreas.sandberg@arm.com    holder_ref = s.holder_ref  # init_holder_helper(holder_ptr=true, owned=false)
16611986Sandreas.sandberg@arm.com    assert stats.alive() == 3
16711986Sandreas.sandberg@arm.com    assert s.set_ref(holder_ref)
16811986Sandreas.sandberg@arm.com    assert s.set_holder(holder_ref)
16911986Sandreas.sandberg@arm.com
17011986Sandreas.sandberg@arm.com    holder_copy = s.holder_copy  # init_holder_helper(holder_ptr=true, owned=true)
17111986Sandreas.sandberg@arm.com    assert stats.alive() == 3
17211986Sandreas.sandberg@arm.com    assert s.set_ref(holder_copy)
17311986Sandreas.sandberg@arm.com    assert s.set_holder(holder_copy)
17411986Sandreas.sandberg@arm.com
17511986Sandreas.sandberg@arm.com    del ref, copy, holder_ref, holder_copy, s
17611986Sandreas.sandberg@arm.com    assert stats.alive() == 0
17711986Sandreas.sandberg@arm.com
17811986Sandreas.sandberg@arm.com
17911986Sandreas.sandberg@arm.comdef test_shared_ptr_from_this_and_references():
18012391Sjason@lowepower.com    s = m.SharedFromThisRef()
18112391Sjason@lowepower.com    stats = ConstructorStats.get(m.B)
18211986Sandreas.sandberg@arm.com    assert stats.alive() == 2
18311986Sandreas.sandberg@arm.com
18411986Sandreas.sandberg@arm.com    ref = s.ref  # init_holder_helper(holder_ptr=false, owned=false, bad_wp=false)
18511986Sandreas.sandberg@arm.com    assert stats.alive() == 2
18611986Sandreas.sandberg@arm.com    assert s.set_ref(ref)
18711986Sandreas.sandberg@arm.com    assert s.set_holder(ref)  # std::enable_shared_from_this can create a holder from a reference
18811986Sandreas.sandberg@arm.com
18911986Sandreas.sandberg@arm.com    bad_wp = s.bad_wp  # init_holder_helper(holder_ptr=false, owned=false, bad_wp=true)
19011986Sandreas.sandberg@arm.com    assert stats.alive() == 2
19111986Sandreas.sandberg@arm.com    assert s.set_ref(bad_wp)
19211986Sandreas.sandberg@arm.com    with pytest.raises(RuntimeError) as excinfo:
19311986Sandreas.sandberg@arm.com        assert s.set_holder(bad_wp)
19411986Sandreas.sandberg@arm.com    assert "Unable to cast from non-held to held instance" in str(excinfo.value)
19511986Sandreas.sandberg@arm.com
19611986Sandreas.sandberg@arm.com    copy = s.copy  # init_holder_helper(holder_ptr=false, owned=true, bad_wp=false)
19711986Sandreas.sandberg@arm.com    assert stats.alive() == 3
19811986Sandreas.sandberg@arm.com    assert s.set_ref(copy)
19911986Sandreas.sandberg@arm.com    assert s.set_holder(copy)
20011986Sandreas.sandberg@arm.com
20111986Sandreas.sandberg@arm.com    holder_ref = s.holder_ref  # init_holder_helper(holder_ptr=true, owned=false, bad_wp=false)
20211986Sandreas.sandberg@arm.com    assert stats.alive() == 3
20311986Sandreas.sandberg@arm.com    assert s.set_ref(holder_ref)
20411986Sandreas.sandberg@arm.com    assert s.set_holder(holder_ref)
20511986Sandreas.sandberg@arm.com
20611986Sandreas.sandberg@arm.com    holder_copy = s.holder_copy  # init_holder_helper(holder_ptr=true, owned=true, bad_wp=false)
20711986Sandreas.sandberg@arm.com    assert stats.alive() == 3
20811986Sandreas.sandberg@arm.com    assert s.set_ref(holder_copy)
20911986Sandreas.sandberg@arm.com    assert s.set_holder(holder_copy)
21011986Sandreas.sandberg@arm.com
21111986Sandreas.sandberg@arm.com    del ref, bad_wp, copy, holder_ref, holder_copy, s
21211986Sandreas.sandberg@arm.com    assert stats.alive() == 0
21312037Sandreas.sandberg@arm.com
21412391Sjason@lowepower.com    z = m.SharedFromThisVirt.get()
21512391Sjason@lowepower.com    y = m.SharedFromThisVirt.get()
21612391Sjason@lowepower.com    assert y is z
21712391Sjason@lowepower.com
21812037Sandreas.sandberg@arm.com
21912037Sandreas.sandberg@arm.comdef test_move_only_holder():
22012391Sjason@lowepower.com    a = m.TypeWithMoveOnlyHolder.make()
22112391Sjason@lowepower.com    stats = ConstructorStats.get(m.TypeWithMoveOnlyHolder)
22212037Sandreas.sandberg@arm.com    assert stats.alive() == 1
22312037Sandreas.sandberg@arm.com    del a
22412037Sandreas.sandberg@arm.com    assert stats.alive() == 0
22512037Sandreas.sandberg@arm.com
22612037Sandreas.sandberg@arm.com
22714299Sbbruce@ucdavis.edudef test_holder_with_addressof_operator():
22814299Sbbruce@ucdavis.edu    # this test must not throw exception from c++
22914299Sbbruce@ucdavis.edu    a = m.TypeForHolderWithAddressOf.make()
23014299Sbbruce@ucdavis.edu    a.print_object_1()
23114299Sbbruce@ucdavis.edu    a.print_object_2()
23214299Sbbruce@ucdavis.edu    a.print_object_3()
23314299Sbbruce@ucdavis.edu    a.print_object_4()
23414299Sbbruce@ucdavis.edu
23514299Sbbruce@ucdavis.edu    stats = ConstructorStats.get(m.TypeForHolderWithAddressOf)
23614299Sbbruce@ucdavis.edu    assert stats.alive() == 1
23714299Sbbruce@ucdavis.edu
23814299Sbbruce@ucdavis.edu    np = m.TypeForHolderWithAddressOf.make()
23914299Sbbruce@ucdavis.edu    assert stats.alive() == 2
24014299Sbbruce@ucdavis.edu    del a
24114299Sbbruce@ucdavis.edu    assert stats.alive() == 1
24214299Sbbruce@ucdavis.edu    del np
24314299Sbbruce@ucdavis.edu    assert stats.alive() == 0
24414299Sbbruce@ucdavis.edu
24514299Sbbruce@ucdavis.edu    b = m.TypeForHolderWithAddressOf.make()
24614299Sbbruce@ucdavis.edu    c = b
24714299Sbbruce@ucdavis.edu    assert b.get() is c.get()
24814299Sbbruce@ucdavis.edu    assert stats.alive() == 1
24914299Sbbruce@ucdavis.edu
25014299Sbbruce@ucdavis.edu    del b
25114299Sbbruce@ucdavis.edu    assert stats.alive() == 1
25214299Sbbruce@ucdavis.edu
25314299Sbbruce@ucdavis.edu    del c
25414299Sbbruce@ucdavis.edu    assert stats.alive() == 0
25514299Sbbruce@ucdavis.edu
25614299Sbbruce@ucdavis.edu
25714299Sbbruce@ucdavis.edudef test_move_only_holder_with_addressof_operator():
25814299Sbbruce@ucdavis.edu    a = m.TypeForMoveOnlyHolderWithAddressOf.make()
25914299Sbbruce@ucdavis.edu    a.print_object()
26014299Sbbruce@ucdavis.edu
26114299Sbbruce@ucdavis.edu    stats = ConstructorStats.get(m.TypeForMoveOnlyHolderWithAddressOf)
26214299Sbbruce@ucdavis.edu    assert stats.alive() == 1
26314299Sbbruce@ucdavis.edu
26414299Sbbruce@ucdavis.edu    a.value = 42
26514299Sbbruce@ucdavis.edu    assert a.value == 42
26614299Sbbruce@ucdavis.edu
26714299Sbbruce@ucdavis.edu    del a
26814299Sbbruce@ucdavis.edu    assert stats.alive() == 0
26914299Sbbruce@ucdavis.edu
27014299Sbbruce@ucdavis.edu
27112037Sandreas.sandberg@arm.comdef test_smart_ptr_from_default():
27212391Sjason@lowepower.com    instance = m.HeldByDefaultHolder()
27312391Sjason@lowepower.com    with pytest.raises(RuntimeError) as excinfo:
27412391Sjason@lowepower.com        m.HeldByDefaultHolder.load_shared_ptr(instance)
27514299Sbbruce@ucdavis.edu    assert "Unable to load a custom holder type from a " \
27614299Sbbruce@ucdavis.edu           "default-holder instance" in str(excinfo.value)
27712037Sandreas.sandberg@arm.com
27812391Sjason@lowepower.com
27912391Sjason@lowepower.comdef test_shared_ptr_gc():
28012391Sjason@lowepower.com    """#187: issue involving std::shared_ptr<> return value policy & garbage collection"""
28112391Sjason@lowepower.com    el = m.ElementList()
28212391Sjason@lowepower.com    for i in range(10):
28312391Sjason@lowepower.com        el.add(m.ElementA(i))
28412391Sjason@lowepower.com    pytest.gc_collect()
28512391Sjason@lowepower.com    for i, v in enumerate(el.get()):
28612391Sjason@lowepower.com        assert i == v.value()
287