1
+ #include < dx2/reflection.hpp>
2
+ #include < filesystem>
3
+ #include < gtest/gtest.h>
4
+ #include < iostream>
5
+ #include < optional>
6
+ #include < string>
7
+ #include < vector>
8
+
9
+ /*
10
+ * Test fixture for ReflectionTable tests. This fixture sets up the test
11
+ * environment for the ReflectionTable class and provides a common path
12
+ * to the test file.
13
+ */
14
+ class ReflectionTableTest : public ::testing::Test {
15
+ protected:
16
+ std::filesystem::path test_file_path;
17
+
18
+ void SetUp () override {
19
+ test_file_path = std::filesystem::current_path () / " data/cut_strong.refl" ;
20
+ }
21
+ };
22
+
23
+ TEST_F (ReflectionTableTest, LoadsAllColumns) {
24
+ ReflectionTable table (test_file_path.string ());
25
+
26
+ auto names = table.get_column_names ();
27
+ std::cout << " Loaded column names:\n " ;
28
+ for (const auto &name : names) {
29
+ std::cout << " - " << name << " \n " ;
30
+ }
31
+
32
+ EXPECT_FALSE (names.empty ());
33
+ EXPECT_NE (std::find (names.begin (), names.end (), " xyzobs.px.value" ),
34
+ names.end ());
35
+ }
36
+
37
+ TEST_F (ReflectionTableTest, TryGetColumnSucceedsOnCorrectType) {
38
+ ReflectionTable table (test_file_path.string ());
39
+
40
+ auto px = table.get_column <double >(" xyzobs.px.value" );
41
+ ASSERT_TRUE (px.has_value ());
42
+
43
+ const auto &span = px.value ();
44
+ std::cout << " xyzobs.px.value shape: " << span.extent (0 ) << " x"
45
+ << span.extent (1 ) << " \n " ;
46
+ EXPECT_EQ (span.extent (1 ), 3 );
47
+ EXPECT_GT (span.extent (0 ), 0 );
48
+ }
49
+
50
+ TEST_F (ReflectionTableTest, TryGetColumnFailsOnWrongType) {
51
+ ReflectionTable table (test_file_path.string ());
52
+
53
+ auto col = table.get_column <int >(" xyzobs.px.value" );
54
+ std::cout << " Column retrieval (int): "
55
+ << (col.has_value () ? " found" : " not found" ) << " \n " ;
56
+ EXPECT_FALSE (col.has_value ());
57
+ }
58
+
59
+ TEST_F (ReflectionTableTest, SelectSubsetUsingFindRows) {
60
+ ReflectionTable table (test_file_path.string ());
61
+
62
+ auto px = table.get_column <double >(" xyzobs.px.value" );
63
+ ASSERT_TRUE (px);
64
+
65
+ const auto &span = px.value ();
66
+
67
+ auto selected = table.find_rows ([&](size_t i) {
68
+ return span (i, 2 ) > 1.0 ; // z > 1.0
69
+ });
70
+
71
+ std::cout << " Selected " << selected.size () << " rows where z > 1.0\n " ;
72
+ EXPECT_FALSE (selected.empty ());
73
+
74
+ auto filtered = table.select (selected);
75
+ auto filtered_px = filtered.get_column <double >(" xyzobs.px.value" );
76
+ ASSERT_TRUE (filtered_px);
77
+ const auto &filtered_span = filtered_px.value ();
78
+
79
+ for (size_t i = 0 ; i < std::min<size_t >(filtered_span.extent (0 ), 5 ); ++i) {
80
+ std::cout << " z[" << i << " ] = " << filtered_span (i, 2 ) << " \n " ;
81
+ }
82
+
83
+ for (size_t i = 0 ; i < filtered_span.extent (0 ); ++i) {
84
+ EXPECT_GT (filtered_span (i, 2 ), 1.0 );
85
+ }
86
+ }
87
+
88
+ TEST_F (ReflectionTableTest, SelectWithMaskReturnsSameResultAsExplicitIndices) {
89
+ ReflectionTable table (test_file_path.string ());
90
+
91
+ auto px = table.get_column <double >(" xyzobs.px.value" );
92
+ ASSERT_TRUE (px);
93
+ const auto &span = px.value ();
94
+
95
+ std::vector<bool > mask (span.extent (0 ), false );
96
+ std::vector<size_t > indices;
97
+
98
+ for (size_t i = 0 ; i < span.extent (0 ); ++i) {
99
+ if (span (i, 2 ) > 1.0 ) {
100
+ mask[i] = true ;
101
+ indices.push_back (i);
102
+ }
103
+ }
104
+
105
+ std::cout << " Mask selected " << indices.size () << " rows\n " ;
106
+
107
+ auto table_from_mask = table.select (mask);
108
+ auto table_from_indices = table.select (indices);
109
+
110
+ auto mask_span =
111
+ table_from_mask.get_column <double >(" xyzobs.px.value" ).value ();
112
+ auto idx_span =
113
+ table_from_indices.get_column <double >(" xyzobs.px.value" ).value ();
114
+
115
+ ASSERT_EQ (mask_span.extent (0 ), idx_span.extent (0 ));
116
+ ASSERT_EQ (mask_span.extent (1 ), idx_span.extent (1 ));
117
+
118
+ for (size_t i = 0 ; i < std::min<size_t >(mask_span.extent (0 ), 3 ); ++i) {
119
+ std::cout << " Row " << i << " : "
120
+ << " mask_z = " << mask_span (i, 2 )
121
+ << " , idx_z = " << idx_span (i, 2 ) << " \n " ;
122
+ }
123
+
124
+ for (size_t i = 0 ; i < mask_span.extent (0 ); ++i) {
125
+ for (size_t j = 0 ; j < mask_span.extent (1 ); ++j) {
126
+ EXPECT_EQ (mask_span (i, j), idx_span (i, j));
127
+ }
128
+ }
129
+ }
130
+
131
+ TEST_F (ReflectionTableTest, SelectEmptyReturnsEmptyTable) {
132
+ ReflectionTable table (test_file_path.string ());
133
+ ReflectionTable empty = table.select (std::vector<size_t >{});
134
+
135
+ std::cout << " Selecting with empty row set...\n " ;
136
+ for (const auto &name : table.get_column_names ()) {
137
+ auto span = empty.get_column <double >(name);
138
+ if (span) {
139
+ std::cout << " " << name << " has " << span->extent (0 ) << " rows\n " ;
140
+ EXPECT_EQ (span.value ().extent (0 ), 0 );
141
+ }
142
+ }
143
+ }
144
+
145
+ TEST_F (ReflectionTableTest, AllDatasetsLoadSuccessfully) {
146
+ ReflectionTable table (test_file_path.string ());
147
+
148
+ std::vector<std::string> expected = get_datasets_in_group (
149
+ test_file_path.string (), " /dials/processing/group_0" );
150
+
151
+ std::vector<std::string> loaded = table.get_column_names ();
152
+
153
+ for (const std::string &full_dataset_path : expected) {
154
+ std::string name = get_dataset_name (full_dataset_path);
155
+
156
+ // Make sure it's present
157
+ auto it = std::find (loaded.begin (), loaded.end (), name);
158
+ EXPECT_NE (it, loaded.end ()) << " Dataset not loaded: " << name;
159
+
160
+ if (it != loaded.end ()) {
161
+ std::cout << " ✅ Dataset loaded: " << name << " \n " ;
162
+ } else {
163
+ std::cerr << " ❌ Dataset missing: " << name << " \n " ;
164
+ }
165
+ }
166
+ }
0 commit comments