114299Sbbruce@ucdavis.edufrom __future__ import division
212391Sjason@lowepower.comimport pytest
312391Sjason@lowepower.comimport sys
412391Sjason@lowepower.com
512391Sjason@lowepower.comfrom pybind11_tests import pytypes as m
612391Sjason@lowepower.comfrom pybind11_tests import debug_enabled
712391Sjason@lowepower.com
812391Sjason@lowepower.com
912391Sjason@lowepower.comdef test_list(capture, doc):
1012391Sjason@lowepower.com    with capture:
1114299Sbbruce@ucdavis.edu        lst = m.get_list()
1214299Sbbruce@ucdavis.edu        assert lst == ["inserted-0", "overwritten", "inserted-2"]
1312391Sjason@lowepower.com
1414299Sbbruce@ucdavis.edu        lst.append("value2")
1514299Sbbruce@ucdavis.edu        m.print_list(lst)
1612391Sjason@lowepower.com    assert capture.unordered == """
1712391Sjason@lowepower.com        Entry at position 0: value
1814299Sbbruce@ucdavis.edu        list item 0: inserted-0
1914299Sbbruce@ucdavis.edu        list item 1: overwritten
2014299Sbbruce@ucdavis.edu        list item 2: inserted-2
2114299Sbbruce@ucdavis.edu        list item 3: value2
2212391Sjason@lowepower.com    """
2312391Sjason@lowepower.com
2412391Sjason@lowepower.com    assert doc(m.get_list) == "get_list() -> list"
2512391Sjason@lowepower.com    assert doc(m.print_list) == "print_list(arg0: list) -> None"
2612391Sjason@lowepower.com
2712391Sjason@lowepower.com
2812391Sjason@lowepower.comdef test_set(capture, doc):
2912391Sjason@lowepower.com    s = m.get_set()
3012391Sjason@lowepower.com    assert s == {"key1", "key2", "key3"}
3112391Sjason@lowepower.com
3212391Sjason@lowepower.com    with capture:
3312391Sjason@lowepower.com        s.add("key4")
3412391Sjason@lowepower.com        m.print_set(s)
3512391Sjason@lowepower.com    assert capture.unordered == """
3612391Sjason@lowepower.com        key: key1
3712391Sjason@lowepower.com        key: key2
3812391Sjason@lowepower.com        key: key3
3912391Sjason@lowepower.com        key: key4
4012391Sjason@lowepower.com    """
4112391Sjason@lowepower.com
4214299Sbbruce@ucdavis.edu    assert not m.set_contains(set([]), 42)
4314299Sbbruce@ucdavis.edu    assert m.set_contains({42}, 42)
4414299Sbbruce@ucdavis.edu    assert m.set_contains({"foo"}, "foo")
4514299Sbbruce@ucdavis.edu
4612391Sjason@lowepower.com    assert doc(m.get_list) == "get_list() -> list"
4712391Sjason@lowepower.com    assert doc(m.print_list) == "print_list(arg0: list) -> None"
4812391Sjason@lowepower.com
4912391Sjason@lowepower.com
5012391Sjason@lowepower.comdef test_dict(capture, doc):
5112391Sjason@lowepower.com    d = m.get_dict()
5212391Sjason@lowepower.com    assert d == {"key": "value"}
5312391Sjason@lowepower.com
5412391Sjason@lowepower.com    with capture:
5512391Sjason@lowepower.com        d["key2"] = "value2"
5612391Sjason@lowepower.com        m.print_dict(d)
5712391Sjason@lowepower.com    assert capture.unordered == """
5812391Sjason@lowepower.com        key: key, value=value
5912391Sjason@lowepower.com        key: key2, value=value2
6012391Sjason@lowepower.com    """
6112391Sjason@lowepower.com
6214299Sbbruce@ucdavis.edu    assert not m.dict_contains({}, 42)
6314299Sbbruce@ucdavis.edu    assert m.dict_contains({42: None}, 42)
6414299Sbbruce@ucdavis.edu    assert m.dict_contains({"foo": None}, "foo")
6514299Sbbruce@ucdavis.edu
6612391Sjason@lowepower.com    assert doc(m.get_dict) == "get_dict() -> dict"
6712391Sjason@lowepower.com    assert doc(m.print_dict) == "print_dict(arg0: dict) -> None"
6812391Sjason@lowepower.com
6912391Sjason@lowepower.com    assert m.dict_keyword_constructor() == {"x": 1, "y": 2, "z": 3}
7012391Sjason@lowepower.com
7112391Sjason@lowepower.com
7212391Sjason@lowepower.comdef test_str(doc):
7312391Sjason@lowepower.com    assert m.str_from_string().encode().decode() == "baz"
7412391Sjason@lowepower.com    assert m.str_from_bytes().encode().decode() == "boo"
7512391Sjason@lowepower.com
7612391Sjason@lowepower.com    assert doc(m.str_from_bytes) == "str_from_bytes() -> str"
7712391Sjason@lowepower.com
7812391Sjason@lowepower.com    class A(object):
7912391Sjason@lowepower.com        def __str__(self):
8012391Sjason@lowepower.com            return "this is a str"
8112391Sjason@lowepower.com
8212391Sjason@lowepower.com        def __repr__(self):
8312391Sjason@lowepower.com            return "this is a repr"
8412391Sjason@lowepower.com
8512391Sjason@lowepower.com    assert m.str_from_object(A()) == "this is a str"
8612391Sjason@lowepower.com    assert m.repr_from_object(A()) == "this is a repr"
8712391Sjason@lowepower.com
8812391Sjason@lowepower.com    s1, s2 = m.str_format()
8912391Sjason@lowepower.com    assert s1 == "1 + 2 = 3"
9012391Sjason@lowepower.com    assert s1 == s2
9112391Sjason@lowepower.com
9212391Sjason@lowepower.com
9312391Sjason@lowepower.comdef test_bytes(doc):
9412391Sjason@lowepower.com    assert m.bytes_from_string().decode() == "foo"
9512391Sjason@lowepower.com    assert m.bytes_from_str().decode() == "bar"
9612391Sjason@lowepower.com
9712391Sjason@lowepower.com    assert doc(m.bytes_from_str) == "bytes_from_str() -> {}".format(
9812391Sjason@lowepower.com        "bytes" if sys.version_info[0] == 3 else "str"
9912391Sjason@lowepower.com    )
10012391Sjason@lowepower.com
10112391Sjason@lowepower.com
10212391Sjason@lowepower.comdef test_capsule(capture):
10312391Sjason@lowepower.com    pytest.gc_collect()
10412391Sjason@lowepower.com    with capture:
10512391Sjason@lowepower.com        a = m.return_capsule_with_destructor()
10612391Sjason@lowepower.com        del a
10712391Sjason@lowepower.com        pytest.gc_collect()
10812391Sjason@lowepower.com    assert capture.unordered == """
10912391Sjason@lowepower.com        creating capsule
11012391Sjason@lowepower.com        destructing capsule
11112391Sjason@lowepower.com    """
11212391Sjason@lowepower.com
11312391Sjason@lowepower.com    with capture:
11412391Sjason@lowepower.com        a = m.return_capsule_with_destructor_2()
11512391Sjason@lowepower.com        del a
11612391Sjason@lowepower.com        pytest.gc_collect()
11712391Sjason@lowepower.com    assert capture.unordered == """
11812391Sjason@lowepower.com        creating capsule
11912391Sjason@lowepower.com        destructing capsule: 1234
12012391Sjason@lowepower.com    """
12112391Sjason@lowepower.com
12212391Sjason@lowepower.com    with capture:
12312391Sjason@lowepower.com        a = m.return_capsule_with_name_and_destructor()
12412391Sjason@lowepower.com        del a
12512391Sjason@lowepower.com        pytest.gc_collect()
12612391Sjason@lowepower.com    assert capture.unordered == """
12712391Sjason@lowepower.com        created capsule (1234, 'pointer type description')
12812391Sjason@lowepower.com        destructing capsule (1234, 'pointer type description')
12912391Sjason@lowepower.com    """
13012391Sjason@lowepower.com
13112391Sjason@lowepower.com
13212391Sjason@lowepower.comdef test_accessors():
13312391Sjason@lowepower.com    class SubTestObject:
13412391Sjason@lowepower.com        attr_obj = 1
13512391Sjason@lowepower.com        attr_char = 2
13612391Sjason@lowepower.com
13712391Sjason@lowepower.com    class TestObject:
13812391Sjason@lowepower.com        basic_attr = 1
13912391Sjason@lowepower.com        begin_end = [1, 2, 3]
14012391Sjason@lowepower.com        d = {"operator[object]": 1, "operator[char *]": 2}
14112391Sjason@lowepower.com        sub = SubTestObject()
14212391Sjason@lowepower.com
14312391Sjason@lowepower.com        def func(self, x, *args):
14412391Sjason@lowepower.com            return self.basic_attr + x + sum(args)
14512391Sjason@lowepower.com
14612391Sjason@lowepower.com    d = m.accessor_api(TestObject())
14712391Sjason@lowepower.com    assert d["basic_attr"] == 1
14812391Sjason@lowepower.com    assert d["begin_end"] == [1, 2, 3]
14912391Sjason@lowepower.com    assert d["operator[object]"] == 1
15012391Sjason@lowepower.com    assert d["operator[char *]"] == 2
15112391Sjason@lowepower.com    assert d["attr(object)"] == 1
15212391Sjason@lowepower.com    assert d["attr(char *)"] == 2
15312391Sjason@lowepower.com    assert d["missing_attr_ptr"] == "raised"
15412391Sjason@lowepower.com    assert d["missing_attr_chain"] == "raised"
15512391Sjason@lowepower.com    assert d["is_none"] is False
15612391Sjason@lowepower.com    assert d["operator()"] == 2
15712391Sjason@lowepower.com    assert d["operator*"] == 7
15812391Sjason@lowepower.com    assert d["implicit_list"] == [1, 2, 3]
15912391Sjason@lowepower.com    assert all(x in TestObject.__dict__ for x in d["implicit_dict"])
16012391Sjason@lowepower.com
16112391Sjason@lowepower.com    assert m.tuple_accessor(tuple()) == (0, 1, 2)
16212391Sjason@lowepower.com
16312391Sjason@lowepower.com    d = m.accessor_assignment()
16412391Sjason@lowepower.com    assert d["get"] == 0
16512391Sjason@lowepower.com    assert d["deferred_get"] == 0
16612391Sjason@lowepower.com    assert d["set"] == 1
16712391Sjason@lowepower.com    assert d["deferred_set"] == 1
16812391Sjason@lowepower.com    assert d["var"] == 99
16912391Sjason@lowepower.com
17012391Sjason@lowepower.com
17112391Sjason@lowepower.comdef test_constructors():
17212391Sjason@lowepower.com    """C++ default and converting constructors are equivalent to type calls in Python"""
17312391Sjason@lowepower.com    types = [str, bool, int, float, tuple, list, dict, set]
17412391Sjason@lowepower.com    expected = {t.__name__: t() for t in types}
17512391Sjason@lowepower.com    assert m.default_constructors() == expected
17612391Sjason@lowepower.com
17712391Sjason@lowepower.com    data = {
17812391Sjason@lowepower.com        str: 42,
17912391Sjason@lowepower.com        bool: "Not empty",
18012391Sjason@lowepower.com        int: "42",
18112391Sjason@lowepower.com        float: "+1e3",
18212391Sjason@lowepower.com        tuple: range(3),
18312391Sjason@lowepower.com        list: range(3),
18412391Sjason@lowepower.com        dict: [("two", 2), ("one", 1), ("three", 3)],
18512391Sjason@lowepower.com        set: [4, 4, 5, 6, 6, 6],
18612391Sjason@lowepower.com        memoryview: b'abc'
18712391Sjason@lowepower.com    }
18812391Sjason@lowepower.com    inputs = {k.__name__: v for k, v in data.items()}
18912391Sjason@lowepower.com    expected = {k.__name__: k(v) for k, v in data.items()}
19012391Sjason@lowepower.com
19112391Sjason@lowepower.com    assert m.converting_constructors(inputs) == expected
19212391Sjason@lowepower.com    assert m.cast_functions(inputs) == expected
19312391Sjason@lowepower.com
19412391Sjason@lowepower.com    # Converting constructors and cast functions should just reference rather
19512391Sjason@lowepower.com    # than copy when no conversion is needed:
19612391Sjason@lowepower.com    noconv1 = m.converting_constructors(expected)
19712391Sjason@lowepower.com    for k in noconv1:
19812391Sjason@lowepower.com        assert noconv1[k] is expected[k]
19912391Sjason@lowepower.com
20012391Sjason@lowepower.com    noconv2 = m.cast_functions(expected)
20112391Sjason@lowepower.com    for k in noconv2:
20212391Sjason@lowepower.com        assert noconv2[k] is expected[k]
20312391Sjason@lowepower.com
20412391Sjason@lowepower.com
20512391Sjason@lowepower.comdef test_implicit_casting():
20612391Sjason@lowepower.com    """Tests implicit casting when assigning or appending to dicts and lists."""
20712391Sjason@lowepower.com    z = m.get_implicit_casting()
20812391Sjason@lowepower.com    assert z['d'] == {
20912391Sjason@lowepower.com        'char*_i1': 'abc', 'char*_i2': 'abc', 'char*_e': 'abc', 'char*_p': 'abc',
21012391Sjason@lowepower.com        'str_i1': 'str', 'str_i2': 'str1', 'str_e': 'str2', 'str_p': 'str3',
21112391Sjason@lowepower.com        'int_i1': 42, 'int_i2': 42, 'int_e': 43, 'int_p': 44
21212391Sjason@lowepower.com    }
21312391Sjason@lowepower.com    assert z['l'] == [3, 6, 9, 12, 15]
21412391Sjason@lowepower.com
21512391Sjason@lowepower.com
21612391Sjason@lowepower.comdef test_print(capture):
21712391Sjason@lowepower.com    with capture:
21812391Sjason@lowepower.com        m.print_function()
21912391Sjason@lowepower.com    assert capture == """
22012391Sjason@lowepower.com        Hello, World!
22112391Sjason@lowepower.com        1 2.0 three True -- multiple args
22212391Sjason@lowepower.com        *args-and-a-custom-separator
22312391Sjason@lowepower.com        no new line here -- next print
22412391Sjason@lowepower.com        flush
22512391Sjason@lowepower.com        py::print + str.format = this
22612391Sjason@lowepower.com    """
22712391Sjason@lowepower.com    assert capture.stderr == "this goes to stderr"
22812391Sjason@lowepower.com
22912391Sjason@lowepower.com    with pytest.raises(RuntimeError) as excinfo:
23012391Sjason@lowepower.com        m.print_failure()
23112391Sjason@lowepower.com    assert str(excinfo.value) == "make_tuple(): unable to convert " + (
23212391Sjason@lowepower.com        "argument of type 'UnregisteredType' to Python object"
23312391Sjason@lowepower.com        if debug_enabled else
23412391Sjason@lowepower.com        "arguments to Python object (compile in debug mode for details)"
23512391Sjason@lowepower.com    )
23612391Sjason@lowepower.com
23712391Sjason@lowepower.com
23812391Sjason@lowepower.comdef test_hash():
23912391Sjason@lowepower.com    class Hashable(object):
24012391Sjason@lowepower.com        def __init__(self, value):
24112391Sjason@lowepower.com            self.value = value
24212391Sjason@lowepower.com
24312391Sjason@lowepower.com        def __hash__(self):
24412391Sjason@lowepower.com            return self.value
24512391Sjason@lowepower.com
24612391Sjason@lowepower.com    class Unhashable(object):
24712391Sjason@lowepower.com        __hash__ = None
24812391Sjason@lowepower.com
24912391Sjason@lowepower.com    assert m.hash_function(Hashable(42)) == 42
25012391Sjason@lowepower.com    with pytest.raises(TypeError):
25112391Sjason@lowepower.com        m.hash_function(Unhashable())
25214299Sbbruce@ucdavis.edu
25314299Sbbruce@ucdavis.edu
25414299Sbbruce@ucdavis.edudef test_number_protocol():
25514299Sbbruce@ucdavis.edu    for a, b in [(1, 1), (3, 5)]:
25614299Sbbruce@ucdavis.edu        li = [a == b, a != b, a < b, a <= b, a > b, a >= b, a + b,
25714299Sbbruce@ucdavis.edu              a - b, a * b, a / b, a | b, a & b, a ^ b, a >> b, a << b]
25814299Sbbruce@ucdavis.edu        assert m.test_number_protocol(a, b) == li
25914299Sbbruce@ucdavis.edu
26014299Sbbruce@ucdavis.edu
26114299Sbbruce@ucdavis.edudef test_list_slicing():
26214299Sbbruce@ucdavis.edu    li = list(range(100))
26314299Sbbruce@ucdavis.edu    assert li[::2] == m.test_list_slicing(li)
264