diff --git a/test/test_rand_templates.py b/test/test_rand_templates.py new file mode 100644 index 00000000..b0eacd55 --- /dev/null +++ b/test/test_rand_templates.py @@ -0,0 +1,108 @@ +import hypothesis +from hypothesis import given, settings, example, note, strategies as st +import cppyy +import pytest + +cppyy.include("limits") + +cppyy.cppdef(""" + namespace test { + template + constexpr std::size_t tuple_size(const T&) { + return std::tuple_size::value; + } + + constexpr bool as_bool(auto b) { + return static_cast(b); + } + + template + struct list { + template + constexpr auto operator==(list) const -> bool { + return false; + } + + constexpr auto operator==(list) const -> bool { + return true; + } + }; + + template + constexpr auto make_list(Ts...) { + return list{}; + } + + template + constexpr auto cat(list, list) { + return list{}; + } + } // namespace test +""") + +std = cppyy.gbl.std +test = cppyy.gbl.test + +bools = st.booleans().map(lambda v: test.as_bool(v)) + +def make_c_type_strat(t): + min_val = std.numeric_limits[t].min() + max_val = std.numeric_limits[t].max() + return st.integers(min_value=int(min_val), max_value=int(max_val)).map(lambda v: t(v)) + +int16s = make_c_type_strat(std.int16_t) +int32s = make_c_type_strat(std.int32_t) +int64s = make_c_type_strat(std.int64_t) + +uint16s = make_c_type_strat(std.uint16_t) +uint32s = make_c_type_strat(std.uint32_t) +uint64s = make_c_type_strat(std.uint64_t) + +cpp_primitives = st.one_of(bools, int16s, int32s, int64s, uint16s, uint32s, uint64s) + +def as_std_tuple_tree(value): + if isinstance(value, list): + values = [as_std_tuple_tree(v) for v in value] + return std.make_tuple(*values) + else: + return value + + +def as_test_list_tree(value): + if isinstance(value, list): + values = [as_test_list_tree(v) for v in value] + return test.make_list(*values) + else: + return value + +@st.composite +def py_list_trees(draw, leaves=cpp_primitives): + t = draw(st.recursive(leaves, lambda children: st.lists(children))) + + if not isinstance(t, list): + t = [t] + + return t + + +@given(st.lists(cpp_primitives)) +def test_std_tuple_size(pytestconfig, ints): + assert test.tuple_size(std.make_tuple(*ints)) == len(ints) + + +@settings(deadline=2000, max_examples=100) +@given(py_list_trees(), py_list_trees()) +@example([0], [[], []]) +def test_std_tuple_cat(pytestconfig, left, right): + expected = as_std_tuple_tree(left + right) + actual = std.tuple_cat(as_std_tuple_tree(left), as_std_tuple_tree(right)) + assert actual == expected + + +@settings(deadline=2000, max_examples=100) +@given(py_list_trees(), py_list_trees()) +@example([0], [[], []]) +def test_list_cat(pytestconfig, left, right): + expected = as_test_list_tree(left + right) + actual = test.cat(as_test_list_tree(left), as_test_list_tree(right)) + assert actual == expected