Skip to content

Commit

Permalink
Remove duplicated tests. (#1011)
Browse files Browse the repository at this point in the history
There's (at least) three attempts at testing read/write cycles for multi-dimensional arrays. The first is whatever is in tests_*multi_dims.cpp. Since it's partial, a second attempt was made: the first half of test_all_types.cpp. Since this was still partial and not quite DRY enough, a third attempt was made.

This PR removes the duplicated tests from the first and second attempt, one-by-one. Each commit removes one test. Or moves/reimplements a test if it's not yet covered by the third attempt.

There's a fourth attempt in test_high_five_base.cpp; but that's left for another PR.
  • Loading branch information
1uc authored Jun 19, 2024
1 parent af4a914 commit bc1f1ef
Show file tree
Hide file tree
Showing 8 changed files with 234 additions and 474 deletions.
2 changes: 1 addition & 1 deletion doc/developer_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ void check_write(...) {
### Test Organization
#### Multi-Dimensional Arrays
All tests for reading/writing whole multi-dimensional arrays to datasets or
attributes belong in `tests/unit/tests_high_five_multi_dimensional.cpp`. This
attributes belong in `tests/unit/test_all_types.cpp`. This
includes write/read cycles; checking all the generic edges cases, e.g. empty
arrays and mismatching sizes; and checking non-reallocation.

Expand Down
2 changes: 1 addition & 1 deletion tests/unit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ if(MSVC)
endif()

## Base tests
foreach(test_name tests_high_five_base tests_high_five_multi_dims tests_high_five_easy test_all_types test_high_five_selection tests_high_five_data_type test_empty_arrays test_legacy test_opencv test_string test_xtensor)
foreach(test_name tests_high_five_base tests_high_five_easy test_all_types test_high_five_selection tests_high_five_data_type test_boost test_empty_arrays test_legacy test_opencv test_string test_stl test_xtensor)
add_executable(${test_name} "${test_name}.cpp")
target_link_libraries(${test_name} HighFive HighFiveWarnings HighFiveFlags Catch2::Catch2WithMain)
target_link_libraries(${test_name} HighFiveOptionalDependencies)
Expand Down
80 changes: 80 additions & 0 deletions tests/unit/compary_arrays.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (c), 2023, 2024 Blue Brain Project - EPFL
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
*/

#include <string>
#include <sstream>
#include <type_traits>

#include <catch2/catch_template_test_macros.hpp>

#include "data_generator.hpp"

namespace HighFive {
namespace testing {

template <class T, class = void>
struct DiffMessageTrait;

template <class T>
struct DiffMessageTrait<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
static std::string diff(T a, T b) {
std::stringstream sstream;
sstream << std::scientific << " delta: " << a - b;
return sstream.str();
}
};

template <class T>
struct DiffMessageTrait<T, typename std::enable_if<!std::is_floating_point<T>::value>::type> {
static std::string diff(T /* a */, T /* b */) {
return "";
}
};

template <class T>
std::string diff_message(T a, T b) {
return DiffMessageTrait<T>::diff(a, b);
}

template <class Actual, class Expected, class Comp>
void compare_arrays(const Actual& actual,
const Expected& expected,
const std::vector<size_t>& dims,
Comp comp) {
using actual_trait = testing::ContainerTraits<Actual>;
using expected_trait = testing::ContainerTraits<Expected>;
using base_type = typename actual_trait::base_type;

auto n = testing::flat_size(dims);

for (size_t i = 0; i < n; ++i) {
auto indices = testing::unravel(i, dims);
base_type actual_value = actual_trait::get(actual, indices);
base_type expected_value = expected_trait::get(expected, indices);
auto c = comp(actual_value, expected_value);
if (!c) {
std::stringstream sstream;
sstream << std::scientific << "i = " << i << ": " << actual_value
<< " != " << expected_value << diff_message(actual_value, expected_value);
INFO(sstream.str());
}
REQUIRE(c);
}
}

template <class Actual, class Expected>
void compare_arrays(const Actual& actual,
const Expected& expected,
const std::vector<size_t>& dims) {
using base_type = typename testing::ContainerTraits<Actual>::base_type;
compare_arrays(expected, actual, dims, [](base_type a, base_type b) { return a == b; });
}

} // namespace testing
} // namespace HighFive
87 changes: 63 additions & 24 deletions tests/unit/data_generator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,38 @@ struct ContainerTraits<std::span<T, Extent>>: public STLLikeContainerTraits<std:
#endif


template <class T, size_t n>
struct ContainerTraits<T[n]> {
using container_type = T[n];
using value_type = T;
using base_type = typename ContainerTraits<value_type>::base_type;

static constexpr bool is_view = ContainerTraits<value_type>::is_view;
static constexpr size_t rank = 1 + ContainerTraits<value_type>::rank;

static void set(container_type& array,
const std::vector<size_t>& indices,
const base_type& value) {
return ContainerTraits<value_type>::set(array[indices[0]], lstrip(indices, 1), value);
}

static base_type get(const container_type& array, const std::vector<size_t>& indices) {
return ContainerTraits<value_type>::get(array[indices[0]], lstrip(indices, 1));
}

static void assign(container_type& dst, const container_type& src) {
for (size_t i = 0; i < n; ++i) {
dst[i] = src[i];
}
}

static void sanitize_dims(std::vector<size_t>& dims, size_t axis) {
dims[axis] = n;
ContainerTraits<value_type>::sanitize_dims(dims, axis + 1);
}
};


// -- Boost -------------------------------------------------------------------
#ifdef HIGHFIVE_TEST_BOOST
template <class T, size_t n>
Expand Down Expand Up @@ -723,6 +755,37 @@ struct MultiDimVector<T, 0> {
using type = T;
};

template <class C, class F>
void initialize_impl(C& array,
const std::vector<size_t>& dims,
std::vector<size_t>& indices,
size_t axis,
F f) {
using traits = ContainerTraits<C>;
if (axis == indices.size()) {
auto value = f(indices);
traits::set(array, indices, value);
} else {
for (size_t i = 0; i < dims[axis]; ++i) {
indices[axis] = i;
initialize_impl(array, dims, indices, axis + 1, f);
}
}
}

template <class C, class F>
void initialize(C& array, const std::vector<size_t>& dims, F f) {
std::vector<size_t> indices(dims.size());
initialize_impl(array, dims, indices, 0, f);
}

template <class C>
void initialize(C& array, const std::vector<size_t>& dims) {
using traits = ContainerTraits<C>;
initialize(array, dims, DefaultValues<typename traits::base_type>());
}


template <class Container>
class DataGenerator {
public:
Expand Down Expand Up @@ -761,30 +824,6 @@ class DataGenerator {
static void sanitize_dims(std::vector<size_t>& dims) {
ContainerTraits<Container>::sanitize_dims(dims, /* axis = */ 0);
}

private:
template <class C, class F>
static void initialize(C& array, const std::vector<size_t>& dims, F f) {
std::vector<size_t> indices(dims.size());
initialize(array, dims, indices, 0, f);
}

template <class C, class F>
static void initialize(C& array,
const std::vector<size_t>& dims,
std::vector<size_t>& indices,
size_t axis,
F f) {
if (axis == indices.size()) {
auto value = f(indices);
traits::set(array, indices, value);
} else {
for (size_t i = 0; i < dims[axis]; ++i) {
indices[axis] = i;
initialize(array, dims, indices, axis + 1, f);
}
}
}
};

} // namespace testing
Expand Down
Loading

0 comments on commit bc1f1ef

Please sign in to comment.