-
Notifications
You must be signed in to change notification settings - Fork 14
FORM Storage Tests #354
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
FORM Storage Tests #354
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
e5dc226
Add a unit test requiring that FORM throws an exception when trying to
aolivier23 10cd360
Added test that two FORM AssociativeContainers can share the same
aolivier23 8a83a00
Added FORM test that three Associative_Containers can share the same
aolivier23 4d27dc1
Apply clang-format fixes
github-actions[bot] ff47309
Added FORM tests for error handling when setting up Containers.
aolivier23 0388f10
Apply clang-format fixes
github-actions[bot] 747a803
Made form::test::read<>() return std::unique_ptr<> instead of copies of
aolivier23 e241cd2
Merge branch 'feature/aolivier-form-storage-tests' of https://github.…
aolivier23 822feff
Apply clang-format fixes
github-actions[bot] a616793
Updated (so-far-unused) form::test::getTechnology() to use
aolivier23 a6b2239
Merge branch 'feature/aolivier-form-storage-tests' of https://github.…
aolivier23 f816ae8
Made all of test_utils.hpp inline in case someone writes a test
aolivier23 5ea6eda
Merge branch 'main' into feature/aolivier-form-storage-tests
aolivier23 163399e
Moved FORM's USE_ROOT_STORAGE compile definition to somewhere where it
aolivier23 4352b16
Merge branch 'main' into feature/aolivier-form-storage-tests
aolivier23 a586242
Updated include guards in test_utils.hpp to match new convention on
aolivier23 6ca3fee
Removed unneeded assert()s from FORM Storage test.
aolivier23 09ea1af
Merge branch 'main' into feature/aolivier-form-storage-tests
aolivier23 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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,109 @@ | ||
| //Tests for FORM's storage layer's design requirements | ||
|
|
||
| #include "test/form/test_utils.hpp" | ||
|
|
||
| #include <catch2/catch_test_macros.hpp> | ||
|
|
||
| #include <cmath> | ||
| #include <numeric> | ||
| #include <vector> | ||
|
|
||
| using namespace form::detail::experimental; | ||
|
|
||
| TEST_CASE("Storage_Container read wrong type", "[form]") | ||
| { | ||
| int const technology = form::technology::ROOT_TTREE; | ||
| std::vector<int> primes = {2, 3, 5, 7, 11, 13, 17, 19}; | ||
| form::test::write(technology, primes); | ||
|
|
||
| auto file = createFile(technology, form::test::testFileName, 'i'); | ||
| auto container = createContainer(technology, form::test::makeTestBranchName<std::vector<int>>()); | ||
| container->setFile(file); | ||
| void const* dataPtr; | ||
| CHECK_THROWS_AS(container->read(0, &dataPtr, typeid(double)), std::runtime_error); | ||
| } | ||
|
|
||
| TEST_CASE("Storage_Container sharing an Association", "[form]") | ||
| { | ||
| int const technology = form::technology::ROOT_TTREE; | ||
| std::vector<float> piData(10, 3.1415927); | ||
| std::string indexData = "[EVENT=00000001;SEG=00000001]"; | ||
|
|
||
| form::test::write(technology, piData, indexData); | ||
|
|
||
| auto [piResult, indexResult] = form::test::read<std::vector<float>, std::string>(technology); | ||
|
|
||
| float const originalSum = std::accumulate(piData.begin(), piData.end(), 0.f); | ||
| float const readSum = std::accumulate(piResult->begin(), piResult->end(), 0.f); | ||
| float const floatDiff = readSum - originalSum; | ||
|
|
||
| SECTION("float container sum") { CHECK(fabs(floatDiff) < std::numeric_limits<float>::epsilon()); } | ||
|
|
||
| SECTION("index") { CHECK(*indexResult == indexData); } | ||
| } | ||
|
|
||
| TEST_CASE("Storage_Container multiple containers in Association", "[form]") | ||
| { | ||
| int const technology = form::technology::ROOT_TTREE; | ||
| std::vector<float> piData(10, 3.1415927); | ||
| std::vector<int> magicData(17); | ||
| std::iota(magicData.begin(), magicData.end(), 42); | ||
| std::string indexData = "[EVENT=00000001;SEG=00000001]"; | ||
|
|
||
| form::test::write(technology, piData, magicData, indexData); | ||
|
|
||
| auto [piResult, magicResult, indexResult] = | ||
| form::test::read<std::vector<float>, std::vector<int>, std::string>(technology); | ||
|
|
||
| SECTION("float container") | ||
| { | ||
| float const originalSum = std::accumulate(piData.begin(), piData.end(), 0.f); | ||
| float const readSum = std::accumulate(piResult->begin(), piResult->end(), 0.f); | ||
| float const floatDiff = readSum - originalSum; | ||
| CHECK(fabs(floatDiff) < std::numeric_limits<float>::epsilon()); | ||
| } | ||
|
|
||
| SECTION("int container") | ||
| { | ||
| int const originalMagic = std::accumulate(magicData.begin(), magicData.end(), 0); | ||
| int const readMagic = std::accumulate(magicResult->begin(), magicResult->end(), 0); | ||
| int const magicDiff = readMagic - originalMagic; | ||
| CHECK(magicDiff == 0); | ||
| } | ||
|
|
||
| SECTION("index data") { CHECK(*indexResult == indexData); } | ||
| } | ||
|
|
||
| TEST_CASE("FORM Container setup error handling") | ||
| { | ||
| int const technology = form::technology::ROOT_TTREE; | ||
| auto file = createFile(technology, "testContainerErrorHandling.root", 'o'); | ||
| auto container = createContainer(technology, "test/testData"); | ||
|
|
||
| std::vector<float> testData; | ||
| void const* ptrTestData = &testData; | ||
| auto const& typeInfo = typeid(testData); | ||
|
|
||
| SECTION("fill() before setParent()") | ||
| { | ||
| CHECK_THROWS_AS(container->setupWrite(typeInfo), std::runtime_error); | ||
| CHECK_THROWS_AS(container->fill(ptrTestData), std::runtime_error); | ||
| } | ||
|
|
||
| SECTION("commit() before setParent()") | ||
| { | ||
| CHECK_THROWS_AS(container->commit(), std::runtime_error); | ||
| } | ||
|
|
||
| SECTION("read() before setParent()") | ||
| { | ||
| CHECK_THROWS_AS(container->read(0, &ptrTestData, typeInfo), std::runtime_error); | ||
| } | ||
|
|
||
| SECTION("mismatched file type") | ||
| { | ||
| std::shared_ptr<IStorage_File> wrongFile( | ||
| new Storage_File("testContainerErrorHandling.root", 'o')); | ||
| CHECK_THROWS_AS(container->setFile(wrongFile), std::runtime_error); | ||
| } | ||
| } |
This file contains hidden or 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,127 @@ | ||
| //Utilities to make FORM unit tests easier to write and maintain | ||
|
|
||
| #ifndef FORM_TEST_UTILS_HPP | ||
| #define FORM_TEST_UTILS_HPP | ||
|
|
||
| #include "storage/istorage.hpp" | ||
| #include "storage/storage_associative_container.hpp" | ||
| #include "util/factories.hpp" | ||
|
|
||
| #include "TClass.h" | ||
|
|
||
| #include <iostream> | ||
| #include <memory> | ||
|
|
||
| using namespace form::detail::experimental; | ||
|
|
||
| namespace form::test { | ||
|
|
||
| inline std::string const testTreeName = "FORMTestTree"; | ||
| inline std::string const testFileName = "FORMTestFile.root"; | ||
|
|
||
| template <class PROD> | ||
| inline std::string getTypeName() | ||
| { | ||
| return TClass::GetClass<PROD>()->GetName(); | ||
| } | ||
|
|
||
| template <class PROD> | ||
| inline std::string makeTestBranchName() | ||
| { | ||
| return testTreeName + "/" + getTypeName<PROD>(); | ||
| } | ||
|
|
||
| inline std::vector<std::shared_ptr<IStorage_Container>> doWrite( | ||
| std::shared_ptr<IStorage_File>& /*file*/, | ||
| int const /*technology*/, | ||
| std::shared_ptr<IStorage_Container>& /*parent*/) | ||
| { | ||
| return std::vector<std::shared_ptr<IStorage_Container>>(); | ||
| } | ||
|
|
||
| template <class PROD, class... PRODS> | ||
| inline std::vector<std::shared_ptr<IStorage_Container>> doWrite( | ||
| std::shared_ptr<IStorage_File>& file, | ||
| int const technology, | ||
| std::shared_ptr<IStorage_Container>& parent, | ||
| PROD& prod, | ||
| PRODS&... prods) | ||
| { | ||
| auto const branchName = makeTestBranchName<PROD>(); | ||
| auto container = createContainer(technology, branchName); | ||
| auto assoc = dynamic_pointer_cast<Storage_Associative_Container>(container); | ||
| if (assoc) { | ||
| assoc->setParent(parent); | ||
| } | ||
| container->setFile(file); | ||
| container->setupWrite(typeid(PROD)); | ||
|
|
||
| auto result = doWrite(file, technology, parent, prods...); | ||
| container->fill(&prod); //This must happen after setupWrite() | ||
| result.push_back(container); | ||
| return result; | ||
| } | ||
|
|
||
| template <class... PRODS> | ||
| inline void write(int const technology, PRODS&... prods) | ||
| { | ||
| auto file = createFile(technology, testFileName.c_str(), 'o'); | ||
| auto parent = createAssociation(technology, testTreeName); | ||
| parent->setFile(file); | ||
| parent->setupWrite(); | ||
|
|
||
| auto keepContainersAlive = doWrite(file, technology, parent, prods...); | ||
| keepContainersAlive.back() | ||
| ->commit(); //Elements are in reverse order of container construction, so this makes sure container owner calls commit() | ||
| } | ||
|
|
||
| template <class PROD> | ||
| inline std::unique_ptr<PROD const> doRead(std::shared_ptr<IStorage_File>& file, | ||
| int const technology, | ||
| std::shared_ptr<IStorage_Container>& parent) | ||
| { | ||
| auto container = createContainer(technology, makeTestBranchName<PROD>()); | ||
| auto assoc = dynamic_pointer_cast<Storage_Associative_Container>(container); | ||
| if (assoc) { | ||
| assoc->setParent(parent); | ||
| } | ||
| container->setFile(file); | ||
| void const* dataPtr = new PROD(); | ||
| void const** dataPtrPtr = &dataPtr; | ||
|
|
||
| if (!container->read(0, dataPtrPtr, typeid(PROD))) | ||
| throw std::runtime_error("Failed to read a " + getTypeName<PROD>()); | ||
|
|
||
| return std::unique_ptr<PROD const>(static_cast<PROD const*>(dataPtr)); | ||
| } | ||
|
|
||
| template <class... PRODS> | ||
| inline std::tuple<std::unique_ptr<PRODS const>...> read(int const technology) | ||
| { | ||
| auto file = createFile(technology, testFileName, 'i'); | ||
| auto parent = createAssociation(technology, testTreeName); | ||
| parent->setFile(file); | ||
|
|
||
| return std::make_tuple(doRead<PRODS>(file, technology, parent)...); | ||
| } | ||
|
|
||
| inline int getTechnology(int const argc, char const** argv) | ||
| { | ||
| if (argc > 2 || (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")))) { | ||
| std::cerr << "Expected exactly one argument, but got " << argc - 1 << "\n" | ||
| << "USAGE: testSchemaWriteOldProduct <technologyInt>\n"; | ||
| return -1; | ||
| } | ||
|
|
||
| //Default to TTree with TFile | ||
| int technology = form::technology::ROOT_TTREE; | ||
|
|
||
| if (argc == 2) | ||
| technology = std::stoi(argv[1]); | ||
|
|
||
| return technology; | ||
| } | ||
|
|
||
| } // namespace form::test | ||
|
|
||
| #endif // FORM_TEST_UTILS_HPP | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.