Skip to content

Commit

Permalink
Add a few property based tests stressing template parameter packs.
Browse files Browse the repository at this point in the history
Requires the `hypothesis` python module.
  • Loading branch information
lukevalenty committed Oct 1, 2024
1 parent 9553581 commit 0e572cd
Showing 1 changed file with 108 additions and 0 deletions.
108 changes: 108 additions & 0 deletions test/test_rand_templates.py
Original file line number Diff line number Diff line change
@@ -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 <typename T>
constexpr std::size_t tuple_size(const T&) {
return std::tuple_size<T>::value;
}
constexpr bool as_bool(auto b) {
return static_cast<bool>(b);
}
template<typename... Ts>
struct list {
template<typename... Us>
constexpr auto operator==(list<Us...>) const -> bool {
return false;
}
constexpr auto operator==(list<Ts...>) const -> bool {
return true;
}
};
template<typename... Ts>
constexpr auto make_list(Ts...) {
return list<Ts...>{};
}
template<typename... Ls, typename... Rs>
constexpr auto cat(list<Ls...>, list<Rs...>) {
return list<Ls..., Rs...>{};
}
} // 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

0 comments on commit 0e572cd

Please sign in to comment.