From 75bc8ba59e2ae4d7837c56a8109faae24ae6d345 Mon Sep 17 00:00:00 2001 From: Dimitri Vlachos Date: Thu, 6 Feb 2025 18:39:51 +0000 Subject: [PATCH] WIP: Add unit tests for ReflectionTable class --- tests/CMakeLists.txt | 6 +- tests/test_reflection_table.cxx | 148 ++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 tests/test_reflection_table.cxx diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1503a19..8eccb62 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -11,9 +11,13 @@ target_link_libraries(test_write_h5_array GTest::gtest_main dx2 hdf5::hdf5) add_executable(test_tensor test_tensor.cxx) target_link_libraries(test_tensor GTest::gtest_main dx2) +add_executable(test_reflection_table test_reflection_table.cxx) +target_link_libraries(test_reflection_table GTest::gtest_main dx2) + include(GoogleTest) gtest_discover_tests(test_make_models PROPERTIES LABELS dx2tests) gtest_discover_tests(test_read_h5_array WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/tests" PROPERTIES LABELS dx2tests) gtest_discover_tests(test_write_h5_array WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/tests" PROPERTIES LABELS dx2tests) -gtest_discover_tests(test_tensor PROPERTIES LABELS dx2tests) \ No newline at end of file +gtest_discover_tests(test_tensor PROPERTIES LABELS dx2tests) +gtest_discover_tests(test_reflection_table WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/tests" PROPERTIES LABELS dx2tests) \ No newline at end of file diff --git a/tests/test_reflection_table.cxx b/tests/test_reflection_table.cxx new file mode 100644 index 0000000..3d6e7e9 --- /dev/null +++ b/tests/test_reflection_table.cxx @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include +#include + +// Test fixture for ReflectionTable tests +class ReflectionTableTest : public ::testing::Test { +protected: + std::filesystem::path test_file_path; + + void SetUp() override { + test_file_path = std::filesystem::current_path() / "data/cut_strong.refl"; + + // Create the test dataset if it does not exist + create_test_dataset(test_file_path, + "/dials/processing/group_0/xyzobs.px.value"); + } + + void create_test_dataset(const std::string &filename, + const std::string &dataset_path) { + hid_t file = H5Fopen(filename.c_str(), H5F_ACC_RDWR, H5P_DEFAULT); + if (file < 0) { + throw std::runtime_error("Error: Unable to open file: " + filename); + } + + hid_t dataset = H5Dopen(file, dataset_path.c_str(), H5P_DEFAULT); + if (dataset >= 0) { + H5Dclose(dataset); + H5Fclose(file); + return; // Dataset already exists + } + + // Create a simple 5x3 dataset for testing + hsize_t dims[2] = {5, 3}; // 5 rows, 3 columns (X, Y, Z) + hid_t dataspace = H5Screate_simple(2, dims, NULL); + dataset = H5Dcreate(file, dataset_path.c_str(), H5T_NATIVE_DOUBLE, + dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (dataset < 0) { + H5Sclose(dataspace); + H5Fclose(file); + throw std::runtime_error("Error: Unable to create test dataset: " + + dataset_path); + } + + // Example reflection table data (5 rows, 3 columns: X, Y, Z) + double test_data[5][3] = { + {1.1, 2.2, 3.3}, {4.4, 5.5, 6.6}, {7.7, 8.8, 9.9}, + {10.1, 11.2, 12.3}, {13.4, 14.5, 15.6}, + }; + + H5Dwrite(dataset, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, + test_data); + + // Close handles + H5Dclose(dataset); + H5Sclose(dataspace); + H5Fclose(file); + } +}; + +// --------------- ReflectionTable Tests --------------- +#pragma region ReflectionTable tests + +// Test loading data from an HDF5 file +TEST_F(ReflectionTableTest, LoadDataFromHDF5) { + ReflectionTable table(test_file_path.string()); + + EXPECT_NO_THROW( + table.select(ReflectionTable::Column::Z, [](double) { return true; })); +} + +// Test selecting reflections where Z > 10 +TEST_F(ReflectionTableTest, SelectReflectionsByZ) { + ReflectionTable table(test_file_path.string()); + + table.select(ReflectionTable::Column::Z, [](double z) { return z > 10.0; }); + + EXPECT_EQ(table.column(ReflectionTable::Column::Z).size(), 2); + EXPECT_EQ(table.column(ReflectionTable::Column::Z)[0], 12.3); + EXPECT_EQ(table.column(ReflectionTable::Column::Z)[1], 15.6); +} + +// Test selecting reflections where X < 5 +TEST_F(ReflectionTableTest, SelectReflectionsByX) { + ReflectionTable table(test_file_path.string()); + + table.select(ReflectionTable::Column::X, [](double x) { return x < 5.0; }); + + EXPECT_EQ(table.column(ReflectionTable::Column::X).size(), 2); + EXPECT_EQ(table.column(ReflectionTable::Column::X)[0], 1.1); + EXPECT_EQ(table.column(ReflectionTable::Column::X)[1], 4.4); +} + +// Test retrieving a single column +TEST_F(ReflectionTableTest, RetrieveColumnY) { + ReflectionTable table(test_file_path.string()); + + std::vector y_values = table.column(ReflectionTable::Column::Y); + + EXPECT_EQ(y_values.size(), 5); + EXPECT_EQ(y_values[0], 2.2); + EXPECT_EQ(y_values[1], 5.5); + EXPECT_EQ(y_values[2], 8.8); + EXPECT_EQ(y_values[3], 11.2); + EXPECT_EQ(y_values[4], 14.5); +} + +// Test selecting reflections on an empty dataset +TEST_F(ReflectionTableTest, SelectOnEmptyDataset) { + std::string empty_dataset = "/dials/processing/empty_dataset"; + create_test_dataset(test_file_path.string(), empty_dataset); + + ReflectionTable table(test_file_path.string()); + + EXPECT_NO_THROW( + table.select(ReflectionTable::Column::Z, [](double) { return true; })); + + EXPECT_EQ(table.column(ReflectionTable::Column::Z).size(), 0); +} + +// Test reading from a non-existent file +TEST_F(ReflectionTableTest, ReadFromNonExistentFile) { + std::string invalid_file = "invalid_file.h5"; + + EXPECT_THROW(ReflectionTable table(invalid_file), std::runtime_error); +} + +// Test reading a non-existent dataset +TEST_F(ReflectionTableTest, ReadNonExistentDataset) { + std::string invalid_dataset = "/this/does/not/exist"; + + EXPECT_THROW(ReflectionTable table(invalid_dataset), std::runtime_error); +} + +// Test if data selection keeps shape integrity +TEST_F(ReflectionTableTest, ShapeAfterSelect) { + ReflectionTable table(test_file_path.string()); + + table.select(ReflectionTable::Column::Z, [](double z) { return z > 5.0; }); + + EXPECT_EQ(table.column(ReflectionTable::Column::X).size(), 4); + EXPECT_EQ(table.column(ReflectionTable::Column::Y).size(), 4); + EXPECT_EQ(table.column(ReflectionTable::Column::Z).size(), 4); +} + +#pragma endregion ReflectionTable tests