| /* | |
| * Copyright 2021 Daniel R. Carvalho | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions are | |
| * met: redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer; | |
| * redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution; | |
| * neither the name of the copyright holders nor the names of its | |
| * contributors may be used to endorse or promote products derived from | |
| * this software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| #include <gmock/gmock.h> | |
| #include <gtest/gtest-spi.h> | |
| #include <gtest/gtest.h> | |
| #include <sys/stat.h> | |
| #include <sys/types.h> | |
| #include <unistd.h> | |
| #include <array> | |
| #include <cassert> | |
| #include <cstdint> | |
| #include <deque> | |
| #include <fstream> | |
| #include <list> | |
| #include <memory> | |
| #include <set> | |
| #include <string> | |
| #include <vector> | |
| #include "base/compiler.hh" | |
| #include "base/gtest/cur_tick_fake.hh" | |
| #include "base/gtest/logging.hh" | |
| #include "base/gtest/serialization_fixture.hh" | |
| #include "sim/serialize.hh" | |
| using namespace gem5; | |
| // Instantiate the mock class to have a valid curTick of 0 | |
| GTestTickHandler tickHandler; | |
| /** @return Whether the given dir exists and is accessible. */ | |
| bool | |
| dirExists(std::string dir) | |
| { | |
| struct stat info; | |
| return (stat(dir.c_str(), &info) == 0) && (info.st_mode & S_IFDIR); | |
| } | |
| using SerializeFixture = SerializationFixture; | |
| class CheckpointInFixture : public SerializationFixture | |
| { | |
| public: | |
| std::unique_ptr<CheckpointIn> cpt; | |
| using SerializeFixture::SerializeFixture; | |
| void | |
| SetUp() override | |
| { | |
| SerializeFixture::SetUp(); | |
| std::ofstream file(getCptPath()); | |
| assert(file.good()); | |
| file << R"cpt_file( | |
| [General] | |
| Test1=BARasdf | |
| Test2=bar | |
| [Junk] | |
| Test3=yo | |
| Test4=mama | |
| [Foo] | |
| Foo1=89 | |
| Foo2=384 | |
| [General] | |
| Test3=89 | |
| [Junk] | |
| Test4+=mia | |
| )cpt_file"; | |
| file.close(); | |
| cpt = std::make_unique<CheckpointIn>(getDirName()); | |
| } | |
| void | |
| TearDown() override | |
| { | |
| std::remove((getCptPath()).c_str()); | |
| SerializeFixture::TearDown(); | |
| } | |
| }; | |
| /** | |
| * A fixture to handle checkpoint in and out variables, as well as the | |
| * testing of the temporary directory. | |
| */ | |
| class SerializableFixture : public SerializeFixture | |
| { | |
| public: | |
| std::unique_ptr<CheckpointIn> cpt_in; | |
| std::unique_ptr<std::ofstream> cpt_out; | |
| using SerializeFixture::SerializeFixture; | |
| void | |
| SetUp() override | |
| { | |
| SerializeFixture::SetUp(); | |
| cpt_out = std::make_unique<std::ofstream>(getCptPath()); | |
| assert(cpt_out->good()); | |
| cpt_in = std::make_unique<CheckpointIn>(getDirName()); | |
| } | |
| void | |
| TearDown() override | |
| { | |
| std::remove((getCptPath()).c_str()); | |
| SerializeFixture::TearDown(); | |
| } | |
| }; | |
| using SerializeFixtureDeathTest = SerializeFixture; | |
| using CheckpointInFixtureDeathTest = CheckpointInFixture; | |
| using SerializableFixtureDeathTest = SerializableFixture; | |
| /** Tests that when setting a checkpoint dir it always ends with a slash. */ | |
| TEST(CheckpointInTest, SetGetDirSlash) | |
| { | |
| ASSERT_EQ(CheckpointIn::setDir(""), "/"); | |
| ASSERT_EQ(CheckpointIn::dir(), "/"); | |
| ASSERT_EQ(CheckpointIn::setDir("/"), "/"); | |
| ASSERT_EQ(CheckpointIn::dir(), "/"); | |
| ASSERT_EQ(CheckpointIn::setDir("test_cpt_dir"), "test_cpt_dir/"); | |
| ASSERT_EQ(CheckpointIn::dir(), "test_cpt_dir/"); | |
| ASSERT_EQ(CheckpointIn::setDir("test_cpt_dir_2/"), "test_cpt_dir_2/"); | |
| ASSERT_EQ(CheckpointIn::dir(), "test_cpt_dir_2/"); | |
| } | |
| /** | |
| * Tests that when the dir name has a "%d" curTick is added. It may also | |
| * work with other formats, but it is not intended. | |
| */ | |
| TEST(CheckpointInTest, SetGetDirTick) | |
| { | |
| ASSERT_EQ(CheckpointIn::setDir("tick%d"), "tick0/"); | |
| ASSERT_EQ(CheckpointIn::dir(), "tick0/"); | |
| ASSERT_EQ(CheckpointIn::setDir("ti%dck"), "ti0ck/"); | |
| ASSERT_EQ(CheckpointIn::dir(), "ti0ck/"); | |
| } | |
| /** | |
| * Test constructor failure by requesting the creation of a checkpoint in | |
| * a non-existent dir. | |
| */ | |
| TEST_F(SerializeFixtureDeathTest, ConstructorFailure) | |
| { | |
| // Assign another cpt dir to make sure that it is changed when a new | |
| // CheckpointIn instance is created | |
| CheckpointIn::setDir("test"); | |
| // Make sure file does not exist, so that the constructor will fail | |
| std::ifstream file(getCptPath()); | |
| assert(!file.good()); | |
| ASSERT_ANY_THROW(CheckpointIn cpt(getDirName())); | |
| } | |
| /** | |
| * Test constructor success by requesting the creation of a checkpoint | |
| * in a specific valid dir. The static cpt dir is change on instantiation. | |
| */ | |
| TEST_F(SerializeFixture, ConstructorSuccess) | |
| { | |
| // Assign another cpt dir to make sure that it is changed when a new | |
| // CheckpointIn instance is created | |
| CheckpointIn::setDir("test"); | |
| // Create the file before creating the cpt to make sure it exists | |
| std::ofstream file(getCptPath()); | |
| assert(file.good()); | |
| file.close(); | |
| CheckpointIn cpt(getDirName()); | |
| // When a new CheckpointIn instance is created the static cpt dir changes | |
| EXPECT_EQ(CheckpointIn::dir(), getDirName()); | |
| } | |
| /** | |
| * Test that changing the static cpt dir does not change the name of the | |
| * cpt dir of previously created instances. | |
| */ | |
| TEST_F(CheckpointInFixtureDeathTest, GetCptDir) | |
| { | |
| ASSERT_ANY_THROW(CheckpointIn("/random_dir_name")); | |
| } | |
| /** Test finding sections. */ | |
| TEST_F(CheckpointInFixture, FindSections) | |
| { | |
| // Successful searches | |
| ASSERT_TRUE(cpt->sectionExists("General")); | |
| ASSERT_TRUE(cpt->sectionExists("Junk")); | |
| ASSERT_TRUE(cpt->sectionExists("Foo")); | |
| // Failed searches | |
| ASSERT_FALSE(cpt->sectionExists("Junk2")); | |
| ASSERT_FALSE(cpt->sectionExists("Test1")); | |
| } | |
| /** Test finding entries. */ | |
| TEST_F(CheckpointInFixture, FindEntries) | |
| { | |
| // Successful searches | |
| ASSERT_TRUE(cpt->entryExists("General", "Test2")); | |
| ASSERT_TRUE(cpt->entryExists("Junk", "Test3")); | |
| ASSERT_TRUE(cpt->entryExists("Junk", "Test4")); | |
| ASSERT_TRUE(cpt->entryExists("General", "Test1")); | |
| ASSERT_TRUE(cpt->entryExists("General", "Test3")); | |
| // Failed searches | |
| ASSERT_FALSE(cpt->entryExists("Junk2", "test3")); | |
| ASSERT_FALSE(cpt->entryExists("Junk", "test4")); | |
| } | |
| /** Test extracting the values of entries. */ | |
| TEST_F(CheckpointInFixture, ExtractEntries) | |
| { | |
| std::string value; | |
| // Successful searches | |
| ASSERT_TRUE(cpt->find("General", "Test2", value)); | |
| ASSERT_EQ(value, "bar"); | |
| ASSERT_TRUE(cpt->find("Junk", "Test3", value)); | |
| ASSERT_EQ(value, "yo"); | |
| ASSERT_TRUE(cpt->find("Junk", "Test4", value)); | |
| ASSERT_EQ(value, "mama mia"); | |
| ASSERT_TRUE(cpt->find("General", "Test1", value)); | |
| ASSERT_EQ(value, "BARasdf"); | |
| ASSERT_TRUE(cpt->find("General", "Test3", value)); | |
| ASSERT_EQ(value, "89"); | |
| // Failed searches | |
| ASSERT_FALSE(cpt->find("Junk2", "test3", value)); | |
| ASSERT_FALSE(cpt->find("Junk", "test4", value)); | |
| } | |
| /** | |
| * Test that paths are increased and decreased according to the scope that | |
| * its SCS was created in (using CheckpointIn). | |
| */ | |
| TEST_F(CheckpointInFixture, SCSCptInPathScoped) | |
| { | |
| Serializable::ScopedCheckpointSection scs(*(cpt.get()), "Section1"); | |
| ASSERT_EQ(Serializable::currentSection(), "Section1"); | |
| { | |
| Serializable::ScopedCheckpointSection scs_2(*(cpt.get()), "Section2"); | |
| ASSERT_EQ(Serializable::currentSection(), "Section1.Section2"); | |
| Serializable::ScopedCheckpointSection scs_3(*(cpt.get()), "Section3"); | |
| ASSERT_EQ(Serializable::currentSection(), | |
| "Section1.Section2.Section3"); | |
| } | |
| Serializable::ScopedCheckpointSection scs_4(*(cpt.get()), "Section4"); | |
| ASSERT_EQ(Serializable::currentSection(), "Section1.Section4"); | |
| } | |
| /** | |
| * Test that paths are increased and decreased according to the scope that | |
| * its SCS was created in (using CheckpointOut). | |
| */ | |
| TEST_F(SerializeFixture, SCSCptOutPathScoped) | |
| { | |
| std::ofstream cpt(getCptPath()); | |
| Serializable::ScopedCheckpointSection scs(cpt, "Section1"); | |
| ASSERT_EQ(Serializable::currentSection(), "Section1"); | |
| { | |
| Serializable::ScopedCheckpointSection scs_2(cpt, "Section2"); | |
| ASSERT_EQ(Serializable::currentSection(), "Section1.Section2"); | |
| Serializable::ScopedCheckpointSection scs_3(cpt, "Section3"); | |
| ASSERT_EQ(Serializable::currentSection(), | |
| "Section1.Section2.Section3"); | |
| } | |
| Serializable::ScopedCheckpointSection scs_4(cpt, "Section4"); | |
| ASSERT_EQ(Serializable::currentSection(), "Section1.Section4"); | |
| } | |
| /** | |
| * Make sure that a SCS that uses a CheckpointIn does not change the | |
| * checkpoint file's contents. | |
| */ | |
| TEST_F(SerializeFixture, SCSNoChangeCptIn) | |
| { | |
| { | |
| // Create empty cpt file | |
| std::ofstream os(getCptPath()); | |
| assert(os.good()); | |
| os.close(); | |
| } | |
| CheckpointIn cpt(getDirName()); | |
| std::ifstream is(getCptPath()); | |
| assert(is.good()); | |
| ASSERT_EQ(is.peek(), std::ifstream::traits_type::eof()); | |
| Serializable::ScopedCheckpointSection scs(cpt, "Section1"); | |
| ASSERT_EQ(is.peek(), std::ifstream::traits_type::eof()); | |
| ASSERT_EQ(Serializable::currentSection(), "Section1"); | |
| } | |
| /** @return The ostream as a std::string. */ | |
| std::string | |
| getString(std::istream &is) | |
| { | |
| auto buf = is.rdbuf(); | |
| std::ostringstream oss; | |
| oss << buf; | |
| return oss.str(); | |
| } | |
| /** | |
| * Flushes the checkpoint and reads its contents. | |
| * | |
| * @param cpt The checkpoint to be flushed. | |
| * @param filename The name of the file to be read. | |
| * @return The contents in the filename, as a string. | |
| */ | |
| std::string | |
| getContents(std::ofstream &cpt, std::string filename) | |
| { | |
| // The checkpoint must be flushed, otherwise the file may not be up- | |
| // to-date and the assertions below will fail | |
| cpt.flush(); | |
| std::ifstream is(filename); | |
| assert(is.good()); | |
| return std::string(std::istreambuf_iterator<char>(is), | |
| std::istreambuf_iterator<char>()); | |
| } | |
| /** | |
| * Make sure that a SCS that uses a CheckpointOut changes the checkpoint | |
| * file's contents (single section). | |
| */ | |
| TEST_F(SerializableFixture, SCSChangeCptOutSingle) | |
| { | |
| Serializable::ScopedCheckpointSection scs(*cpt_out, "Section1"); | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), | |
| "\n[Section1]\n"); | |
| } | |
| /** | |
| * Make sure that a SCS that uses a CheckpointOut changes the checkpoint | |
| * file's contents (multiple sections). | |
| */ | |
| TEST_F(SerializableFixture, SCSChangeCptOutMultiple) | |
| { | |
| std::string expected = ""; | |
| Serializable::ScopedCheckpointSection scs(*cpt_out, "Section1"); | |
| expected += "\n[Section1]\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| { | |
| Serializable::ScopedCheckpointSection scs_2(*cpt_out, "Section2"); | |
| expected += "\n[Section1.Section2]\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| Serializable::ScopedCheckpointSection scs_3(*cpt_out, "Section3"); | |
| expected += "\n[Section1.Section2.Section3]\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| } | |
| Serializable::ScopedCheckpointSection scs_4(*cpt_out, "Section4"); | |
| expected += "\n[Section1.Section4]\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| } | |
| /** | |
| * Make sure that a SCS that uses a CheckpointOut changes the checkpoint | |
| * file's contents (large test). | |
| */ | |
| TEST_F(SerializableFixture, SCSChangeCptOutLarge) | |
| { | |
| std::string expected = ""; | |
| Serializable::ScopedCheckpointSection scs(*cpt_out, "Section1"); | |
| expected += "\n[Section1]\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| { | |
| Serializable::ScopedCheckpointSection scs_2(*cpt_out, "Section2"); | |
| expected += "\n[Section1.Section2]\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| { | |
| Serializable::ScopedCheckpointSection scs_3(*cpt_out, "Section3"); | |
| expected += "\n[Section1.Section2.Section3]\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), | |
| expected); | |
| } | |
| Serializable::ScopedCheckpointSection scs_4(*cpt_out, "Section4"); | |
| expected += "\n[Section1.Section2.Section4]\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| } | |
| Serializable::ScopedCheckpointSection scs_5(*cpt_out, "Section5"); | |
| expected += "\n[Section1.Section5]\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| { | |
| Serializable::ScopedCheckpointSection scs_6(*cpt_out, "Section6"); | |
| expected += "\n[Section1.Section5.Section6]\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| Serializable::ScopedCheckpointSection scs_7(*cpt_out, "Section7"); | |
| expected += "\n[Section1.Section5.Section6.Section7]\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| } | |
| Serializable::ScopedCheckpointSection scs_8(*cpt_out, "Section8"); | |
| expected += "\n[Section1.Section5.Section8]\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| } | |
| /** Test failure to create dir. Try to create a dir in a non-existent dir. */ | |
| TEST(SerializableDeathTest, GenerateCptOutFail) | |
| { | |
| std::ofstream cpt; | |
| const std::string dir_name = | |
| SerializeFixture::generateTempDirName(); | |
| ASSERT_FALSE(dirExists(dir_name)); | |
| ASSERT_ANY_THROW(Serializable::generateCheckpointOut( | |
| dir_name + "/b/a/n/a/n/a/", cpt)); | |
| } | |
| /** Test successful CheckpointOut generation with non-existent dir. */ | |
| TEST_F(SerializeFixture, GenerateCptOut) | |
| { | |
| // The fixture will auto-create the dir. Remove it. | |
| assert(rmdir(getDirName().c_str()) == 0); | |
| std::ofstream cpt; | |
| Serializable::generateCheckpointOut(getDirName(), cpt); | |
| ASSERT_TRUE(dirExists(getDirName())); | |
| // Make sure the checkpoint was properly created. Using EXPECT to | |
| // force removing the directory at the end | |
| EXPECT_NE(getContents(cpt, getCptPath()).find( | |
| "## checkpoint generated: "), std::string::npos); | |
| } | |
| /** Test successful CheckpointOut generation with existing dir. */ | |
| TEST_F(SerializeFixture, GenerateCptOutExistent) | |
| { | |
| assert(dirExists(getDirName())); | |
| // Create the checkpoint and make sure it has been properly created by | |
| // deleting it and making sure the function was successful | |
| std::ofstream cpt; | |
| Serializable::generateCheckpointOut(getDirName(), cpt); | |
| EXPECT_TRUE(remove((getCptPath()).c_str()) == 0); | |
| } | |
| class SerializableType : public Serializable | |
| { | |
| private: | |
| mutable bool _serialized = false; | |
| bool _unserialized = false; | |
| public: | |
| SerializableType() : Serializable() {} | |
| void serialize(CheckpointOut &cp) const override { _serialized = true; } | |
| void unserialize(CheckpointIn &cp) override { _unserialized = true; } | |
| /** | |
| * Checks if serialize() has been called and then marks it as not called. | |
| * | |
| * @return True if serialize() has been called. | |
| */ | |
| bool | |
| checkAndResetSerialized() | |
| { | |
| const bool serialized = _serialized; | |
| _serialized = false; | |
| return serialized; | |
| } | |
| /** | |
| * Checks if unserialize() has been called and then marks it as not called. | |
| * | |
| * @return True if unserialize() has been called. | |
| */ | |
| bool | |
| checkAndResetUnserialized() | |
| { | |
| const bool unserialized = _unserialized; | |
| _unserialized = false; | |
| return unserialized; | |
| } | |
| }; | |
| /** | |
| * Test section serialization and unserialization for an object without | |
| * serializable contents. Since how (un)serialize() works is independent of | |
| * the Serializable class, we just make sure that the respective functions | |
| * are called when calling (un)serializeSection(). | |
| */ | |
| TEST_F(SerializableFixture, SectionSerializationSimple) | |
| { | |
| SerializableType serializable; | |
| // Serialization | |
| { | |
| serializable.serializeSection(*cpt_out, "Section1"); | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), | |
| "\n[Section1]\n"); | |
| ASSERT_TRUE(serializable.checkAndResetSerialized()); | |
| ASSERT_FALSE(serializable.checkAndResetUnserialized()); | |
| serializable.serializeSection(*cpt_out, "Section2"); | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), | |
| "\n[Section1]\n\n[Section2]\n"); | |
| ASSERT_TRUE(serializable.checkAndResetSerialized()); | |
| ASSERT_FALSE(serializable.checkAndResetUnserialized()); | |
| serializable.serializeSection(*cpt_out, "Section3"); | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), | |
| "\n[Section1]\n\n[Section2]\n\n[Section3]\n"); | |
| ASSERT_TRUE(serializable.checkAndResetSerialized()); | |
| ASSERT_FALSE(serializable.checkAndResetUnserialized()); | |
| } | |
| // Unserialization. Since the object has no serializable contents, | |
| // just make sure it does not throw for existent and non-existent | |
| // sections | |
| { | |
| ASSERT_NO_THROW(serializable.unserializeSection(*cpt_in, "Section1")); | |
| ASSERT_FALSE(serializable.checkAndResetSerialized()); | |
| ASSERT_TRUE(serializable.checkAndResetUnserialized()); | |
| ASSERT_NO_THROW(serializable.unserializeSection(*cpt_in, "Section2")); | |
| ASSERT_FALSE(serializable.checkAndResetSerialized()); | |
| ASSERT_TRUE(serializable.checkAndResetUnserialized()); | |
| ASSERT_NO_THROW(serializable.unserializeSection(*cpt_in, "Section3")); | |
| ASSERT_FALSE(serializable.checkAndResetSerialized()); | |
| ASSERT_TRUE(serializable.checkAndResetUnserialized()); | |
| ASSERT_NO_THROW(serializable.unserializeSection(*cpt_in, "Section4")); | |
| ASSERT_FALSE(serializable.checkAndResetSerialized()); | |
| ASSERT_TRUE(serializable.checkAndResetUnserialized()); | |
| } | |
| } | |
| /** | |
| * Test that paramIn called on a param that does not exist triggers an error. | |
| */ | |
| TEST_F(SerializableFixtureDeathTest, ParamIn) | |
| { | |
| int unserialized_integer; | |
| Serializable::ScopedCheckpointSection scs(*cpt_in, "Section1"); | |
| ASSERT_ANY_THROW(paramIn(*cpt_in, "Param1", unserialized_integer)); | |
| } | |
| /** | |
| * Test serialization followed by unserialization, using ParamInImpl and | |
| * ParamOut. | |
| */ | |
| TEST_F(SerializableFixture, ParamOutIn) | |
| { | |
| const int integer = 5; | |
| const double real = 3.7; | |
| const bool boolean = true; | |
| const std::string str = "string test"; | |
| const char character = 'c'; | |
| // Serialization | |
| { | |
| Serializable::ScopedCheckpointSection scs(*cpt_out, "Section1"); | |
| std::string expected = "\n[Section1]\n"; | |
| paramOut(*cpt_out, "Param1", integer); | |
| expected += "Param1=5\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| paramOut(*cpt_out, "Param2", real); | |
| expected += "Param2=3.7\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| paramOut(*cpt_out, "Param3", boolean); | |
| expected += "Param3=true\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| paramOut(*cpt_out, "Param4", str); | |
| expected += "Param4=string test\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| paramOut(*cpt_out, "Param5", character); | |
| expected += "Param5=99\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| } | |
| // Unserialization | |
| { | |
| CheckpointIn cpt(getDirName()); | |
| int unserialized_integer; | |
| double unserialized_real; | |
| bool unserialized_boolean; | |
| std::string unserialized_str; | |
| char unserialized_character; | |
| Serializable::ScopedCheckpointSection scs(cpt, "Section1"); | |
| paramIn(cpt, "Param1", unserialized_integer); | |
| ASSERT_EQ(integer, unserialized_integer); | |
| paramIn(cpt, "Param2", unserialized_real); | |
| ASSERT_EQ(real, unserialized_real); | |
| paramIn(cpt, "Param3", unserialized_boolean); | |
| ASSERT_EQ(boolean, unserialized_boolean); | |
| paramIn(cpt, "Param4", unserialized_str); | |
| ASSERT_EQ(str, unserialized_str); | |
| paramIn(cpt, "Param5", unserialized_character); | |
| ASSERT_EQ(character, unserialized_character); | |
| } | |
| } | |
| /** | |
| * Test serialization followed by unserialization, using ParamInImpl and | |
| * ParamOut, when multiple sections exist. | |
| */ | |
| TEST_F(SerializableFixture, ParamOutInMultipleSections) | |
| { | |
| const int integer = 5; | |
| const double real = 3.7; | |
| const bool boolean = true; | |
| const std::string str = "string test"; | |
| const char character = 'c'; | |
| // Serialization | |
| { | |
| Serializable::ScopedCheckpointSection scs(*cpt_out, "Section1"); | |
| std::string expected = "\n[Section1]\n"; | |
| paramOut(*cpt_out, "Param1", integer); | |
| expected += "Param1=5\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| paramOut(*cpt_out, "Param2", real); | |
| expected += "Param2=3.7\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| { | |
| Serializable::ScopedCheckpointSection scs_2(*cpt_out, "Section2"); | |
| expected += "\n[Section1.Section2]\n"; | |
| paramOut(*cpt_out, "Param3", boolean); | |
| expected += "Param3=true\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), | |
| expected); | |
| } | |
| // Possibly unexpected behavior: Since scs_2 has gone out of scope | |
| // the user may expect that we'd go back to Section1; however, this | |
| // is not the case, and Param4 is added to Section1.Section2 | |
| paramOut(*cpt_out, "Param4", str); | |
| expected += "Param4=string test\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), expected); | |
| { | |
| Serializable::ScopedCheckpointSection scs_3(*cpt_out, "Section3"); | |
| expected += "\n[Section1.Section3]\n"; | |
| Serializable::ScopedCheckpointSection scs_4(*cpt_out, "Section4"); | |
| expected += "\n[Section1.Section3.Section4]\n"; | |
| paramOut(*cpt_out, "Param5", character); | |
| expected += "Param5=99\n"; | |
| ASSERT_EQ(getContents(*cpt_out, getCptPath()), | |
| expected); | |
| } | |
| } | |
| // Unserialization | |
| { | |
| CheckpointIn cpt(getDirName()); | |
| int unserialized_integer; | |
| double unserialized_real; | |
| bool unserialized_boolean; | |
| std::string unserialized_str; | |
| char unserialized_character; | |
| Serializable::ScopedCheckpointSection scs(cpt, "Section1"); | |
| paramIn(cpt, "Param1", unserialized_integer); | |
| ASSERT_EQ(integer, unserialized_integer); | |
| paramIn(cpt, "Param2", unserialized_real); | |
| ASSERT_EQ(real, unserialized_real); | |
| { | |
| Serializable::ScopedCheckpointSection scs_2(cpt, "Section2"); | |
| paramIn(cpt, "Param3", unserialized_boolean); | |
| ASSERT_EQ(boolean, unserialized_boolean); | |
| // Due to the reason mentioned above on serialization, this param | |
| // must be extracted within the scope of Section 2 | |
| paramIn(cpt, "Param4", unserialized_str); | |
| ASSERT_EQ(str, unserialized_str); | |
| } | |
| { | |
| Serializable::ScopedCheckpointSection scs_3(cpt, "Section3"); | |
| Serializable::ScopedCheckpointSection scs_4(cpt, "Section4"); | |
| paramIn(cpt, "Param5", unserialized_character); | |
| ASSERT_EQ(character, unserialized_character); | |
| } | |
| } | |
| } | |
| /** Test optional parameters. */ | |
| TEST_F(SerializeFixture, OptParamOutIn) | |
| { | |
| const double real = 3.7; | |
| const std::string str = "string test"; | |
| // Serialization | |
| { | |
| std::ofstream cpt(getCptPath()); | |
| Serializable::ScopedCheckpointSection scs(cpt, "Section1"); | |
| paramOut(cpt, "Param2", real); | |
| paramOut(cpt, "Param4", str); | |
| } | |
| // Unserialization | |
| { | |
| CheckpointIn cpt(getDirName()); | |
| int unserialized_integer; | |
| double unserialized_real; | |
| bool unserialized_boolean; | |
| std::string unserialized_str; | |
| Serializable::ScopedCheckpointSection scs(cpt, "Section1"); | |
| // Optional without warning | |
| gtestLogOutput.str(""); | |
| ASSERT_FALSE(optParamIn(cpt, "Param1", unserialized_integer, false)); | |
| ASSERT_EQ(gtestLogOutput.str(), ""); | |
| gtestLogOutput.str(""); | |
| ASSERT_TRUE(optParamIn(cpt, "Param2", unserialized_real, false)); | |
| ASSERT_EQ(real, unserialized_real); | |
| ASSERT_EQ(gtestLogOutput.str(), ""); | |
| // Optional with default request for warning | |
| gtestLogOutput.str(""); | |
| ASSERT_FALSE(optParamIn(cpt, "Param3", unserialized_boolean)); | |
| ASSERT_THAT(gtestLogOutput.str(), | |
| ::testing::HasSubstr("warn: optional parameter Section1:Param3 " | |
| "not present\n")); | |
| gtestLogOutput.str(""); | |
| ASSERT_TRUE(optParamIn(cpt, "Param4", unserialized_str)); | |
| ASSERT_EQ(str, unserialized_str); | |
| ASSERT_EQ(gtestLogOutput.str(), ""); | |
| // Explicit request for warning | |
| gtestLogOutput.str(""); | |
| ASSERT_FALSE(optParamIn(cpt, "Param5", unserialized_boolean, true)); | |
| ASSERT_THAT(gtestLogOutput.str(), | |
| ::testing::HasSubstr("warn: optional parameter Section1:Param5 " | |
| "not present\n")); | |
| } | |
| } | |
| /** Check for death when there is no section and paramIn is requested. */ | |
| TEST_F(SerializableFixtureDeathTest, NoSectionParamIn) | |
| { | |
| #ifndef NDEBUG | |
| GTEST_SKIP() << "Skipping as assertions are " | |
| "stripped out of fast builds"; | |
| #endif | |
| std::ofstream of(getCptPath()); | |
| CheckpointIn cpt(getDirName()); | |
| int unserialized_integer; | |
| ASSERT_DEATH(paramIn(cpt, "Param1", unserialized_integer), ""); | |
| } | |
| /** Test arrayParamOut and arrayParamIn. */ | |
| TEST_F(SerializeFixture, ArrayParamOutIn) | |
| { | |
| const int integer[] = {5, 10, 15}; | |
| std::array<double, 4> real = {0.1, 1.345, 892.72, 1e+10}; | |
| std::list<bool> boolean = {true, false}; | |
| std::vector<std::string> str = {"a", "string", "test"}; | |
| std::set<uint64_t> uint64 = {12751928501, 13, 111111}; | |
| std::deque<uint8_t> uint8 = {17, 42, 255}; | |
| // Serialization | |
| { | |
| std::ofstream cpt(getCptPath()); | |
| Serializable::ScopedCheckpointSection scs(cpt, "Section1"); | |
| std::string expected = "\n[Section1]\n"; | |
| arrayParamOut(cpt, "Param1", integer); | |
| expected += "Param1=5 10 15\n"; | |
| ASSERT_EQ(getContents(cpt, getCptPath()), expected); | |
| arrayParamOut(cpt, "Param2", real); | |
| expected += "Param2=0.1 1.345 892.72 1e+10\n"; | |
| ASSERT_EQ(getContents(cpt, getCptPath()), expected); | |
| arrayParamOut(cpt, "Param3", boolean); | |
| expected += "Param3=true false\n"; | |
| ASSERT_EQ(getContents(cpt, getCptPath()), expected); | |
| arrayParamOut(cpt, "Param4", str); | |
| expected += "Param4=a string test\n"; | |
| ASSERT_EQ(getContents(cpt, getCptPath()), expected); | |
| arrayParamOut(cpt, "Param5", uint64); | |
| expected += "Param5=13 111111 12751928501\n"; | |
| ASSERT_EQ(getContents(cpt, getCptPath()), expected); | |
| arrayParamOut(cpt, "Param6", uint8); | |
| expected += "Param6=17 42 255\n"; | |
| ASSERT_EQ(getContents(cpt, getCptPath()), expected); | |
| } | |
| // Unserialization | |
| { | |
| CheckpointIn cpt(getDirName()); | |
| int unserialized_integer[3]; | |
| std::array<double, 4> unserialized_real; | |
| std::list<bool> unserialized_boolean; | |
| std::vector<std::string> unserialized_str; | |
| std::set<uint64_t> unserialized_uint64; | |
| std::deque<uint8_t> unserialized_uint8; | |
| Serializable::ScopedCheckpointSection scs(cpt, "Section1"); | |
| arrayParamIn(cpt, "Param1", unserialized_integer, 3); | |
| ASSERT_THAT(unserialized_integer, testing::ElementsAre(5, 10, 15)); | |
| arrayParamIn(cpt, "Param2", unserialized_real.data(), | |
| unserialized_real.size()); | |
| ASSERT_EQ(real, unserialized_real); | |
| arrayParamIn(cpt, "Param3", unserialized_boolean); | |
| ASSERT_EQ(boolean, unserialized_boolean); | |
| arrayParamIn(cpt, "Param4", unserialized_str); | |
| ASSERT_EQ(str, unserialized_str); | |
| arrayParamIn(cpt, "Param5", unserialized_uint64); | |
| ASSERT_EQ(uint64, unserialized_uint64); | |
| arrayParamIn(cpt, "Param6", unserialized_uint8); | |
| ASSERT_EQ(uint8, unserialized_uint8); | |
| } | |
| } | |
| /** | |
| * Test arrayParamOut and arrayParamIn for strings with spaces. | |
| * @todo This is broken because spaces are delimiters between array | |
| * entries; so, strings containing spaces are seen as multiple entries | |
| */ | |
| TEST_F(SerializeFixture, DISABLED_ArrayParamOutInSpacedStrings) | |
| { | |
| std::vector<std::string> str = {"a string test", "for", "array param out"}; | |
| // Serialization | |
| { | |
| std::ofstream cpt(getCptPath()); | |
| Serializable::ScopedCheckpointSection scs(cpt, "Section1"); | |
| std::string expected = "\n[Section1]\n"; | |
| arrayParamOut(cpt, "Param1", str); | |
| expected += "Param1=string test for array param out\n"; | |
| ASSERT_EQ(getContents(cpt, getCptPath()), expected); | |
| } | |
| // Unserialization | |
| { | |
| CheckpointIn cpt(getDirName()); | |
| std::vector<std::string> unserialized_str; | |
| Serializable::ScopedCheckpointSection scs(cpt, "Section1"); | |
| arrayParamIn(cpt, "Param1", unserialized_str); | |
| ASSERT_EQ(str, unserialized_str); | |
| } | |
| } | |
| /** | |
| * Test that using arrayParamIn with sizes smaller than the container's | |
| * throws an exception. | |
| */ | |
| TEST_F(SerializeFixtureDeathTest, ArrayParamOutInSmaller) | |
| { | |
| // Serialization | |
| { | |
| const int integer[] = {5, 10, 15}; | |
| std::ofstream cpt(getCptPath()); | |
| Serializable::ScopedCheckpointSection scs(cpt, "Section1"); | |
| std::string expected = "\n[Section1]\n"; | |
| arrayParamOut(cpt, "Param1", integer); | |
| expected += "Param1=5 10 15\n"; | |
| ASSERT_EQ(getContents(cpt, getCptPath()), expected); | |
| } | |
| // Unserialization | |
| { | |
| CheckpointIn cpt(getDirName()); | |
| int unserialized_integer[1]; | |
| Serializable::ScopedCheckpointSection scs(cpt, "Section1"); | |
| ASSERT_ANY_THROW(arrayParamIn(cpt, "Param1", unserialized_integer, 2)); | |
| } | |
| } | |
| /** Test mappingParamOut and mappingParamIn with all keys. */ | |
| TEST_F(SerializeFixture, MappingParamOutIn) | |
| { | |
| const int integers[] = {10, 32, 100}; | |
| std::array<double, 4> reals = {0.1, 1.345, 892.72, 1e+10}; | |
| const char* const names_ints[] = {"ten", "thirty-two", "one hundred"}; | |
| const char* const names_reals[] = {"first", "second", "third", "fourth"}; | |
| // Serialization | |
| { | |
| std::ofstream cpt(getCptPath()); | |
| Serializable::ScopedCheckpointSection scs(cpt, "Section1"); | |
| std::string expected = "\n[Section1]\n"; | |
| mappingParamOut(cpt, "Integers", names_ints, integers, 3); | |
| expected += "\n[Section1.Integers]\nten=10\nthirty-two=32\n" | |
| "one hundred=100\n"; | |
| ASSERT_EQ(getContents(cpt, getCptPath()), expected); | |
| mappingParamOut(cpt, "Reals", names_reals, reals.data(), reals.size()); | |
| expected += "\n[Section1.Reals]\nfirst=0.1\nsecond=1.345\n" | |
| "third=892.72\nfourth=1e+10\n"; | |
| ASSERT_EQ(getContents(cpt, getCptPath()), expected); | |
| } | |
| // Unserialization | |
| { | |
| CheckpointIn cpt(getDirName()); | |
| int unserialized_integers[3]; | |
| std::array<double, 4> unserialized_reals; | |
| mappingParamIn(cpt, "Section1.Integers", names_ints, | |
| unserialized_integers, 3); | |
| ASSERT_THAT(unserialized_integers, testing::ElementsAre(10, 32, 100)); | |
| mappingParamIn(cpt, "Section1.Reals", names_reals, | |
| unserialized_reals.data(), unserialized_reals.size()); | |
| ASSERT_EQ(unserialized_reals, reals); | |
| } | |
| } | |
| /** Test that missing keys are ignored on mappingParamIn. */ | |
| TEST_F(SerializeFixture, MappingParamOutInMissing) | |
| { | |
| const int integers[] = {10, 32, 100}; | |
| std::array<double, 4> reals = {0.1, 1.345, 892.72, 1e+10}; | |
| // Serialization | |
| { | |
| const char* const names_ints[] = {"ten", "thirty-two", "one hundred"}; | |
| const char* const names_reals[] = | |
| {"first", "second", "third", "fourth"}; | |
| std::ofstream cpt(getCptPath()); | |
| Serializable::ScopedCheckpointSection scs(cpt, "Section1"); | |
| std::string expected = "\n[Section1]\n"; | |
| mappingParamOut(cpt, "Integers", names_ints, integers, 3); | |
| expected += "\n[Section1.Integers]\nten=10\nthirty-two=32\n" | |
| "one hundred=100\n"; | |
| ASSERT_EQ(getContents(cpt, getCptPath()), expected); | |
| mappingParamOut(cpt, "Reals", names_reals, reals.data(), reals.size()); | |
| expected += "\n[Section1.Reals]\nfirst=0.1\nsecond=1.345\n" | |
| "third=892.72\nfourth=1e+10\n"; | |
| ASSERT_EQ(getContents(cpt, getCptPath()), expected); | |
| } | |
| // Unserialization | |
| { | |
| const char* const names_ints[] = {"one hundred"}; | |
| const char* const names_reals[] = {"first", "third"}; | |
| std::array<double, 2> expected_reals = {0.1, 892.72}; | |
| CheckpointIn cpt(getDirName()); | |
| std::string err; | |
| int unserialized_integers[1]; | |
| std::array<double, 2> unserialized_reals; | |
| gtestLogOutput.str(""); | |
| mappingParamIn(cpt, "Section1.Integers", names_ints, | |
| unserialized_integers, 1); | |
| ASSERT_THAT(unserialized_integers, testing::ElementsAre(100)); | |
| err = gtestLogOutput.str(); | |
| ASSERT_THAT(err, ::testing::HasSubstr("warn: unknown entry found in " | |
| "checkpoint: Section1.Integers thirty-two 32\n")); | |
| ASSERT_THAT(err, ::testing::HasSubstr("warn: unknown entry found in " | |
| "checkpoint: Section1.Integers ten 10\n")); | |
| gtestLogOutput.str(""); | |
| mappingParamIn(cpt, "Section1.Reals", names_reals, | |
| unserialized_reals.data(), unserialized_reals.size()); | |
| ASSERT_EQ(unserialized_reals, expected_reals); | |
| err = gtestLogOutput.str(); | |
| ASSERT_THAT(err, ::testing::HasSubstr("warn: unknown entry found in " | |
| "checkpoint: Section1.Reals fourth 1e+10\n")); | |
| ASSERT_THAT(err, ::testing::HasSubstr("warn: unknown entry found in " | |
| "checkpoint: Section1.Reals second 1.345\n")); | |
| } | |
| } | |
| /** | |
| * Test serialization followed by unserialization, using SERIALIZE_SCALAR and | |
| * UNSERIALIZE_SCALAR. | |
| */ | |
| TEST_F(SerializeFixture, SerializeScalar) | |
| { | |
| const int expected_integer = 5; | |
| const double expected_real = 3.7; | |
| const bool expected_boolean = true; | |
| const std::string expected_str = "string test"; | |
| // Serialization | |
| { | |
| const int integer = expected_integer; | |
| const double real = expected_real; | |
| const bool boolean = expected_boolean; | |
| const std::string str = expected_str; | |
| std::ofstream cp(getCptPath()); | |
| Serializable::ScopedCheckpointSection scs(cp, "Section1"); | |
| std::string expected = "\n[Section1]\n"; | |
| SERIALIZE_SCALAR(integer); | |
| expected += "integer=5\n"; | |
| ASSERT_EQ(getContents(cp, getCptPath()), expected); | |
| SERIALIZE_SCALAR(real); | |
| expected += "real=3.7\n"; | |
| ASSERT_EQ(getContents(cp, getCptPath()), expected); | |
| SERIALIZE_SCALAR(boolean); | |
| expected += "boolean=true\n"; | |
| ASSERT_EQ(getContents(cp, getCptPath()), expected); | |
| SERIALIZE_SCALAR(str); | |
| expected += "str=string test\n"; | |
| ASSERT_EQ(getContents(cp, getCptPath()), expected); | |
| } | |
| // Unserialization | |
| { | |
| CheckpointIn cp(getDirName()); | |
| int integer; | |
| double real; | |
| bool boolean; | |
| std::string str; | |
| Serializable::ScopedCheckpointSection scs(cp, "Section1"); | |
| UNSERIALIZE_SCALAR(integer); | |
| ASSERT_EQ(integer, expected_integer); | |
| UNSERIALIZE_SCALAR(real); | |
| ASSERT_EQ(real, expected_real); | |
| UNSERIALIZE_SCALAR(boolean); | |
| ASSERT_EQ(boolean, expected_boolean); | |
| UNSERIALIZE_SCALAR(str); | |
| ASSERT_EQ(str, expected_str); | |
| } | |
| } | |
| /** Test optional parameters with UNSERIALIZE_OPT_SCALAR. */ | |
| TEST_F(SerializeFixture, UnserializeOptScalar) | |
| { | |
| const double expected_real = 3.7; | |
| const std::string expected_str = "string test"; | |
| // Serialization | |
| { | |
| const double real = expected_real; | |
| const std::string str = expected_str; | |
| std::ofstream cp(getCptPath()); | |
| Serializable::ScopedCheckpointSection scs(cp, "Section1"); | |
| SERIALIZE_SCALAR(real); | |
| SERIALIZE_SCALAR(str); | |
| } | |
| // Unserialization | |
| { | |
| CheckpointIn cp(getDirName()); | |
| int integer; | |
| double real; | |
| bool boolean; | |
| std::string str; | |
| Serializable::ScopedCheckpointSection scs(cp, "Section1"); | |
| // Optional without warning | |
| ASSERT_FALSE(UNSERIALIZE_OPT_SCALAR(integer)); | |
| ASSERT_TRUE(UNSERIALIZE_OPT_SCALAR(real)); | |
| ASSERT_EQ(real, expected_real); | |
| // Optional with default request for warning | |
| ASSERT_FALSE(UNSERIALIZE_OPT_SCALAR(boolean)); | |
| ASSERT_TRUE(UNSERIALIZE_OPT_SCALAR(str)); | |
| ASSERT_EQ(str, expected_str); | |
| } | |
| } | |
| /** | |
| * Test serialization followed by unserialization, using SERIALIZE_ENUM and | |
| * UNSERIALIZE_ENUM. | |
| */ | |
| TEST_F(SerializeFixture, SerializeEnum) | |
| { | |
| enum Number | |
| { | |
| ZERO, | |
| TEN=10, | |
| THIRTY_TWO=32 | |
| }; | |
| const Number expected_val = ZERO; | |
| const Number expected_val_2 = THIRTY_TWO; | |
| // Serialization | |
| { | |
| const Number zero = expected_val; | |
| const Number thirty_two = expected_val_2; | |
| std::ofstream cp(getCptPath()); | |
| Serializable::ScopedCheckpointSection scs(cp, "Section1"); | |
| std::string expected = "\n[Section1]\n"; | |
| SERIALIZE_ENUM(zero); | |
| expected += "zero=0\n"; | |
| ASSERT_EQ(getContents(cp, getCptPath()), expected); | |
| SERIALIZE_ENUM(thirty_two); | |
| expected += "thirty_two=32\n"; | |
| ASSERT_EQ(getContents(cp, getCptPath()), expected); | |
| } | |
| // Unserialization | |
| { | |
| CheckpointIn cp(getDirName()); | |
| Number zero; | |
| Number thirty_two; | |
| Serializable::ScopedCheckpointSection scs(cp, "Section1"); | |
| UNSERIALIZE_ENUM(zero); | |
| ASSERT_EQ(zero, expected_val); | |
| UNSERIALIZE_ENUM(thirty_two); | |
| ASSERT_EQ(thirty_two, expected_val_2); | |
| } | |
| } | |
| /** Test SERIALIZE_ARRAY and UNSERIALIZE_ARRAY. */ | |
| TEST_F(SerializeFixture, SerializeArray) | |
| { | |
| std::array<double, 4> expected_real = {0.1, 1.345, 892.72, 1e+10}; | |
| // Serialization | |
| { | |
| const int integer[] = {5, 10, 15}; | |
| const double *real = expected_real.data(); | |
| std::ofstream cp(getCptPath()); | |
| Serializable::ScopedCheckpointSection scs(cp, "Section1"); | |
| std::string expected = "\n[Section1]\n"; | |
| SERIALIZE_ARRAY(integer, 3); | |
| expected += "integer=5 10 15\n"; | |
| ASSERT_EQ(getContents(cp, getCptPath()), expected); | |
| SERIALIZE_ARRAY(real, expected_real.size()); | |
| expected += "real=0.1 1.345 892.72 1e+10\n"; | |
| ASSERT_EQ(getContents(cp, getCptPath()), expected); | |
| } | |
| // Unserialization | |
| { | |
| CheckpointIn cp(getDirName()); | |
| int integer[3]; | |
| std::array<double, 4> real_array; | |
| double *real = real_array.data(); | |
| Serializable::ScopedCheckpointSection scs(cp, "Section1"); | |
| UNSERIALIZE_ARRAY(integer, 3); | |
| ASSERT_THAT(integer, testing::ElementsAre(5, 10, 15)); | |
| UNSERIALIZE_ARRAY(real, expected_real.size()); | |
| ASSERT_EQ(real_array, expected_real); | |
| } | |
| } | |
| /** Test SERIALIZE_CONTAINER and UNSERIALIZE_CONTAINER. */ | |
| TEST_F(SerializeFixture, SerializeContainer) | |
| { | |
| std::list<bool> expected_boolean = {true, false}; | |
| std::vector<std::string> expected_str = {"a", "string", "test"}; | |
| std::set<uint64_t> expected_uint64 = {12751928501, 13, 111111}; | |
| std::deque<uint8_t> expected_uint8 = {17, 42, 255}; | |
| // Serialization | |
| { | |
| const std::list<bool> boolean = expected_boolean; | |
| const std::vector<std::string> str = expected_str; | |
| const std::set<uint64_t> uint64 = expected_uint64; | |
| const std::deque<uint8_t> uint8 = expected_uint8; | |
| std::ofstream cp(getCptPath()); | |
| Serializable::ScopedCheckpointSection scs(cp, "Section1"); | |
| std::string expected = "\n[Section1]\n"; | |
| SERIALIZE_CONTAINER(boolean); | |
| expected += "boolean=true false\n"; | |
| ASSERT_EQ(getContents(cp, getCptPath()), expected); | |
| SERIALIZE_CONTAINER(str); | |
| expected += "str=a string test\n"; | |
| ASSERT_EQ(getContents(cp, getCptPath()), expected); | |
| SERIALIZE_CONTAINER(uint64); | |
| expected += "uint64=13 111111 12751928501\n"; | |
| ASSERT_EQ(getContents(cp, getCptPath()), expected); | |
| SERIALIZE_CONTAINER(uint8); | |
| expected += "uint8=17 42 255\n"; | |
| ASSERT_EQ(getContents(cp, getCptPath()), expected); | |
| } | |
| // Unserialization | |
| { | |
| CheckpointIn cp(getDirName()); | |
| std::list<bool> boolean; | |
| std::vector<std::string> str; | |
| std::set<uint64_t> uint64; | |
| std::deque<uint8_t> uint8; | |
| Serializable::ScopedCheckpointSection scs(cp, "Section1"); | |
| UNSERIALIZE_CONTAINER(boolean); | |
| ASSERT_EQ(boolean, expected_boolean); | |
| UNSERIALIZE_CONTAINER(str); | |
| ASSERT_EQ(str, expected_str); | |
| UNSERIALIZE_CONTAINER(uint64); | |
| ASSERT_EQ(uint64, expected_uint64); | |
| UNSERIALIZE_CONTAINER(uint8); | |
| ASSERT_EQ(uint8, expected_uint8); | |
| } | |
| } | |
| /** Test SERIALIZE_MAPPING and UNSERIALIZE_MAPPING with all keys. */ | |
| TEST_F(SerializeFixture, SerializeMapping) | |
| { | |
| const int expected_integers[] = {10, 32, 100}; | |
| std::array<double, 4> expected_reals = {0.1, 1.345, 892.72, 1e+10}; | |
| const char* const names_ints[] = {"ten", "thirty-two", "one hundred"}; | |
| const char* const names_reals[] = {"first", "second", "third", "fourth"}; | |
| // Serialization | |
| { | |
| const int *integers = expected_integers; | |
| const double *reals = expected_reals.data(); | |
| std::ofstream cp(getCptPath()); | |
| Serializable::ScopedCheckpointSection scs(cp, "Section1"); | |
| std::string expected = "\n[Section1]\n"; | |
| SERIALIZE_MAPPING(integers, names_ints, 3); | |
| expected += "\n[Section1.integers]\nten=10\nthirty-two=32\n" | |
| "one hundred=100\n"; | |
| ASSERT_EQ(getContents(cp, getCptPath()), expected); | |
| SERIALIZE_MAPPING(reals, names_reals, expected_reals.size()); | |
| expected += "\n[Section1.reals]\nfirst=0.1\nsecond=1.345\n" | |
| "third=892.72\nfourth=1e+10\n"; | |
| ASSERT_EQ(getContents(cp, getCptPath()), expected); | |
| } | |
| // Unserialization | |
| { | |
| CheckpointIn cp(getDirName()); | |
| int integers[3]; | |
| double reals[4]; | |
| Serializable::ScopedCheckpointSection scs(cp, "Section1"); | |
| UNSERIALIZE_MAPPING(integers, names_ints, 3); | |
| ASSERT_THAT(integers, testing::ElementsAre(10, 32, 100)); | |
| UNSERIALIZE_MAPPING(reals, names_reals, expected_reals.size()); | |
| ASSERT_THAT(reals, testing::ElementsAre(0.1, 1.345, 892.72, 1e+10)); | |
| } | |
| } |