Skip to content

Commit d29e471

Browse files
authored
Merge pull request #704 from UWB-Biocomputing/issue-703-serialization-test
[ISSUE-703] Add Serialization tests for CPU neural simulations
2 parents ab1004a + 7d047f9 commit d29e471

12 files changed

+448
-177
lines changed

.gitignore

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,13 @@ graphitti
4242
ggraphitti
4343
cgraphitti
4444
tests
45-
serialTest
46-
deserialTest
47-
serialFileAccessTest
48-
#recorderTest
45+
serialFullTest
46+
serialFirstHalfTest
47+
serialSecondHalfTest
48+
core
49+
# core is generated by GDB during debugging
50+
51+
# Recorder Test
4952
*.exe
5053
*.out
5154
*.app

CMakeLists.txt

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ else()
5353
project(Graphitti LANGUAGES CXX C)
5454
endif()
5555

56-
#Setting the base version to C++ 11
56+
#Setting the base version to C++ 17
5757
set(CMAKE_CXX_STANDARD 17)
5858

5959
#set(DEBUG_MODE YES) for debugging, no optimization
@@ -373,35 +373,37 @@ target_link_libraries(tests gtest gtest_main)
373373
# Link the combined library into the 'tests' executable.
374374
target_link_libraries(tests combinedLib)
375375

376-
# add_executable(serialTest
377-
# Testing/RunTests.cpp
378-
# Testing/UnitTesting/SerializationTests.cpp)
376+
#------- SERIALIZATION TESTS --------------------
377+
# Serialization tests must be executed separately, as each test requires the
378+
# simulation to run from start to finish. Running multiple simulations with
379+
# the same singleton instance results in a segmentation fault (SEG FAULT).
379380

380-
# # Links the Googletest framework with the serialTest executable
381-
# target_link_libraries(serialTest gtest gtest_main)
382-
383-
# # Link the combined library into the 'serialTest' executable.
384-
# target_link_libraries(serialTest combinedLib)
381+
add_executable(serialFullTest
382+
Testing/RunTests.cpp
383+
Testing/UnitTesting/SerializationFullTest.cpp)
385384

386-
# add_executable(deserialTest
387-
# Testing/RunTests.cpp
388-
# Testing/UnitTesting/DeserializationTests.cpp)
385+
add_executable(serialFirstHalfTest
386+
Testing/RunTests.cpp
387+
Testing/UnitTesting/SerializationFirstHalfTest.cpp)
389388

390-
# # Links the Googletest framework with the deserialTest executable
391-
# target_link_libraries(deserialTest gtest gtest_main)
389+
add_executable(serialSecondHalfTest
390+
Testing/RunTests.cpp
391+
Testing/UnitTesting/SerializationSecondHalfTest.cpp)
392392

393-
# # Link the combined library into the 'deserialTest' executable.
394-
# target_link_libraries(deserialTest combinedLib)
393+
# Link the GoogleTest framework to each of the serial test executables.
394+
target_link_libraries(serialFullTest gtest gtest_main)
395+
target_link_libraries(serialFirstHalfTest gtest gtest_main)
396+
target_link_libraries(serialSecondHalfTest gtest gtest_main)
395397

396-
# add_executable(serialFileAccessTest
397-
# Testing/RunTests.cpp
398-
# Testing/UnitTesting/SerializationFileAccessTest.cpp)
398+
# Link the combined library and filesystem support to the respective serial test executables.
399+
target_link_libraries(serialFullTest stdc++fs)
400+
target_link_libraries(serialFullTest combinedLib)
399401

400-
# # Links the Googletest framework with the serialFileAccessTest executable
401-
# target_link_libraries(serialFileAccessTest gtest gtest_main)
402+
target_link_libraries(serialFirstHalfTest stdc++fs)
403+
target_link_libraries(serialFirstHalfTest combinedLib)
402404

403-
# # Link the combined library into the 'serialFileAccessTest' executable.
404-
# target_link_libraries(serialFileAccessTest combinedLib)
405+
target_link_libraries(serialSecondHalfTest stdc++fs)
406+
target_link_libraries(serialSecondHalfTest combinedLib)
405407

406408
add_executable(serialFileAccessTest
407409
Testing/RunTests.cpp

Testing/UnitTesting/DeserializationTests.cpp

Lines changed: 0 additions & 34 deletions
This file was deleted.

Testing/UnitTesting/SerializationFileAccessTest.cpp

Lines changed: 0 additions & 43 deletions
This file was deleted.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* @file SerializationFirstHalfTest.cpp
3+
*
4+
* @brief The serialization test verifies correctness through a series of steps performed across three files:
5+
* SerializeFullFileTest.cpp, SerializationFirstHalfTest.cpp, and SerializationSecondHalfTest.cpp.
6+
*
7+
* STEP 1: Run a full simulation (e.g., 10 epochs) and save its serialized output.
8+
* STEP 2: Split the full simulation's input configuration file into two halves based on the epoch count
9+
* (e.g., 10 epochs → 5 + 5 epochs).
10+
* Reference file: /configfiles/test-small-long-half.xml
11+
* STEP 3: Run the first half of the simulation (e.g., 5 epochs) and save its serialized output.
12+
* STEP 4: Run the second half of the simulation (e.g., the remaining 5 epochs) using the serialized output
13+
* from the first half as the starting point.
14+
* STEP 5: Compare the serialized output of the second half with the full simulation's serialized output.
15+
* If they match, the final result files should also be identical, confirming successful serialization.
16+
*
17+
* @note This specific test, SerializationFirstHalfTest, covers the third step: running the first half of the simulation and saving its serialized output
18+
*
19+
* To run the serialization tests, execute the script `run_serial_test.sh` located in the `build` directory.
20+
*
21+
* @ingroup Testing/UnitTesting
22+
*/
23+
24+
25+
#include "SerializationHelper.cpp"
26+
#include "gtest/gtest.h"
27+
28+
using namespace std;
29+
30+
// Test serialization by running full and half simulations, and comparing serialized files
31+
TEST(SerializationTest, SerializeFirstHalfTest)
32+
{
33+
string executable = "./cgraphitti";
34+
35+
// Configuration file for the half simulation
36+
string configFileHalf = "../configfiles/test-small-long-half.xml";
37+
38+
// Path to save the serialized output file
39+
string serialFirstHalf = "../Testing/UnitTesting/TestOutput/First-half-serialized-file.xml";
40+
41+
// Command-line arguments for the simulation
42+
string argumentFirstHalf = "-c " + configFileHalf + " -s " + serialFirstHalf;
43+
44+
// Run simulations
45+
ASSERT_TRUE(runSimulation(executable, argumentFirstHalf)) << "First half simulation failed.";
46+
47+
// Check that the serialized file was created
48+
ASSERT_TRUE(fileExists(serialFirstHalf)) << "Serialized first half file does not exist.";
49+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/**
2+
* @file SerializationFullTest.cpp
3+
*
4+
* @brief The serialization test verifies correctness through a series of steps performed across three files:
5+
* SerializeFullFileTest.cpp, SerializationFirstHalfTest.cpp, and SerializationSecondHalfTest.cpp.
6+
*
7+
* STEP 1: Run a full simulation (e.g., 10 epochs) and save its serialized output.
8+
* STEP 2: Split the full simulation's input configuration file into two halves based on the epoch count
9+
* (e.g., 10 epochs → 5 + 5 epochs).
10+
* Reference file: /configfiles/test-small-long-half.xml
11+
* STEP 3: Run the first half of the simulation (e.g., 5 epochs) and save its serialized output.
12+
* STEP 4: Run the second half of the simulation (e.g., the remaining 5 epochs) using the serialized output
13+
* from the first half as the starting point.
14+
* STEP 5: Compare the serialized output of the second half with the full simulation's serialized output.
15+
* If they match, the final result files should also be identical, confirming successful serialization.
16+
*
17+
* @note This specific test, SerializeFullFileTest, covers the first step: running the full simulation and saving the serialized file.
18+
*
19+
* To run the serialization tests, execute the script `run_serial_test.sh` located in the `build` directory.
20+
*
21+
* @ingroup Testing/UnitTesting
22+
*/
23+
24+
#include "SerializationHelper.cpp"
25+
#include "gtest/gtest.h"
26+
27+
using namespace std;
28+
29+
// Test to ensure the full simulation runs, serializes correctly, and the serialized file is created.
30+
TEST(SerializationFull, SerializeFullFileTest)
31+
{
32+
string executable = "./cgraphitti";
33+
34+
// Configuration file for the full simulation
35+
string configFileFull = "../configfiles/test-small-long.xml";
36+
37+
// Path to save the serialized output file
38+
string serialFull = "../Testing/UnitTesting/TestOutput/Full-serialized-file.xml";
39+
40+
// Command-line arguments for the simulation
41+
string argumentFull = "-c " + configFileFull + " -s " + serialFull;
42+
43+
// Run the full simulation
44+
ASSERT_TRUE(runSimulation(executable, argumentFull)) << "Full simulation failed.";
45+
46+
// Check that the serialized file was created
47+
ASSERT_TRUE(fileExists(serialFull)) << "Serialized full simulation file does not exist.";
48+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/**
2+
* @file SerializationHelper.cpp
3+
*
4+
* @brief Helper class that contains utility functions for serialization testing.
5+
*
6+
* @ingroup Testing/UnitTesting
7+
*/
8+
9+
#include "Core.h"
10+
#include <filesystem>
11+
#include <fstream>
12+
#include <tinyxml.h>
13+
14+
using namespace std;
15+
namespace fs = std::filesystem;
16+
17+
// Helper function to run the simulation
18+
bool runSimulation(const string &executable, const string &arguments)
19+
{
20+
Core core;
21+
return core.runSimulation(executable, arguments) == 0 ? true : false;
22+
}
23+
24+
// Helper function to check if a file exists
25+
bool fileExists(const string &filePath)
26+
{
27+
return fs::exists(filePath);
28+
}
29+
30+
// Helper function to compare two XML elements recursively
31+
bool compareXmlElements(TiXmlElement *elem1, TiXmlElement *elem2)
32+
{
33+
if (!elem1 || !elem2) {
34+
return false;
35+
}
36+
37+
// Compare element names
38+
if (std::string(elem1->Value()) != std::string(elem2->Value())) {
39+
return false;
40+
}
41+
42+
// Compare attributes
43+
TiXmlAttribute *attr1 = elem1->FirstAttribute();
44+
TiXmlAttribute *attr2 = elem2->FirstAttribute();
45+
46+
while (attr1 && attr2) {
47+
if (std::string(attr1->Name()) != std::string(attr2->Name())
48+
|| std::string(attr1->Value()) != std::string(attr2->Value())) {
49+
return false;
50+
}
51+
attr1 = attr1->Next();
52+
attr2 = attr2->Next();
53+
}
54+
55+
// Check if one element has more attributes than the other
56+
if (attr1 || attr2) {
57+
return false;
58+
}
59+
60+
// Compare child elements
61+
TiXmlElement *child1 = elem1->FirstChildElement();
62+
TiXmlElement *child2 = elem2->FirstChildElement();
63+
64+
while (child1 && child2) {
65+
if (!compareXmlElements(child1, child2)) {
66+
return false;
67+
}
68+
child1 = child1->NextSiblingElement();
69+
child2 = child2->NextSiblingElement();
70+
}
71+
72+
// Check if one element has more children than the other
73+
if (child1 || child2) {
74+
return false;
75+
}
76+
77+
return true;
78+
}
79+
80+
// Helper function to compare XML files
81+
bool compareXmlFiles(const std::string &filePath1, const std::string &filePath2)
82+
{
83+
TiXmlDocument doc1, doc2;
84+
85+
// Load the first XML file
86+
if (!doc1.LoadFile(filePath1.c_str())) {
87+
std::cerr << "Failed to load XML file: " << filePath1 << std::endl;
88+
return false;
89+
}
90+
91+
// Load the second XML file
92+
if (!doc2.LoadFile(filePath2.c_str())) {
93+
std::cerr << "Failed to load XML file: " << filePath2 << std::endl;
94+
return false;
95+
}
96+
97+
// Compare the root elements of both XML documents
98+
TiXmlElement *root1 = doc1.RootElement();
99+
TiXmlElement *root2 = doc2.RootElement();
100+
101+
if (!root1 || !root2) {
102+
std::cerr << "One of the XML files has no root element." << std::endl;
103+
return false;
104+
}
105+
106+
// Recursively compare the XML structures
107+
return compareXmlElements(root1, root2);
108+
}

0 commit comments

Comments
 (0)