21#include <cuspatial/traits.hpp>
23#include <cuspatial_test/test_util.cuh>
25#include <rmm/device_uvector.hpp>
26#include <rmm/device_vector.hpp>
28#include <thrust/host_vector.h>
30#include <gmock/gmock.h>
31#include <gtest/gtest.h>
46auto floating_eq_by_ulp(T val)
48 if constexpr (std::is_same_v<T, float>) {
49 return ::testing::NanSensitiveFloatEq(val);
51 return ::testing::NanSensitiveDoubleEq(val);
59auto floating_eq_by_abs_error(T val, T abs_error)
61 if constexpr (std::is_same_v<T, float>) {
62 return ::testing::NanSensitiveFloatNear(val, abs_error);
64 return ::testing::NanSensitiveDoubleNear(val, abs_error);
68MATCHER(vec_2d_matcher,
69 std::string(negation ?
"are not" :
"are") +
" approximately equal vec_2d structs")
71 auto lhs = std::get<0>(arg);
72 auto rhs = std::get<1>(arg);
74 if (::testing::Matches(floating_eq_by_ulp(rhs.x))(lhs.x) &&
75 ::testing::Matches(floating_eq_by_ulp(rhs.y))(lhs.y))
78 *result_listener << std::fixed
79 << std::setprecision(std::numeric_limits<
decltype(lhs)>::max_digits10) << lhs
85MATCHER_P(vec_2d_near_matcher,
87 std::string(negation ?
"are not" :
"are") +
" approximately equal vec_2d structs")
89 auto lhs = std::get<0>(arg);
90 auto rhs = std::get<1>(arg);
92 if (::testing::Matches(floating_eq_by_abs_error(rhs.x, abs_error))(lhs.x) &&
93 ::testing::Matches(floating_eq_by_abs_error(rhs.y, abs_error))(lhs.y))
96 *result_listener << std::fixed
97 << std::setprecision(std::numeric_limits<
decltype(lhs)>::max_digits10) << lhs
103MATCHER(float_matcher, std::string(negation ?
"are not" :
"are") +
" approximately equal floats")
105 auto lhs = std::get<0>(arg);
106 auto rhs = std::get<1>(arg);
108 if (::testing::Matches(floating_eq_by_ulp(rhs))(lhs))
return true;
110 *result_listener << std::fixed
111 << std::setprecision(std::numeric_limits<
decltype(lhs)>::max_digits10) << lhs
117MATCHER_P(float_near_matcher,
119 std::string(negation ?
"are not" :
"are") +
" approximately equal floats")
121 auto lhs = std::get<0>(arg);
122 auto rhs = std::get<1>(arg);
124 if (::testing::Matches(floating_eq_by_abs_error(rhs, abs_error))(lhs))
return true;
126 *result_listener << std::fixed
127 << std::setprecision(std::numeric_limits<
decltype(lhs)>::max_digits10) << lhs
133MATCHER_P(optional_matcher, m, std::string(negation ?
"are not" :
"are") +
" equal optionals")
135 auto lhs = std::get<0>(arg);
136 auto rhs = std::get<1>(arg);
138 if (lhs.has_value() != rhs.has_value()) {
139 *result_listener <<
"lhs " << (lhs.has_value() ?
"" :
"does not ") <<
"has value, while rhs "
140 << (rhs.has_value() ?
"" :
"does not ") <<
"has value.";
142 }
else if (!lhs.has_value() && !rhs.has_value()) {
145 return ExplainMatchResult(m, std::tuple(lhs.value(), rhs.value()), result_listener);
148template <
typename Vector1,
typename Vector2>
149inline void expect_vector_equivalent(Vector1
const& lhs, Vector2
const& rhs)
151 using T =
typename Vector1::value_type;
152 static_assert(std::is_same_v<T, typename Vector2::value_type>,
"Value type mismatch.");
154 if constexpr (cuspatial::is_vec_2d<T>) {
155 EXPECT_THAT(to_host<T>(lhs), ::testing::Pointwise(vec_2d_matcher(), to_host<T>(rhs)));
156 }
else if constexpr (std::is_floating_point_v<T>) {
157 EXPECT_THAT(to_host<T>(lhs), ::testing::Pointwise(float_matcher(), to_host<T>(rhs)));
158 }
else if constexpr (std::is_integral_v<T>) {
159 EXPECT_THAT(to_host<T>(lhs), ::testing::Pointwise(::testing::Eq(), to_host<T>(rhs)));
160 }
else if constexpr (cuspatial::is_optional<T>) {
161 if constexpr (cuspatial::is_vec_2d<typename T::value_type>) {
162 EXPECT_THAT(to_host<T>(lhs),
163 ::testing::Pointwise(optional_matcher(vec_2d_matcher()), to_host<T>(rhs)));
164 }
else if constexpr (std::is_floating_point_v<typename T::value_type>) {
165 EXPECT_THAT(to_host<T>(lhs),
166 ::testing::Pointwise(optional_matcher(float_matcher()), to_host<T>(rhs)));
167 }
else if constexpr (std::is_integral_v<typename T::value_type>) {
168 EXPECT_THAT(to_host<T>(lhs),
169 ::testing::Pointwise(optional_matcher(::testing::Eq()), to_host<T>(rhs)));
178template <
typename Vector1,
typename Vector2,
typename U>
179inline void expect_vector_equivalent(Vector1
const& lhs, Vector2
const& rhs, U abs_error)
181 using T =
typename Vector1::value_type;
182 static_assert(std::is_same_v<T, typename Vector2::value_type>,
"Value type mismatch.");
183 static_assert(!std::is_integral_v<T>,
"Integral types cannot be compared with an error.");
185 if constexpr (cuspatial::is_vec_2d<T>) {
186 EXPECT_THAT(to_host<T>(lhs),
187 ::testing::Pointwise(vec_2d_near_matcher(abs_error), to_host<T>(rhs)));
188 }
else if constexpr (std::is_floating_point_v<T>) {
189 EXPECT_THAT(to_host<T>(lhs),
190 ::testing::Pointwise(float_near_matcher(abs_error), to_host<T>(rhs)));
191 }
else if constexpr (cuspatial::is_optional<T>) {
192 if constexpr (cuspatial::is_vec_2d<typename T::value_type>) {
193 EXPECT_THAT(to_host<T>(lhs),
194 ::testing::Pointwise(optional_matcher(vec_2d_matcher()), to_host<T>(rhs)));
195 }
else if constexpr (std::is_floating_point_v<typename T::value_type>) {
196 EXPECT_THAT(to_host<T>(lhs),
197 ::testing::Pointwise(optional_matcher(float_matcher()), to_host<T>(rhs)));
206#define CUSPATIAL_EXPECT_VECTORS_EQUIVALENT(lhs, rhs, ...) \
208 SCOPED_TRACE(" <-- line of failure\n"); \
209 cuspatial::test::expect_vector_equivalent(lhs, rhs, ##__VA_ARGS__); \
214template <
typename PairVector,
typename T =
typename PairVector::value_type::value_type>
215std::pair<rmm::device_vector<vec_2d<T>>, rmm::device_vector<vec_2d<T>>> unpack_vec2d_pair_vector(
216 PairVector
const& pairs)
218 using Pair =
typename PairVector::value_type;
220 auto first = rmm::device_vector<vec_2d<T>>(pairs.size());
221 auto second = rmm::device_vector<vec_2d<T>>(pairs.size());
223 auto zipped_output = thrust::make_zip_iterator(first.begin(), second.begin());
225 thrust::transform(pairs.begin(), pairs.end(), zipped_output, [] __device__(Pair
const& pair) {
227 return thrust::make_tuple(a, b);
229 return {std::move(first), std::move(second)};
232template <
typename PairVector1,
typename PairVector2>
233void expect_vec_2d_pair_equivalent(PairVector1
const& expected, PairVector2
const& got)
235 auto [expected_first, expected_second] = unpack_vec2d_pair_vector(expected);
236 auto [got_first, got_second] = unpack_vec2d_pair_vector(got);
237 CUSPATIAL_EXPECT_VECTORS_EQUIVALENT(expected_first, got_first);
238 CUSPATIAL_EXPECT_VECTORS_EQUIVALENT(expected_second, got_second);
241#define CUSPATIAL_EXPECT_VEC2D_PAIRS_EQUIVALENT(lhs, rhs) \
243 SCOPED_TRACE(" <-- line of failure\n"); \
244 cuspatial::test::expect_vec_2d_pair_equivalent(lhs, rhs); \
247template <
typename Array1,
typename Array2>
248void expect_multilinestring_array_equivalent(Array1& lhs, Array2& rhs)
250 auto [lhs_geometry_offset, lhs_part_offset, lhs_coordinates] = lhs.release();
251 auto [rhs_geometry_offset, rhs_part_offset, rhs_coordinates] = rhs.release();
253 CUSPATIAL_EXPECT_VECTORS_EQUIVALENT(lhs_geometry_offset, rhs_geometry_offset);
254 CUSPATIAL_EXPECT_VECTORS_EQUIVALENT(lhs_part_offset, rhs_part_offset);
255 CUSPATIAL_EXPECT_VECTORS_EQUIVALENT(lhs_coordinates, rhs_coordinates);
258#define CUSPATIAL_EXPECT_MULTILINESTRING_ARRAY_EQUIVALENT(lhs, rhs) \
260 SCOPED_TRACE(" <-- line of failure\n"); \
261 cuspatial::test::expect_multilinestring_array_equivalent(lhs, rhs); \
264template <
typename Array1,
typename Array2>
265void expect_multipoint_array_equivalent(Array1& lhs, Array2& rhs)
267 auto [lhs_geometry_offset, lhs_coordinates] = lhs.release();
268 auto [rhs_geometry_offset, rhs_coordinates] = rhs.release();
270 CUSPATIAL_EXPECT_VECTORS_EQUIVALENT(lhs_geometry_offset, rhs_geometry_offset);
271 CUSPATIAL_EXPECT_VECTORS_EQUIVALENT(lhs_coordinates, rhs_coordinates);
274#define CUSPATIAL_EXPECT_MULTIPOINT_ARRAY_EQUIVALENT(lhs, rhs) \
276 SCOPED_TRACE(" <-- line of failure\n"); \
277 cuspatial::test::expect_multipoint_array_equivalent(lhs, rhs); \
280#define CUSPATIAL_RUN_TEST(FUNC, ...) \
282 SCOPED_TRACE(" <-- line of failure\n"); \