add settings class.

This commit is contained in:
amass 2024-01-06 00:06:35 +08:00
parent b8c3ed6b7d
commit 20750d1a80
8 changed files with 392 additions and 0 deletions

View File

@ -31,6 +31,9 @@ add_executable(UnitTest main.cpp
HttpProxy/BoostUrlTest.cpp
Universal/BoostLogTest.cpp
Universal/DateTimeTest.cpp
Universal/MessageManagerTest.cpp
Universal/SingletonTest.cpp
)
target_compile_definitions(UnitTest

View File

@ -0,0 +1,83 @@
#include <BoostLog.h>
#include <DateTime.h>
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_SUITE(DateTimeTest, *boost::unit_test::enabled())
BOOST_AUTO_TEST_CASE(BasicUse) {
std::time_t c_current = std::time(nullptr);
auto c_local = localtime(&c_current);
auto now = DateTime::currentDateTime();
BOOST_CHECK_EQUAL(now.year(), c_local->tm_year + 1900);
BOOST_CHECK_EQUAL(now.month(), c_local->tm_mon + 1);
BOOST_CHECK_EQUAL(now.day(), c_local->tm_mday);
BOOST_CHECK_EQUAL(now.hour(), c_local->tm_hour);
BOOST_CHECK_EQUAL(now.minute(), c_local->tm_min);
BOOST_CHECK_EQUAL(now.second(), c_local->tm_sec);
// std::cout << "now: " << DateTime::toString(std::chrono::system_clock::now()) << std::endl;
// std::cout << "now: " << DateTime::currentDateTime().toString() << std::endl;
auto day = DateTime::makeDateTime(2018, 8, 15, 13, 14, 59);
DateTime r(day);
BOOST_CHECK_EQUAL(r.week(), DateTime::Wednesday);
BOOST_CHECK_EQUAL(DateTime::toString(day), "2018-08-15 13:14:59");
}
BOOST_AUTO_TEST_CASE(IsLeapYearTest) {
BOOST_TEST(DateTime::isLeapYear(2008));
BOOST_TEST(!DateTime::isLeapYear(2100));
}
BOOST_AUTO_TEST_CASE(TomorrowTest) {
DateTime day(2018, 8, 15, 13, 14, 59);
auto t = day.tomorrow();
BOOST_CHECK_EQUAL(t.toString(), "2018-08-16 13:14:59");
day = DateTime(2018, 12, 31, 13, 14, 59);
t = day.tomorrow();
BOOST_CHECK_EQUAL(t.toString(), "2019-01-01 13:14:59");
day = DateTime(2020, 2, 28, 13, 14, 59);
t = day.tomorrow();
BOOST_CHECK_EQUAL(t.toString(), "2020-02-29 13:14:59");
day = DateTime(2021, 2, 28, 13, 14, 59);
t = day.tomorrow();
BOOST_CHECK_EQUAL(t.toString(), "2021-03-01 13:14:59");
day = DateTime(2021, 10, 25, 22, 31, 59);
t = day.tomorrow();
BOOST_CHECK_EQUAL(t.toString(), "2021-10-26 22:31:59");
}
BOOST_AUTO_TEST_CASE(CurrentMSecsSinceEpoch) {
BOOST_CHECK_EQUAL(DateTime::currentMSecsSinceEpoch(),
std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now())
.time_since_epoch()
.count());
}
BOOST_AUTO_TEST_CASE(ParseTimeString) {
auto [hour, minute, second] = DateTime::parseTime("12:14:15");
BOOST_CHECK_EQUAL(hour, 12);
BOOST_CHECK_EQUAL(minute, 14);
BOOST_CHECK_EQUAL(second, 15);
std::tie(hour, minute, second) = DateTime::parseTime("15:12");
BOOST_CHECK_EQUAL(hour, 15);
BOOST_CHECK_EQUAL(minute, 12);
BOOST_CHECK_EQUAL(second, 0);
std::tie(hour, minute, second) = DateTime::parseTime("00:09:07");
BOOST_CHECK_EQUAL(hour, 0);
BOOST_CHECK_EQUAL(minute, 9);
BOOST_CHECK_EQUAL(second, 7);
std::tie(hour, minute, second) = DateTime::parseTime("15:12");
BOOST_CHECK_EQUAL(hour, 15);
BOOST_CHECK_EQUAL(minute, 12);
BOOST_CHECK_EQUAL(second, 0);
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -0,0 +1,187 @@
#include <BoostLog.h>
#include <FunctionTraits.h>
#include <MessageManager.h>
#include <boost/function_types/function_type.hpp>
#include <boost/test/unit_test.hpp>
static int test(int a, int b) {
return a + b;
}
class Test {
public:
int test(int a, int b) {
result = a + b + 3;
return result;
}
int result{0};
};
BOOST_AUTO_TEST_SUITE(MessageManagerTest, *boost::unit_test::enabled())
// returned-function-return-type (* function-name (parameter-list) ) (function-to-return-parameter-list)
BOOST_AUTO_TEST_CASE(FunctionTraitsNormalFunctionTest) {
using namespace std::placeholders;
MessageManager m;
m.registerTopic("123", [](int a) -> void { a = a + 102; });
BOOST_CHECK_EQUAL(m.topicCount<int(int)>("123"), 1);
Test t;
m.registerTopic("123", [&t](int a, int b) { return t.test(a, b); });
BOOST_CHECK_EQUAL(m.topicCount<int(int, int)>("123"), 1);
m.registerTopic("123", std::bind(&Test::test, &t, _1, _2));
BOOST_CHECK_EQUAL(m.topicCount<int(int, int)>("123"), 2);
m.registerTopic("123", &test);
BOOST_CHECK_EQUAL(m.topicCount<int(int, int)>("123"), 3);
m.removeTopic<int(int, int)>("123");
BOOST_CHECK_EQUAL(m.topicCount<int(int, int)>("123"), 0);
m.registerTopic("123", [](const std::string &title) {});
m.registerTopic(
"123", [](int type, const std::string &title, const std::string &message, const std::function<void()> &yes) {});
}
BOOST_AUTO_TEST_CASE(SyncMessage) {
using namespace std::placeholders;
MessageManager manager;
int result1 = 0;
std::thread::id id;
manager.registerTopic("123", [&result1](int a) {
result1 += a;
return a + 102;
});
int result2 = 0;
manager.registerTopic("123", [&result2](const int &a) {
result2 = a + 102;
return result2;
});
manager.sendMessage("123", 5);
BOOST_CHECK_EQUAL(result1, 5);
BOOST_CHECK_EQUAL(result2, 107);
int result3 = 0;
manager.registerTopic("123", [&result3](int a, int b) {
result3 = a + b;
return 0;
});
Test t;
manager.registerTopic("123", std::bind(&Test::test, &t, _1, _2));
manager.sendMessage("123", 12, 13);
BOOST_CHECK_EQUAL(result3, 25);
BOOST_CHECK_EQUAL(t.result, 28);
int result4 = 0;
manager.registerTopic("123", [&result4]() {
result4 = 102;
return result4;
});
manager.sendMessage("123");
BOOST_CHECK_EQUAL(result4, 102);
constexpr auto magic = "MagicString";
std::string result5;
manager.registerTopic("test", [&result5](const std::string &text) { result5 = text; });
// manager.sendMessage<std::string>("test", magic); // 编译不通过
// manager.sendMessage("test", magic); // const char*无法匹配到std::string
// BOOST_CHECK_EQUAL(result5, magic);
// result5.clear();
manager.sendMessage<void(const std::string &), std::string>("test", magic);
BOOST_CHECK_EQUAL(result5, magic);
result5.clear();
manager.sendMessage<void(const std::string &)>("test", std::string(magic));
BOOST_CHECK_EQUAL(result5, magic);
result5.clear();
manager.sendMessage<void(std::string)>("test", magic);
BOOST_CHECK_EQUAL(result5, magic);
result5.clear();
manager.sendMessage("test", std::string(magic));
BOOST_CHECK_EQUAL(result5, magic);
}
BOOST_AUTO_TEST_CASE(SyncMessageWithVoidArg) {
MessageManager manager;
constexpr auto Topic = MessageManager::Message<>("test1");
int result = 0;
manager.registerTopic("test1", [&result]() -> void { result = 250; });
manager.sendMessage("test1");
BOOST_CHECK_EQUAL(result, 250);
result = 0;
manager.sendMessage(Topic);
BOOST_CHECK_EQUAL(result, 250);
}
BOOST_AUTO_TEST_CASE(AsyncMessage) {
int result = 0;
std::thread::id id;
auto test1 = [&result, &id](int a, int b) -> void {
result = a + b;
id = std::this_thread::get_id();
};
MessageManager manager;
manager.registerTopic("test1", test1);
manager.sendAsyncMessage("test1", 2, 6);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
BOOST_CHECK_EQUAL(result, 8);
BOOST_CHECK_NE(std::this_thread::get_id(), id);
constexpr auto magic = "MagicString";
manager.registerTopic("StringCompare", [magic](const std::string &text) { BOOST_CHECK_EQUAL(text, magic); });
{
std::string string(magic);
manager.sendAsyncMessage("StringCompare", string);
}
}
BOOST_AUTO_TEST_CASE(AsyncMessageImplictConversion) {
float result1 = 0;
auto test1 = [&result1](int a, int b) -> void { result1 = a + b; };
float result2 = 0;
auto test2 = [&result2](int a, int b) -> void { result2 = a + b; };
MessageManager manager;
manager.registerTopic("test1", test1);
manager.registerTopic("test2", test2);
manager.sendAsyncMessage<decltype(test1)>("test1", 2.6, 6);
manager.sendAsyncMessage("test2", (int)3.6, 6);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
BOOST_CHECK_EQUAL(result1, 8);
BOOST_CHECK_EQUAL(result2, 9);
}
BOOST_AUTO_TEST_CASE(DefineTopicUseMessage) {
constexpr auto TestTopic1 = MessageManager::Message<int, int>("TestTopic1");
int result1 = 0;
auto test1 = [&result1](int a, int b) -> void { result1 = a + b; };
MessageManager manager;
manager.registerTopic(TestTopic1, test1);
manager.sendMessage(TestTopic1, 2, 3);
BOOST_CHECK_EQUAL(result1, 5);
std::string result2;
constexpr auto TestTopic2 = MessageManager::Message<const std::string &>("TestTopic2");
auto test2 = [&result2](const std::string &text) -> void { result2 = text; };
manager.registerTopic(TestTopic2, test2);
manager.sendMessage(TestTopic2, std::string("hello"));
std::string message("hello");
// manager.sendMessage(TestTopic2, message);
// manager.sendMessage(TestTopic2, "hello");
BOOST_CHECK_EQUAL(result2, "hello");
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -0,0 +1,39 @@
#include "Singleton.h"
#include <boost/test/unit_test.hpp>
class Test {
public:
size_t index;
};
BOOST_AUTO_TEST_CASE(LocalInstance) {
auto test = Amass::Singleton<Test>::instance();
BOOST_TEST(!test);
{
auto local = Amass::Singleton<Test>::instance<Amass::Construct>();
BOOST_TEST(local);
auto refer = Amass::Singleton<Test>::instance();
BOOST_TEST(refer);
}
test = Amass::Singleton<Test>::instance();
BOOST_TEST(!test);
}
BOOST_AUTO_TEST_CASE(GlobalInstance) {
auto test = Amass::Singleton<Test, Amass::GlobalInstance>::instance();
BOOST_TEST(test);
{
auto local = Amass::Singleton<Test, Amass::GlobalInstance>::instance();
BOOST_TEST(local);
auto refer = Amass::Singleton<Test, Amass::GlobalInstance>::instance();
BOOST_TEST(refer);
}
test = Amass::Singleton<Test, Amass::GlobalInstance>::instance();
BOOST_TEST(test);
}

View File

@ -0,0 +1,36 @@
#include "ApplicationSettings.h"
#include "BoostLog.h"
#include <boost/property_tree/ini_parser.hpp>
#include <filesystem>
ApplicationSettings::ApplicationSettings(boost::asio::io_context &ioContext, const std::string &path)
: m_ioContext(ioContext), m_timer(ioContext), m_path(path) {
if (std::filesystem::exists(std::filesystem::path(path))) {
try {
boost::property_tree::read_ini(path, m_ptree);
} catch (const boost::property_tree::ini_parser_error &e) {
LOG(error) << e.what();
}
}
run();
}
void ApplicationSettings::run() {
m_timer.expires_after(std::chrono::seconds(1));
m_timer.async_wait([this](const boost::system::error_code &error) {
if (error) {
LOG(error) << error.message();
return;
}
if (m_needSave) {
try {
std::lock_guard locker(m_mutex);
boost::property_tree::write_ini(m_path, m_ptree);
} catch (const boost::property_tree::ini_parser_error &e) {
LOG(error) << e.what();
}
m_needSave = false;
}
run();
});
}

View File

@ -0,0 +1,38 @@
#ifndef __APPLICATIONSETTINGS_H__
#define __APPLICATIONSETTINGS_H__
#include <boost/asio/io_context.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/property_tree/ptree.hpp>
class ApplicationSettings {
#define BUILD_SETTING_FIELD(Category, Type, Name, DefaultValue) \
inline void set##Name(const Type &value) { \
std::lock_guard locker(m_mutex); \
m_ptree.put(#Category "." #Name, value); \
m_needSave = true; \
} \
inline Type get##Name() const { \
std::lock_guard locker(m_mutex); \
return m_ptree.get<Type>(#Category "." #Name, DefaultValue); \
}
#define BUILD_STATUS(Type, Name, DefaultValue) BUILD_SETTING_FIELD(Status, Type, Name, DefaultValue)
public:
ApplicationSettings(boost::asio::io_context &ioContext, const std::string &path);
protected:
void run();
boost::property_tree::ptree m_ptree;
bool m_needSave = false;
mutable std::mutex m_mutex;
private:
boost::asio::io_context &m_ioContext;
boost::asio::steady_timer m_timer;
std::string m_path;
};
#endif // __APPLICATIONSETTINGS_H__

View File

@ -1,6 +1,7 @@
find_package(Boost REQUIRED COMPONENTS log log_setup program_options)
add_library(Universal
ApplicationSettings.h ApplicationSettings.cpp
BoostLog.h BoostLog.inl BoostLog.cpp
BufferUtility.h BufferUtility.cpp
DateTime.h DateTime.cpp

View File

@ -36,6 +36,11 @@ public:
std::chrono::time_point<std::chrono::system_clock> operator()();
std::string toString(const std::string_view &format = "%F %T") const;
/**
* @brief 2023-10-12 12:10:23 then return 2023-10-13 12:10:23
*
* @return DateTime
*/
DateTime tomorrow();
// Returns the number of milliseconds since 1970-01-01T00:00:00 Universal Coordinated Time. This number is like the