Skip to content

Commit 36ba7f2

Browse files
Add tests for NexusClasses (#39305)
1 parent 53d99b6 commit 36ba7f2

File tree

8 files changed

+98
-19
lines changed

8 files changed

+98
-19
lines changed

Framework/Nexus/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ set(INC_FILES
2929
set(TEST_FILES
3030
H5UtilTest.h
3131
NexusIOHelperTest.h
32+
NexusClassesTest.h
3233
NexusDescriptorTest.h
3334
NeXusFileTest.h
3435
NeXusFileLeakTest.h

Framework/Nexus/inc/MantidNexus/NexusClasses.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,6 @@ class MANTID_NEXUS_DLL NXObject {
104104
std::string const &path() const { return m_path; }
105105
/// Returns the name of the object
106106
std::string name() const;
107-
/// Attributes
108-
NXAttributes attributes;
109107
/// Nexus file id
110108
std::shared_ptr<::NeXus::File> m_fileID;
111109

@@ -114,7 +112,6 @@ class MANTID_NEXUS_DLL NXObject {
114112
bool m_open; ///< Set to true if the object has been open
115113
private:
116114
NXObject(); ///< Private default constructor
117-
void getAttributes();
118115
};
119116

120117
/** Abstract base class for a Nexus data set. A typical use include:
@@ -155,6 +152,8 @@ class MANTID_NEXUS_DLL NXDataSet : public NXObject {
155152
std::string name() const { return m_info.nxname; } // cppcheck-suppress returnByReference
156153
/// Returns the Nexus type of the data. The types are defied in napi.h
157154
NXnumtype type() const { return m_info.type; }
155+
/// Attributes
156+
NXAttributes attributes;
158157

159158
protected:
160159
/**
@@ -188,6 +187,7 @@ class MANTID_NEXUS_DLL NXDataSet : public NXObject {
188187

189188
private:
190189
NXInfo m_info; ///< Holds the data info
190+
void getAttributes();
191191
};
192192

193193
template <typename T>

Framework/Nexus/src/NexusClasses.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ std::string NXObject::name() const {
113113

114114
/** Reads in attributes
115115
*/
116-
void NXObject::getAttributes() {
116+
void NXDataSet::getAttributes() {
117117
std::vector<char> buff(128);
118118
for (::NeXus::AttrInfo const &ainfo : m_fileID->getAttrInfos()) {
119119
if (ainfo.type != NXnumtype::CHAR && ainfo.length != 1) {

Framework/Nexus/test/CMakeLists.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ if(CXXTEST_FOUND)
55

66
cxxtest_add_test(NexusTest ${TEST_FILES})
77

8-
target_link_libraries(NexusTest PRIVATE Mantid::Nexus gmock)
9-
add_framework_test_helpers(NexusTest)
8+
target_link_libraries(NexusTest PRIVATE Mantid::Nexus gmock Mantid::Kernel)
109
add_dependencies(FrameworkTests NexusTest)
1110
add_dependencies(NexusTest UnitTestData)
1211
# Add to the 'FrameworkTests' group in VS
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Mantid Repository : https://github.com/mantidproject/mantid
2+
//
3+
// Copyright &copy; 2025 ISIS Rutherford Appleton Laboratory UKRI,
4+
// NScD Oak Ridge National Laboratory, European Spallation Source,
5+
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6+
// SPDX - License - Identifier: GPL - 3.0 +
7+
#pragma once
8+
9+
#include "MantidNexus/NexusClasses.h"
10+
#include "test_helper.h"
11+
#include <cxxtest/TestSuite.h>
12+
#include <filesystem>
13+
14+
class NexusClassesTest : public CxxTest::TestSuite {
15+
public:
16+
// This pair of boilerplate methods prevent the suite being created statically
17+
// This means the constructor isn't called when running other tests
18+
static NexusClassesTest *createSuite() { return new NexusClassesTest(); }
19+
static void destroySuite(NexusClassesTest *suite) { delete suite; }
20+
21+
void test_EQSANS_89157() {
22+
const std::string filename = NexusTest::getFullPath("EQSANS_89157.nxs.h5");
23+
Mantid::NeXus::NXRoot root(filename);
24+
25+
// groups don't load their attributes
26+
27+
auto entry = root.openFirstEntry();
28+
TS_ASSERT_EQUALS(entry.name(), "entry");
29+
// entry.NX_class() returns the type in "NexusClasses" (i.e. NXentry) rather than what is in the file
30+
31+
// check NXChar
32+
auto definition = root.openNXChar("entry/definition"); // relative path
33+
definition.load();
34+
TS_ASSERT_EQUALS(std::string(definition(), definition.dim0()), "NXsnsevent");
35+
// and from getString
36+
TS_ASSERT_EQUALS(root.getString("entry/definition"), "NXsnsevent");
37+
38+
TS_ASSERT(!entry.containsGroup("bank91_events")); // there aren't that many groups
39+
TS_ASSERT(entry.containsGroup("bank19_events"));
40+
41+
auto bank19 = entry.openNXGroup("bank19_events");
42+
TS_ASSERT_EQUALS(bank19.name(), "bank19_events");
43+
// bank19.NX_class() returns the type in "NexusClasses" (i.e. NXClass) rather than what is in the file
44+
45+
// load time-of-flight as a float because NexusClasses doesn't autoconvert types
46+
auto time_of_flight = bank19.openNXFloat("event_time_offset");
47+
TS_ASSERT_EQUALS(time_of_flight.dim0(), 256); // from looking in the file
48+
TS_ASSERT_EQUALS(time_of_flight.attributes.n(), 2);
49+
TS_ASSERT_EQUALS(time_of_flight.attributes("units"), "microsecond");
50+
TS_ASSERT_EQUALS(time_of_flight.attributes("target"), "/entry/instrument/bank19/event_time_offset");
51+
time_of_flight.load();
52+
TS_ASSERT_DELTA(time_of_flight[0], 16681.5, .01);
53+
TS_ASSERT_DELTA(time_of_flight[255], 958.1, .01);
54+
TS_ASSERT_THROWS_ANYTHING(time_of_flight[256]); // out of bounds
55+
56+
auto duration = root.openNXFloat("/entry/duration"); // absolute path
57+
TS_ASSERT_EQUALS(duration.attributes.n(), 1);
58+
TS_ASSERT_EQUALS(duration.attributes("units"), "second");
59+
duration.load();
60+
TS_ASSERT_DELTA(duration[0], 7200., .1);
61+
}
62+
};

Framework/Nexus/test/NexusIOHelperTest.h

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
// SPDX - License - Identifier: GPL - 3.0 +
77
#pragma once
88

9-
#include "MantidAPI/FileFinder.h"
109
#include "MantidNexus/NeXusFile.hpp"
1110
#include "MantidNexus/NexusIOHelper.h"
11+
#include "test_helper.h"
1212

1313
#include <cxxtest/TestSuite.h>
1414

@@ -18,7 +18,7 @@ class NexusIOHelperTest : public CxxTest::TestSuite {
1818

1919
public:
2020
void test_nexus_io_helper_readNexusVector() {
21-
const std::string filename = Mantid::API::FileFinder::Instance().getFullPath("V20_ESS_example.nxs");
21+
const std::string filename = NexusTest::getFullPath("V20_ESS_example.nxs");
2222
::NeXus::File file(filename);
2323
file.openGroup("entry", "NXentry");
2424
file.openGroup("raw_event_data", "NXevent_data");
@@ -39,7 +39,7 @@ class NexusIOHelperTest : public CxxTest::TestSuite {
3939
}
4040

4141
void test_nexus_io_helper_readNexusVector_out_buffer() {
42-
const std::string filename = Mantid::API::FileFinder::Instance().getFullPath("V20_ESS_example.nxs");
42+
const std::string filename = NexusTest::getFullPath("V20_ESS_example.nxs");
4343
::NeXus::File file(filename);
4444
file.openGroup("entry", "NXentry");
4545
file.openGroup("raw_event_data", "NXevent_data");
@@ -68,7 +68,7 @@ class NexusIOHelperTest : public CxxTest::TestSuite {
6868
}
6969

7070
void test_nexus_io_helper_readNexusVector_throws_when_narrowing() {
71-
const std::string filename = Mantid::API::FileFinder::Instance().getFullPath("V20_ESS_example.nxs");
71+
const std::string filename = NexusTest::getFullPath("V20_ESS_example.nxs");
7272
::NeXus::File file(filename);
7373
file.openGroup("entry", "NXentry");
7474
file.openGroup("raw_event_data", "NXevent_data");
@@ -87,7 +87,7 @@ class NexusIOHelperTest : public CxxTest::TestSuite {
8787
}
8888

8989
void test_nexus_io_helper_readNexusVector_allow_narrowing() {
90-
const std::string filename = Mantid::API::FileFinder::Instance().getFullPath("V20_ESS_example.nxs");
90+
const std::string filename = NexusTest::getFullPath("V20_ESS_example.nxs");
9191
::NeXus::File file(filename);
9292
file.openGroup("entry", "NXentry");
9393
file.openGroup("raw_event_data", "NXevent_data");
@@ -108,8 +108,7 @@ class NexusIOHelperTest : public CxxTest::TestSuite {
108108
}
109109

110110
void test_nexus_io_helper_readNexusVector_v20_ess_integration_2018() {
111-
const std::string filename =
112-
Mantid::API::FileFinder::Instance().getFullPath("V20_ESSIntegration_2018-12-13_0942.nxs");
111+
const std::string filename = NexusTest::getFullPath("V20_ESSIntegration_2018-12-13_0942.nxs");
113112
::NeXus::File file(filename);
114113
file.openGroup("entry", "NXentry");
115114
file.openGroup("event_data", "NXevent_data");
@@ -126,7 +125,7 @@ class NexusIOHelperTest : public CxxTest::TestSuite {
126125
}
127126

128127
void test_nexus_io_helper_readNexusSlab() {
129-
const std::string filename = Mantid::API::FileFinder::Instance().getFullPath("V20_ESS_example.nxs");
128+
const std::string filename = NexusTest::getFullPath("V20_ESS_example.nxs");
130129
::NeXus::File file(filename);
131130
file.openGroup("entry", "NXentry");
132131
file.openGroup("raw_event_data", "NXevent_data");
@@ -143,7 +142,7 @@ class NexusIOHelperTest : public CxxTest::TestSuite {
143142
}
144143

145144
void test_nexus_io_helper_readNexusSlab_out_buffer() {
146-
const std::string filename = Mantid::API::FileFinder::Instance().getFullPath("V20_ESS_example.nxs");
145+
const std::string filename = NexusTest::getFullPath("V20_ESS_example.nxs");
147146
::NeXus::File file(filename);
148147
file.openGroup("entry", "NXentry");
149148
file.openGroup("raw_event_data", "NXevent_data");
@@ -164,7 +163,7 @@ class NexusIOHelperTest : public CxxTest::TestSuite {
164163
}
165164

166165
void test_nexus_io_helper_readNexusSlab_throws_when_Narrowing() {
167-
const std::string filename = Mantid::API::FileFinder::Instance().getFullPath("V20_ESS_example.nxs");
166+
const std::string filename = NexusTest::getFullPath("V20_ESS_example.nxs");
168167
::NeXus::File file(filename);
169168
file.openGroup("entry", "NXentry");
170169
file.openGroup("raw_event_data", "NXevent_data");
@@ -184,8 +183,7 @@ class NexusIOHelperTest : public CxxTest::TestSuite {
184183
}
185184

186185
void test_nexus_io_helper_readNexusSlab_v20_ess_integration_2018() {
187-
const std::string filename =
188-
Mantid::API::FileFinder::Instance().getFullPath("V20_ESSIntegration_2018-12-13_0942.nxs");
186+
const std::string filename = NexusTest::getFullPath("V20_ESSIntegration_2018-12-13_0942.nxs");
189187
::NeXus::File file(filename);
190188
file.openGroup("entry", "NXentry");
191189
file.openGroup("event_data", "NXevent_data");
@@ -202,7 +200,7 @@ class NexusIOHelperTest : public CxxTest::TestSuite {
202200
}
203201

204202
void test_nexus_io_helper_readNexusValue() {
205-
const std::string filename = Mantid::API::FileFinder::Instance().getFullPath("LARMOR00003368.nxs");
203+
const std::string filename = NexusTest::getFullPath("LARMOR00003368.nxs");
206204
::NeXus::File file(filename);
207205
file.openGroup("raw_data_1", "NXentry");
208206
file.openGroup("monitor_1", "NXmonitor");

Framework/Nexus/test/test_helper.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,18 @@ void NexusTest::removeFile(const std::string &filename) {
88
}
99
}
1010

11+
std::string NexusTest::getFullPath(const std::string &filename) {
12+
using Mantid::Kernel::ConfigService;
13+
auto dataPaths = ConfigService::Instance().getDataSearchDirs();
14+
for (auto &dataPath : dataPaths) {
15+
const auto hdf5Path = std::filesystem::path(dataPath) / filename;
16+
if (std::filesystem::exists(hdf5Path)) {
17+
return hdf5Path.string();
18+
}
19+
}
20+
return std::string();
21+
}
22+
1123
/**
1224
* Let's face it, std::string is poorly designed,
1325
* and this is the constructor that it needed to have.

Framework/Nexus/test/test_helper.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "MantidKernel/ConfigService.h"
12
#include <filesystem>
23
#include <string>
34

@@ -8,6 +9,12 @@ namespace NexusTest {
89
*/
910
void removeFile(std::string const &filename);
1011

12+
/**
13+
* @param filename filename without path
14+
* @return full path to file. This returns empty string if it doesn't exist.
15+
*/
16+
std::string getFullPath(const std::string &filename);
17+
1118
/**
1219
* Let's face it, std::string is poorly designed,
1320
* and this is the constructor that it needed to have.

0 commit comments

Comments
 (0)