-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Skeleton HDF5 wrapper class and failing tests.
Basic class structure and some failing tests for TDD.
- Loading branch information
1 parent
bc9c4fe
commit 3e8d84b
Showing
3 changed files
with
235 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,65 @@ | ||
/** | ||
* @file hdf5_io.h | ||
* @brief File I/O using HDF5 | ||
* @brief File I/O using HDF5. | ||
*/ | ||
#pragma once | ||
#include <string> | ||
#include <vector> | ||
|
||
#include <H5Cpp.h> | ||
|
||
/** | ||
* @brief Mode to write the file: R, RW, O. | ||
*/ | ||
enum HDF5FileMode { | ||
READONLY = 0, | ||
READWRITE, | ||
OVERWRITE | ||
}; | ||
|
||
/** | ||
* @brief A simple class to wrap the HDF5 I/O. | ||
*/ | ||
class HDF5File { | ||
|
||
public: | ||
/** Default constructor: default filename and mode. */ | ||
HDF5File() : filename_("tdms.hdf5"), mode_(READONLY) { _open(); } | ||
|
||
/** Normal constructor. */ | ||
HDF5File(const std::string &filename, HDF5FileMode mode) : filename_(filename), mode_(mode) { | ||
_open(); | ||
} | ||
|
||
/** Destructor, deletes pointers. */ | ||
~HDF5File(); | ||
|
||
/** Writes array to the file. */ | ||
void write(); | ||
|
||
/** reads data from the file. */ | ||
void read(); | ||
|
||
/** | ||
* @brief Check file health. | ||
* | ||
* @param print_debug Optionally this function can print to the debug log. | ||
* @return true If the file is OK. | ||
* @return false If the file is not OK. | ||
*/ | ||
bool isOK(bool print_debug=false); | ||
|
||
private: | ||
/** Common to both constructors: open/create the file and set file_ to point to it. */ | ||
void _open(); | ||
std::string filename_; /**< The file name. */ | ||
HDF5FileMode mode_; /**< The I/O mode: default is to create non-existing. */ | ||
H5::H5File *file_ = nullptr; /**< The H5 file itself. */ | ||
std::vector<H5::DataSet *> datasets_; /**< All datasets to be written to the file. */ | ||
}; | ||
|
||
/** | ||
* @brief Test of HDF5 I/O | ||
* @brief Example of HDF5 I/O... to be deleted. | ||
* This function should not make it to a PR. | ||
*/ | ||
void test_hdf5(); | ||
void example_hdf5(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/** | ||
* @file test_hdf5_io.cpp | ||
* @brief Tests of the HDF5 file I/O functionality. | ||
*/ | ||
#include "hdf5_io.h" | ||
|
||
// std | ||
#include <ctime> | ||
#include <filesystem> | ||
#include <random> | ||
|
||
// external | ||
#include <catch2/catch_approx.hpp> | ||
#include <catch2/catch_test_macros.hpp> | ||
#include <spdlog/spdlog.h> | ||
|
||
// tdms | ||
#include "unit_test_utils.h" | ||
|
||
using tdms_tests::create_tmp_dir; // unit_test_utils.h | ||
|
||
TEST_CASE("Test file I/O construction/destruction.") { | ||
// setup - temporary directory | ||
auto tmp = create_tmp_dir(); | ||
|
||
SECTION("Check file I/O modes") { | ||
// check possible file i/o modes: create file, then open same file readonly, then open | ||
// rw, then create it again (even though it already exists) | ||
for (auto i : {HDF5FileMode::OVERWRITE, HDF5FileMode::READONLY, HDF5FileMode::READWRITE, | ||
HDF5FileMode::OVERWRITE}) { | ||
SPDLOG_DEBUG("Constructing in mode {}", i); | ||
HDF5File fi(tmp.string() + "/test_file_constructor.h5", static_cast<HDF5FileMode>(i)); | ||
CHECK(fi.isOK()); | ||
}// destructor called as we leave scope | ||
} | ||
|
||
SECTION("Check all reasonable file extensions are OK") { | ||
for (auto extension : {".hdf5", ".h5", ".mat"}) { | ||
HDF5File fi(tmp.string() + "/test_file" + extension, OVERWRITE); | ||
CHECK(fi.isOK()); | ||
} | ||
} | ||
|
||
SECTION("Check can't open nonexistent file") { | ||
CHECK_THROWS(HDF5File(tmp.string() + "/this_file_doesnt_exist.h5", HDF5FileMode::READONLY)); | ||
} | ||
|
||
// We should get an exception if we try to write to a readonly file. | ||
SECTION("Check can't open file readonly and write to it") { | ||
// create a file | ||
{ | ||
HDF5File f1(tmp.string() + "/test_file_read_only.h5", HDF5FileMode::OVERWRITE); | ||
}// destructor called as we leave scope | ||
|
||
HDF5File f2(tmp.string() + "/test_file_read_only.h5", HDF5FileMode::READONLY); | ||
CHECK_THROWS(f2.write()); | ||
} | ||
|
||
// Normal operation: we should be able to create a file and write to it, then read from it. | ||
SECTION("Check write then read.") { | ||
// create a file | ||
{ | ||
HDF5File f1(tmp.string() + "/test_file_wr.h5", HDF5FileMode::OVERWRITE); | ||
f1.write(); | ||
CHECK(f1.isOK()); | ||
|
||
}// destructor called as we leave scope | ||
|
||
HDF5File f2(tmp.string() + "/test_file_wr.h5", HDF5FileMode::READONLY); | ||
f2.read(); | ||
} | ||
|
||
SECTION("Check write then (overwrite) then read.") { | ||
|
||
// Create the file and write some data. | ||
{ | ||
HDF5File f1(tmp.string() + "/test_file_wwr.h5", HDF5FileMode::OVERWRITE); | ||
f1.write(); | ||
CHECK(f1.isOK()); | ||
|
||
}// destructor called as we leave scope | ||
|
||
// Overwrite the file and add some different data. | ||
{ | ||
HDF5File f2(tmp.string() + "/test_file_wwr.h5", HDF5FileMode::OVERWRITE); | ||
f2.write(); | ||
CHECK(f2.isOK()); | ||
|
||
}// destructor called as we leave scope | ||
|
||
// Now open the file in readonly. The first data should not be there (and | ||
// should throw an exception). The second data should be there. | ||
HDF5File f3(tmp.string() + "/test_file_wwr.h5", HDF5FileMode::READONLY); | ||
f3.read(); | ||
|
||
CHECK_NOTHROW(f3.read()); | ||
CHECK_THROWS(f3.read()); | ||
} | ||
|
||
// teardown - remove temporary directory and all files | ||
SPDLOG_DEBUG("Removing temporary directory."); | ||
std::filesystem::remove_all(tmp); | ||
} | ||
|
||
TEST_CASE("Test call example sandbox function") { | ||
// setup - temporary directory | ||
auto tmp = create_tmp_dir(); | ||
|
||
SPDLOG_INFO("Calling the example"); | ||
example_hdf5(); | ||
SPDLOG_INFO("Example has run"); | ||
|
||
// teardown - remove temporary directory and all files | ||
SPDLOG_DEBUG("Removing temporary directory."); | ||
std::filesystem::remove_all(tmp); | ||
} |