Skip to content

Commit

Permalink
feat: Improve Sunshine compatibility (#67)
Browse files Browse the repository at this point in the history
  • Loading branch information
FrogTheFrog authored Jul 19, 2024
1 parent 693fb9f commit d435ad9
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 42 deletions.
2 changes: 1 addition & 1 deletion src/common/file_settings_persistence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace display_device {
return false;
}

std::ranges::copy(data, std::ostreambuf_iterator<char> { stream });
std::copy(std::begin(data), std::end(data), std::ostreambuf_iterator<char> { stream });
return true;
}
catch (const std::exception &error) {
Expand Down
3 changes: 2 additions & 1 deletion src/common/include/display_device/logging.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ namespace display_device {
debug,
info,
warning,
error
error,
fatal
};

/**
Expand Down
72 changes: 34 additions & 38 deletions src/common/logging.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#if !defined(_MSC_VER) && !defined(_POSIX_THREAD_SAFE_FUNCTIONS)
#define _POSIX_THREAD_SAFE_FUNCTIONS // For localtime_r
#endif

// class header include
#include "display_device/logging.h"

Expand All @@ -8,14 +12,30 @@
#include <mutex>

namespace display_device {
namespace {
std::tm
threadSafeLocaltime(const std::time_t &time) {
#if defined(_MSC_VER) // MSVCRT (2005+): std::localtime is threadsafe
const auto tm_ptr { std::localtime(&time) };
#else // POSIX
std::tm buffer;
const auto tm_ptr { localtime_r(&time, &buffer) };
#endif // _MSC_VER
if (tm_ptr) {
return *tm_ptr;
}
return {};
}
} // namespace

Logger &
Logger::get() {
static Logger instance; // GCOVR_EXCL_BR_LINE for some reason...
return instance;
}

void
Logger::setLogLevel(LogLevel log_level) {
Logger::setLogLevel(const LogLevel log_level) {
m_enabled_log_level = log_level;
}

Expand Down Expand Up @@ -44,45 +64,18 @@ namespace display_device {

std::stringstream stream;
{
// Time (limited by GCC 11, so it's not pretty and no timezones are supported...)
// Time (limited by GCC 10, so it's not pretty...)
{
static const auto get_time { []() {
static const auto to_year_month_day { [](const auto &now) {
return std::chrono::year_month_day { std::chrono::time_point_cast<std::chrono::days>(now) };
} };
static const auto to_hour_minute_second { [](const auto &now) {
const auto start_of_day { std::chrono::floor<std::chrono::days>(now) };
const auto time_since_start_of_day { std::chrono::round<std::chrono::seconds>(now - start_of_day) };
return std::chrono::hh_mm_ss { time_since_start_of_day };
} };
static const auto to_milliseconds { [](const auto &now) {
const auto now_ms { std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) };
const auto time_s { std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()) };
return now_ms - time_s;
} };

const auto now { std::chrono::system_clock::now() };
return std::make_tuple(to_year_month_day(now), to_hour_minute_second(now), to_milliseconds(now));
} };

const auto [year_month_day, hh_mm_ss, ms] { get_time() };
const auto old_flags { stream.flags() }; // Save formatting flags so that they can be restored...
const auto now { std::chrono::system_clock::now() };
const auto now_ms { std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) };
const auto now_s { std::chrono::duration_cast<std::chrono::seconds>(now_ms) };

const std::time_t time { std::chrono::system_clock::to_time_t(now) };
const auto localtime { threadSafeLocaltime(time) };
const auto now_decimal_part { now_ms - now_s };

stream << "[";
stream << std::setfill('0') << std::setw(2) << static_cast<int>(year_month_day.year());
stream << "-";
stream << std::setfill('0') << std::setw(2) << static_cast<unsigned>(year_month_day.month());
stream << "-";
stream << std::setfill('0') << std::setw(2) << static_cast<unsigned>(year_month_day.day());
stream << " ";
stream << std::setfill('0') << std::setw(2) << hh_mm_ss.hours().count();
stream << ":";
stream << std::setfill('0') << std::setw(2) << hh_mm_ss.minutes().count();
stream << ":";
stream << std::setfill('0') << std::setw(2) << hh_mm_ss.seconds().count();
stream << ".";
stream << std::setfill('0') << std::setw(3) << ms.count();
stream << "] ";
const auto old_flags { stream.flags() }; // Save formatting flags so that they can be restored...
stream << std::put_time(&localtime, "[%Y-%m-%d %H:%M:%S.") << std::setfill('0') << std::setw(3) << now_decimal_part.count() << "] ";
stream.flags(old_flags);
}

Expand All @@ -103,6 +96,9 @@ namespace display_device {
case LogLevel::error:
stream << "ERROR: ";
break;
case LogLevel::fatal:
stream << "FATAL: ";
break;
}

// Value
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/general/test_file_settings_persistence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ TEST_F_S(Store, FileOverwritten) {

{
std::ofstream file { filepath, std::ios_base::binary };
std::ranges::copy(data1, std::ostreambuf_iterator<char> { file });
std::copy(std::begin(data1), std::end(data1), std::ostreambuf_iterator<char> { file });
}

EXPECT_TRUE(std::filesystem::exists(filepath));
Expand Down Expand Up @@ -92,7 +92,7 @@ TEST_F_S(Load, FileRead) {

{
std::ofstream file { filepath, std::ios_base::binary };
std::ranges::copy(data, std::ostreambuf_iterator<char> { file });
std::copy(std::begin(data), std::end(data), std::ostreambuf_iterator<char> { file });
}

EXPECT_EQ(getImpl(filepath).load(), data);
Expand Down
24 changes: 24 additions & 0 deletions tests/unit/general/test_logging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ TEST_S(LogLevelVerbose) {
EXPECT_EQ(logger.isLogLevelEnabled(level::info), true);
EXPECT_EQ(logger.isLogLevelEnabled(level::warning), true);
EXPECT_EQ(logger.isLogLevelEnabled(level::error), true);
EXPECT_EQ(logger.isLogLevelEnabled(level::fatal), true);
}

TEST_S(LogLevelDebug) {
Expand All @@ -31,6 +32,7 @@ TEST_S(LogLevelDebug) {
EXPECT_EQ(logger.isLogLevelEnabled(level::info), true);
EXPECT_EQ(logger.isLogLevelEnabled(level::warning), true);
EXPECT_EQ(logger.isLogLevelEnabled(level::error), true);
EXPECT_EQ(logger.isLogLevelEnabled(level::fatal), true);
}

TEST_S(LogLevelInfo) {
Expand All @@ -44,6 +46,7 @@ TEST_S(LogLevelInfo) {
EXPECT_EQ(logger.isLogLevelEnabled(level::info), true);
EXPECT_EQ(logger.isLogLevelEnabled(level::warning), true);
EXPECT_EQ(logger.isLogLevelEnabled(level::error), true);
EXPECT_EQ(logger.isLogLevelEnabled(level::fatal), true);
}

TEST_S(LogLevelWarning) {
Expand All @@ -57,6 +60,7 @@ TEST_S(LogLevelWarning) {
EXPECT_EQ(logger.isLogLevelEnabled(level::info), false);
EXPECT_EQ(logger.isLogLevelEnabled(level::warning), true);
EXPECT_EQ(logger.isLogLevelEnabled(level::error), true);
EXPECT_EQ(logger.isLogLevelEnabled(level::fatal), true);
}

TEST_S(LogLevelError) {
Expand All @@ -70,6 +74,21 @@ TEST_S(LogLevelError) {
EXPECT_EQ(logger.isLogLevelEnabled(level::info), false);
EXPECT_EQ(logger.isLogLevelEnabled(level::warning), false);
EXPECT_EQ(logger.isLogLevelEnabled(level::error), true);
EXPECT_EQ(logger.isLogLevelEnabled(level::fatal), true);
}

TEST_S(LogLevelFatal) {
using level = display_device::Logger::LogLevel;
auto &logger { display_device::Logger::get() };

logger.setLogLevel(level::fatal);

EXPECT_EQ(logger.isLogLevelEnabled(level::verbose), false);
EXPECT_EQ(logger.isLogLevelEnabled(level::debug), false);
EXPECT_EQ(logger.isLogLevelEnabled(level::info), false);
EXPECT_EQ(logger.isLogLevelEnabled(level::warning), false);
EXPECT_EQ(logger.isLogLevelEnabled(level::error), false);
EXPECT_EQ(logger.isLogLevelEnabled(level::fatal), true);
}

TEST_S(DefaultLogger) {
Expand All @@ -89,6 +108,7 @@ TEST_S(DefaultLogger) {
EXPECT_TRUE(testRegex(write_and_get_cout(level::info, "Hello World!"), R"(\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3}\] INFO: Hello World!\n)"));
EXPECT_TRUE(testRegex(write_and_get_cout(level::warning, "Hello World!"), R"(\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3}\] WARNING: Hello World!\n)"));
EXPECT_TRUE(testRegex(write_and_get_cout(level::error, "Hello World!"), R"(\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3}\] ERROR: Hello World!\n)"));
EXPECT_TRUE(testRegex(write_and_get_cout(level::fatal, "Hello World!"), R"(\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3}\] FATAL: Hello World!\n)"));
// clang-format on
}

Expand Down Expand Up @@ -122,6 +142,10 @@ TEST_S(CustomCallback) {
logger.write(level::error, "Hello World!");
EXPECT_EQ(output, "4 Hello World!");
EXPECT_TRUE(m_cout_buffer.str().empty());

logger.write(level::fatal, "Hello World!");
EXPECT_EQ(output, "5 Hello World!");
EXPECT_TRUE(m_cout_buffer.str().empty());
}

TEST_S(WriteMethodRespectsLogLevel, DefaultLogger) {
Expand Down

0 comments on commit d435ad9

Please sign in to comment.