test: add test for carton binstore
- rename serialize namespace to serdes. - fix some compile issue. - add test for carton binstore
This commit is contained in:
@@ -41,7 +41,7 @@ PRIVATE
|
|||||||
yycc/carton/binstore/types.cpp
|
yycc/carton/binstore/types.cpp
|
||||||
yycc/carton/binstore/setting.cpp
|
yycc/carton/binstore/setting.cpp
|
||||||
yycc/carton/binstore/configuration.cpp
|
yycc/carton/binstore/configuration.cpp
|
||||||
#yycc/carton/binstore/storage.cpp
|
yycc/carton/binstore/storage.cpp
|
||||||
yycc/carton/lexer61.cpp
|
yycc/carton/lexer61.cpp
|
||||||
)
|
)
|
||||||
target_sources(YYCCommonplace
|
target_sources(YYCCommonplace
|
||||||
@@ -108,10 +108,10 @@ FILES
|
|||||||
yycc/carton/clap/resolver.hpp
|
yycc/carton/clap/resolver.hpp
|
||||||
yycc/carton/binstore.hpp
|
yycc/carton/binstore.hpp
|
||||||
yycc/carton/binstore/types.hpp
|
yycc/carton/binstore/types.hpp
|
||||||
yycc/carton/binstore/serializer.hpp
|
yycc/carton/binstore/serdes.hpp
|
||||||
yycc/carton/binstore/setting.hpp
|
yycc/carton/binstore/setting.hpp
|
||||||
yycc/carton/binstore/configuration.hpp
|
yycc/carton/binstore/configuration.hpp
|
||||||
#yycc/carton/binstore/storage.hpp
|
yycc/carton/binstore/storage.hpp
|
||||||
yycc/carton/lexer61.hpp
|
yycc/carton/lexer61.hpp
|
||||||
yycc/carton/fft.hpp
|
yycc/carton/fft.hpp
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "binstore/types.hpp"
|
||||||
|
#include "binstore/serdes.hpp"
|
||||||
|
#include "binstore/setting.hpp"
|
||||||
|
#include "binstore/configuration.hpp"
|
||||||
|
#include "binstore/storage.hpp"
|
||||||
|
|
||||||
namespace yycc::carton::binstore {
|
namespace yycc::carton::binstore {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,11 +5,13 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <concepts>
|
#include <concepts>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <cmath>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#define NS_YYCC_BINSTORE_TYPES ::yycc::carton::binstore::types
|
#define NS_YYCC_BINSTORE_TYPES ::yycc::carton::binstore::types
|
||||||
|
|
||||||
namespace yycc::carton::binstore::serializer {
|
namespace yycc::carton::binstore::serdes {
|
||||||
|
|
||||||
// TODO: Support numeric list and string list SerDes.
|
// TODO: Support numeric list and string list SerDes.
|
||||||
|
|
||||||
@@ -120,6 +122,33 @@ namespace yycc::carton::binstore::serializer {
|
|||||||
NS_YYCC_BINSTORE_TYPES::ByteArray reset() const { return this->serialize(TDefault).value(); }
|
NS_YYCC_BINSTORE_TYPES::ByteArray reset() const { return this->serialize(TDefault).value(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T, auto TDefault = static_cast<T>(0)>
|
||||||
|
requires std::is_enum_v<T>
|
||||||
|
struct EnumSerDes {
|
||||||
|
EnumSerDes() = default;
|
||||||
|
YYCC_DEFAULT_COPY_MOVE(EnumSerDes)
|
||||||
|
|
||||||
|
using UnderlyingType = std::underlying_type_t<T>;
|
||||||
|
using ValueType = T;
|
||||||
|
|
||||||
|
std::optional<NS_YYCC_BINSTORE_TYPES::ByteArray> serialize(const ValueType& value) const {
|
||||||
|
return inner.serialize(static_cast<UnderlyingType>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<ValueType> deserialize(const NS_YYCC_BINSTORE_TYPES::ByteArray& ba) const {
|
||||||
|
return inner.deserialize(ba).transform([](auto v) { return static_cast<ValueType>(v); });
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_YYCC_BINSTORE_TYPES::ByteArray reset() const { return inner.reset(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
IntegralSerDes<UnderlyingType,
|
||||||
|
std::numeric_limits<UnderlyingType>::min(),
|
||||||
|
std::numeric_limits<UnderlyingType>::max(),
|
||||||
|
static_cast<UnderlyingType>(TDefault)>
|
||||||
|
inner;
|
||||||
|
};
|
||||||
|
|
||||||
template<bool TDefault = false>
|
template<bool TDefault = false>
|
||||||
struct BoolSerDes {
|
struct BoolSerDes {
|
||||||
BoolSerDes() = default;
|
BoolSerDes() = default;
|
||||||
@@ -195,4 +224,4 @@ namespace yycc::carton::binstore::serializer {
|
|||||||
NS_YYCC_BINSTORE_TYPES::ByteArray reset() const { return this->serialize(u8"").value(); }
|
NS_YYCC_BINSTORE_TYPES::ByteArray reset() const { return this->serialize(u8"").value(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace yycc::carton::binstore::serializer
|
} // namespace yycc::carton::binstore::serdes
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#define TYPES ::yycc::carton::binstore::types
|
#define TYPES ::yycc::carton::binstore::types
|
||||||
#define CFG ::yycc::carton::binstore::configuration
|
#define CFG ::yycc::carton::binstore::configuration
|
||||||
#define SERDES ::yycc::carton::binstore::serializer
|
#define SERDES ::yycc::carton::binstore::serdes
|
||||||
#define SAFECAST ::yycc::num::safe_cast
|
#define SAFECAST ::yycc::num::safe_cast
|
||||||
|
|
||||||
namespace yycc::carton::binstore::storage {
|
namespace yycc::carton::binstore::storage {
|
||||||
@@ -129,7 +129,7 @@ namespace yycc::carton::binstore::storage {
|
|||||||
|
|
||||||
TYPES::BinstoreResult<void> Storage::load(std::istream& s, LoadStrategy strategy) {
|
TYPES::BinstoreResult<void> Storage::load(std::istream& s, LoadStrategy strategy) {
|
||||||
// Before loading, we need clear all stored raw data first.
|
// Before loading, we need clear all stored raw data first.
|
||||||
this->raws.clear();
|
this->clear();
|
||||||
|
|
||||||
// Read identifier
|
// Read identifier
|
||||||
TYPES::VersionIdentifier version;
|
TYPES::VersionIdentifier version;
|
||||||
@@ -171,7 +171,7 @@ namespace yycc::carton::binstore::storage {
|
|||||||
auto token = token_finder.value();
|
auto token = token_finder.value();
|
||||||
|
|
||||||
// If there is duplicated entry, report error
|
// If there is duplicated entry, report error
|
||||||
if (this->raws.contains(token)) std::unexpected(TYPES::BinstoreError::DuplicatedAssign);
|
if (this->raws.contains(token)) return std::unexpected(TYPES::BinstoreError::DuplicatedAssign);
|
||||||
// Otherwise insert it
|
// Otherwise insert it
|
||||||
this->raws.emplace(token, std::move(ba));
|
this->raws.emplace(token, std::move(ba));
|
||||||
}
|
}
|
||||||
@@ -212,6 +212,10 @@ namespace yycc::carton::binstore::storage {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Storage::clear() {
|
||||||
|
this->raws.clear();
|
||||||
|
}
|
||||||
|
|
||||||
bool Storage::has_setting(TYPES::Token token) const {
|
bool Storage::has_setting(TYPES::Token token) const {
|
||||||
return this->cfg.get_settings().has_setting(token);
|
return this->cfg.get_settings().has_setting(token);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#include "../../macro/class_copy_move.hpp"
|
#include "../../macro/class_copy_move.hpp"
|
||||||
#include "types.hpp"
|
#include "types.hpp"
|
||||||
#include "configuration.hpp"
|
#include "configuration.hpp"
|
||||||
#include "serializer.hpp"
|
#include "serdes.hpp"
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
#define NS_YYCC_BINSTORE_TYPES ::yycc::carton::binstore::types
|
#define NS_YYCC_BINSTORE_TYPES ::yycc::carton::binstore::types
|
||||||
#define NS_YYCC_BINSTORE_CFG ::yycc::carton::binstore::configuration
|
#define NS_YYCC_BINSTORE_CFG ::yycc::carton::binstore::configuration
|
||||||
#define NS_YYCC_BINSTORE_SERDES ::yycc::carton::binstore::serializer
|
#define NS_YYCC_BINSTORE_SERDES ::yycc::carton::binstore::serdes
|
||||||
|
|
||||||
namespace yycc::carton::binstore::storage {
|
namespace yycc::carton::binstore::storage {
|
||||||
|
|
||||||
@@ -61,10 +61,15 @@ namespace yycc::carton::binstore::storage {
|
|||||||
YYCC_DEFAULT_COPY_MOVE(Storage)
|
YYCC_DEFAULT_COPY_MOVE(Storage)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NS_YYCC_BINSTORE_TYPES::BinstoreResult<void> load_from_file(const std::filesystem::path& fpath, LoadStrategy strategy);
|
NS_YYCC_BINSTORE_TYPES::BinstoreResult<void> load_from_file(const std::filesystem::path& fpath, LoadStrategy strategy = LoadStrategy::MigrateOld);
|
||||||
NS_YYCC_BINSTORE_TYPES::BinstoreResult<void> load(std::istream& s, LoadStrategy strategy);
|
NS_YYCC_BINSTORE_TYPES::BinstoreResult<void> load(std::istream& s, LoadStrategy strategy = LoadStrategy::MigrateOld);
|
||||||
NS_YYCC_BINSTORE_TYPES::BinstoreResult<void> save_into_file(const std::filesystem::path& fpath);
|
NS_YYCC_BINSTORE_TYPES::BinstoreResult<void> save_into_file(const std::filesystem::path& fpath);
|
||||||
NS_YYCC_BINSTORE_TYPES::BinstoreResult<void> save(std::ostream& s);
|
NS_YYCC_BINSTORE_TYPES::BinstoreResult<void> save(std::ostream& s);
|
||||||
|
/**
|
||||||
|
* @brief Clear all raw data saved in internal cache.
|
||||||
|
* @details This will cause every setting was set in default value when user fetching them.
|
||||||
|
*/
|
||||||
|
void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
@@ -129,7 +134,7 @@ namespace yycc::carton::binstore::storage {
|
|||||||
// Get raw value.
|
// Get raw value.
|
||||||
const auto& ba = this->get_raw_value(token);
|
const auto& ba = this->get_raw_value(token);
|
||||||
// Try to deserialize it.
|
// Try to deserialize it.
|
||||||
auto value = serdes.deserialize(raw_value);
|
auto value = serdes.deserialize(ba);
|
||||||
// If the result is okey, return it.
|
// If the result is okey, return it.
|
||||||
if (value.has_value()) {
|
if (value.has_value()) {
|
||||||
return value.value();
|
return value.value();
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <concepts>
|
#include <concepts>
|
||||||
|
#include <stdexcept>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#define NS_YYCC_NUM_PARSE ::yycc::num::parse
|
#define NS_YYCC_NUM_PARSE ::yycc::num::parse
|
||||||
|
|||||||
@@ -0,0 +1,385 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <yycc.hpp>
|
||||||
|
#include <yycc/carton/binstore.hpp>
|
||||||
|
#include <yycc/prelude.hpp>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#define BINSTORE ::yycc::carton::binstore
|
||||||
|
|
||||||
|
namespace yycctest::carton::binstore {
|
||||||
|
|
||||||
|
using Token = BINSTORE::types::Token;
|
||||||
|
using VersionIdentifier = BINSTORE::types::VersionIdentifier;
|
||||||
|
using Setting = BINSTORE::setting::Setting;
|
||||||
|
using SettingCollection = BINSTORE::setting::SettingCollection;
|
||||||
|
using Configuration = BINSTORE::configuration::Configuration;
|
||||||
|
using Storage = BINSTORE::storage::Storage;
|
||||||
|
using LoadStrategy = BINSTORE::storage::LoadStrategy;
|
||||||
|
namespace serdes = BINSTORE::serdes;
|
||||||
|
|
||||||
|
#pragma region Binstore Builder
|
||||||
|
|
||||||
|
// YYC MARK:
|
||||||
|
// Due to the same reason like clap,
|
||||||
|
// I rename them with new test suit name.
|
||||||
|
|
||||||
|
TEST(CartonBinstoreSetting, BadSetting) {
|
||||||
|
// Test that we can create settings with names
|
||||||
|
EXPECT_NO_THROW(Setting setting(u8"test-setting"));
|
||||||
|
// Test that we cannot create settings with empty names
|
||||||
|
EXPECT_ANY_THROW(Setting setting(u8""));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CartonBinstoreSetting, BadSettings) {
|
||||||
|
// Test that duplicate names are not allowed
|
||||||
|
auto settings = SettingCollection();
|
||||||
|
auto token1 = settings.add_setting(Setting(u8"setting1"));
|
||||||
|
EXPECT_ANY_THROW(settings.add_setting(Setting(u8"setting1")));
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region Binstore Operations
|
||||||
|
|
||||||
|
enum class TestEnum : int8_t { Test1, Test2, Test3 };
|
||||||
|
|
||||||
|
class CartonBinstore : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
CartonBinstore() :
|
||||||
|
// YYC MARK:
|
||||||
|
// Due to the same reason like clap, I need initialize a blank configuration.
|
||||||
|
configuration(0, SettingCollection()) {
|
||||||
|
// Create settings
|
||||||
|
auto settings = SettingCollection();
|
||||||
|
int_setting = settings.add_setting(Setting(u8"int-setting"));
|
||||||
|
float_setting = settings.add_setting(Setting(u8"float-setting"));
|
||||||
|
string_setting = settings.add_setting(Setting(u8"string-setting"));
|
||||||
|
bool_setting = settings.add_setting(Setting(u8"bool-setting"));
|
||||||
|
clamped_float_setting = settings.add_setting(Setting(u8"clamped-float-setting"));
|
||||||
|
enum_setting = settings.add_setting(Setting(u8"enum-setting"));
|
||||||
|
|
||||||
|
// Create configuration
|
||||||
|
configuration = Configuration(0, std::move(settings));
|
||||||
|
}
|
||||||
|
~CartonBinstore() override = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Build Storage with given Configuration.
|
||||||
|
* @remarks The Configuration passed to Storage is a copy of this class member.
|
||||||
|
* @return Built Storage.
|
||||||
|
*/
|
||||||
|
Storage build_storage() const { return Storage(Configuration(this->configuration)); }
|
||||||
|
|
||||||
|
// Tokens for accessing settings
|
||||||
|
Token int_setting;
|
||||||
|
using IntSettingSerDes = serdes::IntegralSerDes<i32>;
|
||||||
|
Token float_setting;
|
||||||
|
using FloatSettingSerDes = serdes::FloatingPointSerDes<float>;
|
||||||
|
Token string_setting;
|
||||||
|
using StringSettingSerDes = serdes::StringSerDes;
|
||||||
|
Token bool_setting;
|
||||||
|
using BoolSettingSerDes = serdes::BoolSerDes<>;
|
||||||
|
Token clamped_float_setting;
|
||||||
|
using ClampedFloatSettingSerDes = serdes::FloatingPointSerDes<float, -1.0f, 1.0f>;
|
||||||
|
Token enum_setting;
|
||||||
|
using EnumSettingSerDes = serdes::EnumSerDes<TestEnum, TestEnum::Test1>;
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
Configuration configuration;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(CartonBinstore, Configuration) {
|
||||||
|
// Test version
|
||||||
|
EXPECT_EQ(configuration.get_version(), 0);
|
||||||
|
|
||||||
|
// Test settings access
|
||||||
|
const auto& settings = configuration.get_settings();
|
||||||
|
EXPECT_EQ(settings.length(), 6);
|
||||||
|
EXPECT_TRUE(settings.has_setting(int_setting));
|
||||||
|
EXPECT_TRUE(settings.has_setting(float_setting));
|
||||||
|
EXPECT_TRUE(settings.has_setting(string_setting));
|
||||||
|
EXPECT_TRUE(settings.has_setting(bool_setting));
|
||||||
|
EXPECT_TRUE(settings.has_setting(clamped_float_setting));
|
||||||
|
EXPECT_TRUE(settings.has_setting(enum_setting));
|
||||||
|
EXPECT_NO_THROW(settings.get_setting(int_setting));
|
||||||
|
EXPECT_NO_THROW(settings.get_setting(float_setting));
|
||||||
|
EXPECT_NO_THROW(settings.get_setting(string_setting));
|
||||||
|
EXPECT_NO_THROW(settings.get_setting(bool_setting));
|
||||||
|
EXPECT_NO_THROW(settings.get_setting(clamped_float_setting));
|
||||||
|
EXPECT_NO_THROW(settings.get_setting(enum_setting));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CartonBinstore, StorageBasicOperations) {
|
||||||
|
auto storage = build_storage();
|
||||||
|
|
||||||
|
// Test that we can reset values to defaults
|
||||||
|
EXPECT_NO_THROW(storage.reset_value<IntSettingSerDes>(int_setting));
|
||||||
|
EXPECT_NO_THROW(storage.reset_value<FloatSettingSerDes>(float_setting));
|
||||||
|
EXPECT_NO_THROW(storage.reset_value<StringSettingSerDes>(string_setting));
|
||||||
|
EXPECT_NO_THROW(storage.reset_value<BoolSettingSerDes>(bool_setting));
|
||||||
|
EXPECT_NO_THROW(storage.reset_value<ClampedFloatSettingSerDes>(clamped_float_setting));
|
||||||
|
EXPECT_NO_THROW(storage.reset_value<EnumSettingSerDes>(enum_setting));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CartonBinstore, StorageSetValueGetValue) {
|
||||||
|
auto storage = build_storage();
|
||||||
|
|
||||||
|
// Test setting and getting values
|
||||||
|
// Integer setting
|
||||||
|
{
|
||||||
|
i32 test_value = 114;
|
||||||
|
bool set_success = storage.set_value<IntSettingSerDes>(int_setting, test_value);
|
||||||
|
EXPECT_TRUE(set_success);
|
||||||
|
|
||||||
|
auto retrieved_value = storage.get_value<IntSettingSerDes>(int_setting);
|
||||||
|
EXPECT_EQ(retrieved_value, test_value);
|
||||||
|
}
|
||||||
|
// Float setting
|
||||||
|
{
|
||||||
|
float test_value = 2.0f;
|
||||||
|
bool set_success = storage.set_value<FloatSettingSerDes>(float_setting, test_value);
|
||||||
|
EXPECT_TRUE(set_success);
|
||||||
|
|
||||||
|
auto retrieved_value = storage.get_value<FloatSettingSerDes>(float_setting);
|
||||||
|
EXPECT_EQ(retrieved_value, test_value);
|
||||||
|
}
|
||||||
|
// String setting
|
||||||
|
{
|
||||||
|
std::u8string test_value = u8"test";
|
||||||
|
bool set_success = storage.set_value<StringSettingSerDes>(string_setting, test_value);
|
||||||
|
EXPECT_TRUE(set_success);
|
||||||
|
|
||||||
|
auto retrieved_value = storage.get_value<StringSettingSerDes>(string_setting);
|
||||||
|
EXPECT_EQ(retrieved_value, test_value);
|
||||||
|
}
|
||||||
|
// Boolean setting
|
||||||
|
{
|
||||||
|
bool test_value = true;
|
||||||
|
bool set_success = storage.set_value<BoolSettingSerDes>(bool_setting, test_value);
|
||||||
|
EXPECT_TRUE(set_success);
|
||||||
|
|
||||||
|
auto retrieved_value = storage.get_value<BoolSettingSerDes>(bool_setting);
|
||||||
|
EXPECT_EQ(retrieved_value, test_value);
|
||||||
|
}
|
||||||
|
// Clamped float setting (within range)
|
||||||
|
{
|
||||||
|
float test_value = 0.5f;
|
||||||
|
bool set_success = storage.set_value<ClampedFloatSettingSerDes>(clamped_float_setting, test_value);
|
||||||
|
EXPECT_TRUE(set_success);
|
||||||
|
|
||||||
|
auto retrieved_value = storage.get_value<ClampedFloatSettingSerDes>(clamped_float_setting);
|
||||||
|
EXPECT_FLOAT_EQ(retrieved_value, test_value);
|
||||||
|
}
|
||||||
|
// Enum setting
|
||||||
|
{
|
||||||
|
TestEnum test_value = TestEnum::Test2;
|
||||||
|
bool set_success = storage.set_value<EnumSettingSerDes>(enum_setting, test_value);
|
||||||
|
EXPECT_TRUE(set_success);
|
||||||
|
|
||||||
|
auto retrieved_value = storage.get_value<EnumSettingSerDes>(enum_setting);
|
||||||
|
EXPECT_EQ(retrieved_value, test_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CartonBinstore, StorageConstraintHandling) {
|
||||||
|
auto storage = build_storage();
|
||||||
|
|
||||||
|
// Test clamped float setting with out-of-range value
|
||||||
|
// Should fail serialization and be reset to default
|
||||||
|
float out_of_range_value = 2.0f; // Outside [-1.0f, 1.0f]
|
||||||
|
bool set_success = storage.set_value<ClampedFloatSettingSerDes>(clamped_float_setting, out_of_range_value);
|
||||||
|
EXPECT_FALSE(set_success); // Should return false indicating constraint violation
|
||||||
|
|
||||||
|
// Value should be reset to default (0.0f)
|
||||||
|
auto default_value = storage.get_value<ClampedFloatSettingSerDes>(clamped_float_setting);
|
||||||
|
EXPECT_EQ(default_value, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CartonBinstore, StoragePersistence) {
|
||||||
|
// Create storage
|
||||||
|
auto storage = build_storage();
|
||||||
|
|
||||||
|
// Prepare test value
|
||||||
|
static i32 INT_VALUE = 114;
|
||||||
|
static float FLOAT_VALUE = 2.0f;
|
||||||
|
static std::u8string STRING_VALUE = u8"test";
|
||||||
|
static bool BOOL_VALUE = true;
|
||||||
|
static float CLAMPED_FLOAT_VALUE = 0.5f;
|
||||||
|
static TestEnum ENUM_VALUE = TestEnum::Test2;
|
||||||
|
|
||||||
|
// Set settings with given value.
|
||||||
|
{
|
||||||
|
ASSERT_TRUE(storage.set_value<IntSettingSerDes>(int_setting, INT_VALUE));
|
||||||
|
ASSERT_TRUE(storage.set_value<FloatSettingSerDes>(float_setting, FLOAT_VALUE));
|
||||||
|
ASSERT_TRUE(storage.set_value<StringSettingSerDes>(string_setting, STRING_VALUE));
|
||||||
|
ASSERT_TRUE(storage.set_value<BoolSettingSerDes>(bool_setting, BOOL_VALUE));
|
||||||
|
ASSERT_TRUE(storage.set_value<ClampedFloatSettingSerDes>(clamped_float_setting, CLAMPED_FLOAT_VALUE));
|
||||||
|
ASSERT_TRUE(storage.set_value<EnumSettingSerDes>(enum_setting, ENUM_VALUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save it into buffer.
|
||||||
|
// Use stringstream as buffer.
|
||||||
|
std::stringstream ss;
|
||||||
|
ASSERT_TRUE(storage.save(ss).has_value());
|
||||||
|
|
||||||
|
// Clear IO bit flags, not the content.
|
||||||
|
ss.clear();
|
||||||
|
// Clear values
|
||||||
|
storage.clear();
|
||||||
|
|
||||||
|
// Load it into new created storage.
|
||||||
|
ASSERT_TRUE(storage.load(ss, LoadStrategy::OnlyCurrent).has_value());
|
||||||
|
|
||||||
|
// Check loaded settings
|
||||||
|
{
|
||||||
|
auto retrieved_value = storage.get_value<IntSettingSerDes>(int_setting);
|
||||||
|
EXPECT_EQ(retrieved_value, INT_VALUE);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto retrieved_value = storage.get_value<FloatSettingSerDes>(float_setting);
|
||||||
|
EXPECT_EQ(retrieved_value, FLOAT_VALUE);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto retrieved_value = storage.get_value<StringSettingSerDes>(string_setting);
|
||||||
|
EXPECT_EQ(retrieved_value, STRING_VALUE);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto retrieved_value = storage.get_value<BoolSettingSerDes>(bool_setting);
|
||||||
|
EXPECT_EQ(retrieved_value, BOOL_VALUE);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto retrieved_value = storage.get_value<ClampedFloatSettingSerDes>(clamped_float_setting);
|
||||||
|
EXPECT_FLOAT_EQ(retrieved_value, CLAMPED_FLOAT_VALUE);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto retrieved_value = storage.get_value<EnumSettingSerDes>(enum_setting);
|
||||||
|
EXPECT_EQ(retrieved_value, ENUM_VALUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
#pragma region Binstore Version Handling
|
||||||
|
|
||||||
|
class CartonBinstoreVersion : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
CartonBinstoreVersion() {
|
||||||
|
// Create settings
|
||||||
|
auto settings = SettingCollection();
|
||||||
|
setting = settings.add_setting(Setting(u8"int-setting"));
|
||||||
|
}
|
||||||
|
~CartonBinstoreVersion() override = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Build Storage with given Settings.
|
||||||
|
* @param[in] ver Version used by intermediate Configuration.
|
||||||
|
* @remarks The Settings passed to Storage is a copy of this class member.
|
||||||
|
* The intermediate Configuration is eaten by Storage.
|
||||||
|
* @return Built Storage.
|
||||||
|
*/
|
||||||
|
Storage build_storage(VersionIdentifier ver) const {
|
||||||
|
auto cfg = Configuration(ver, SettingCollection(this->settings));
|
||||||
|
return Storage(std::move(cfg));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prepare a stringstream for loading.
|
||||||
|
* @param[in] ss The string stream to be loaded in future.
|
||||||
|
*/
|
||||||
|
void prepare_load(std::stringstream& ss) const {
|
||||||
|
ss.clear();
|
||||||
|
ss.seekg(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tokens for accessing settings
|
||||||
|
Token setting;
|
||||||
|
using SettingSerDes = serdes::IntegralSerDes<i32>;
|
||||||
|
static constexpr i32 SETTING_VALUE = 42;
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
SettingCollection settings;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(CartonBinstoreVersion, LoadStrategy) {
|
||||||
|
// Prepare buffer and essential settings
|
||||||
|
constexpr VersionIdentifier OLD_VERSION = 32;
|
||||||
|
constexpr VersionIdentifier MID_VERSION = 32;
|
||||||
|
constexpr VersionIdentifier NEW_VERSION = 61;
|
||||||
|
|
||||||
|
// Create old, mid, new storage buffer.
|
||||||
|
std::stringstream ss_old, ss_mid, ss_new;
|
||||||
|
auto storage_old = build_storage(OLD_VERSION);
|
||||||
|
auto storage_mid = build_storage(MID_VERSION);
|
||||||
|
auto storage_new = build_storage(NEW_VERSION);
|
||||||
|
{
|
||||||
|
storage_old.set_value<SettingSerDes>(setting, SETTING_VALUE);
|
||||||
|
ASSERT_TRUE(storage_old.save(ss_old).has_value());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
storage_mid.set_value<SettingSerDes>(setting, SETTING_VALUE);
|
||||||
|
ASSERT_TRUE(storage_mid.save(ss_mid).has_value());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
storage_new.set_value<SettingSerDes>(setting, SETTING_VALUE);
|
||||||
|
ASSERT_TRUE(storage_new.save(ss_new).has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to load other configuration by OnlyCurrent strategy
|
||||||
|
{
|
||||||
|
storage_mid.clear();
|
||||||
|
prepare_load(ss_old);
|
||||||
|
ASSERT_FALSE(storage_mid.load(ss_old, LoadStrategy::OnlyCurrent).has_value());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
storage_mid.clear();
|
||||||
|
prepare_load(ss_mid);
|
||||||
|
ASSERT_TRUE(storage_mid.load(ss_mid, LoadStrategy::OnlyCurrent).has_value());
|
||||||
|
EXPECT_EQ(storage_mid.get_value<SettingSerDes>(setting), SETTING_VALUE);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
storage_mid.clear();
|
||||||
|
prepare_load(ss_new);
|
||||||
|
ASSERT_FALSE(storage_mid.load(ss_new, LoadStrategy::OnlyCurrent).has_value());
|
||||||
|
}
|
||||||
|
// Try to load other configuration by MigrateOld strategy
|
||||||
|
{
|
||||||
|
storage_mid.clear();
|
||||||
|
prepare_load(ss_old);
|
||||||
|
ASSERT_TRUE(storage_mid.load(ss_old, LoadStrategy::MigrateOld).has_value());
|
||||||
|
EXPECT_EQ(storage_mid.get_value<SettingSerDes>(setting), SETTING_VALUE);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
storage_mid.clear();
|
||||||
|
prepare_load(ss_mid);
|
||||||
|
ASSERT_TRUE(storage_mid.load(ss_mid, LoadStrategy::MigrateOld).has_value());
|
||||||
|
EXPECT_EQ(storage_mid.get_value<SettingSerDes>(setting), SETTING_VALUE);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
storage_mid.clear();
|
||||||
|
prepare_load(ss_new);
|
||||||
|
ASSERT_FALSE(storage_mid.load(ss_new, LoadStrategy::MigrateOld).has_value());
|
||||||
|
}
|
||||||
|
// Try to load other configuration by AcceptAll strategy
|
||||||
|
{
|
||||||
|
storage_mid.clear();
|
||||||
|
prepare_load(ss_old);
|
||||||
|
ASSERT_TRUE(storage_mid.load(ss_old, LoadStrategy::AcceptAll).has_value());
|
||||||
|
EXPECT_EQ(storage_mid.get_value<SettingSerDes>(setting), SETTING_VALUE);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
storage_mid.clear();
|
||||||
|
prepare_load(ss_mid);
|
||||||
|
ASSERT_TRUE(storage_mid.load(ss_mid, LoadStrategy::AcceptAll).has_value());
|
||||||
|
EXPECT_EQ(storage_mid.get_value<SettingSerDes>(setting), SETTING_VALUE);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
storage_mid.clear();
|
||||||
|
prepare_load(ss_new);
|
||||||
|
ASSERT_TRUE(storage_mid.load(ss_new, LoadStrategy::AcceptAll).has_value());
|
||||||
|
EXPECT_EQ(storage_mid.get_value<SettingSerDes>(setting), SETTING_VALUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma endregion
|
||||||
|
|
||||||
|
} // namespace yycctest::carton::binstore
|
||||||
@@ -22,6 +22,8 @@ namespace yycctest::carton::tabulate {
|
|||||||
|
|
||||||
void expected_print(const std::u8string_view& exp) {
|
void expected_print(const std::u8string_view& exp) {
|
||||||
ss.str("");
|
ss.str("");
|
||||||
|
ss.clear();
|
||||||
|
|
||||||
table.print(ss);
|
table.print(ss);
|
||||||
EXPECT_EQ(REINTERPRET::as_utf8_view(ss.view()), exp);
|
EXPECT_EQ(REINTERPRET::as_utf8_view(ss.view()), exp);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user