Repository: aosedge/aos_core_lib_cpp
Pull request #310: Add fs and time utils needed by zephyr fs backed logger
Author: login: mlohvynenko
Created: 2025-05-12T09:38:55Z | Merged: 2025-05-14T07:31:26Z



Diff:
diff --git a/include/aos/common/tools/fs.hpp b/include/aos/common/tools/fs.hpp
index 4afcc553f..a47132220 100644
--- a/include/aos/common/tools/fs.hpp
+++ b/include/aos/common/tools/fs.hpp
@@ -225,6 +225,17 @@ Error ReadFile(const String& fileName, Array<uint8_t>& buff);
  */
 Error ReadFileToString(const String& fileName, String& text);
 
+/**
+ * Reads line from file.
+ *
+ * @param fd file descriptor.
+ * @param pos position in the file.
+ * @param line line to read.
+ * @param delimiter line delimiter.
+ * @return Error.
+ */
+Error ReadLine(int fd, size_t pos, String& line, const String& delimiter = "\n\0");
+
 /**
  * Overwrites file with a specified data.
  *
diff --git a/include/aos/common/tools/time.hpp b/include/aos/common/tools/time.hpp
index 5a33f50d9..bdd0ad002 100644
--- a/include/aos/common/tools/time.hpp
+++ b/include/aos/common/tools/time.hpp
@@ -341,6 +341,14 @@ class Time {
         return Time(ts);
     }
 
+    /**
+     * Returns UTC time from string representation.
+     *
+     * @param utcTimeStr UTC time string.
+     * @return RetWithError<Time>.
+     */
+    static RetWithError<Time> UTC(const String& utcTimeStr);
+
     /**
      * Checks whether Time object is default initialized.
      *
@@ -456,6 +464,13 @@ class Time {
         return ErrorEnum::eNone;
     }
 
+    /**
+     * @brief Returns UTC string representation.
+     *
+     * @return StaticString<cTimeStrLen>
+     */
+    RetWithError<StaticString<cTimeStrLen>> ToUTCString() const;
+
     /**
      * Checks whether a current time is less than a specified one.
      *
@@ -504,22 +519,12 @@ class Time {
      */
     friend Log& operator<<(Log& log, const Time& obj)
     {
-        tm                        buf;
-        StaticString<cTimeStrLen> utcTimeStr;
-
-        auto time = gmtime_r(&obj.mTime.tv_sec, &buf);
-        assert(time != nullptr);
-
-        utcTimeStr.Resize(utcTimeStr.MaxSize());
-
-        size_t size = strftime(utcTimeStr.Get(), utcTimeStr.Size(), "%FT%TZ", time);
-        assert(size != 0);
-
-        utcTimeStr.Resize(size - 1);
-
-        log << utcTimeStr;
+        auto [utcTimeStr, err] = obj.ToUTCString();
+        if (!err.IsNone()) {
+            return log << err;
+        }
 
-        return log;
+        return log << utcTimeStr;
     }
 
 private:
diff --git a/src/common/tools/fs.cpp b/src/common/tools/fs.cpp
index 79d6de9c9..761875189 100644
--- a/src/common/tools/fs.cpp
+++ b/src/common/tools/fs.cpp
@@ -393,6 +393,31 @@ Error ReadFileToString(const String& fileName, String& text)
     return text.Resize(buff.Size());
 }
 
+Error ReadLine(int fd, size_t pos, String& line, const String& delimiter)
+{
+    if (lseek(fd, pos, SEEK_SET) < 0) {
+        return Error(errno);
+    }
+
+    line.Resize(line.MaxSize());
+
+    ssize_t bytes = read(fd, line.Get(), line.MaxSize());
+    if (bytes < 0) {
+        return Error(errno);
+    }
+
+    if (auto err = line.Resize(bytes); !err.IsNone()) {
+        return err;
+    }
+
+    auto [eolPos, err] = line.FindAny(0, delimiter);
+    if (!err.IsNone()) {
+        return err;
+    }
+
+    return line.Resize(eolPos);
+}
+
 Error WriteFile(const String& fileName, const Array<uint8_t>& data, uint32_t perm)
 {
     // zephyr doesn't support O_TRUNC flag. This is WA to trunc file if it exists.
diff --git a/src/common/tools/time.cpp b/src/common/tools/time.cpp
index d156a1f86..dba25390c 100644
--- a/src/common/tools/time.cpp
+++ b/src/common/tools/time.cpp
@@ -4,10 +4,153 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
+#if defined(__ZEPHYR__)
+#include <zephyr/sys/timeutil.h>
+#endif
+
 #include "aos/common/tools/time.hpp"
 
 namespace aos {
 
+namespace {
+
+/***********************************************************************************************************************
+ * Constants
+ **********************************************************************************************************************/
+
+constexpr auto cUTCFormat = "%Y-%m-%dT%H:%M:%SZ";
+
+/***********************************************************************************************************************
+ * Static
+ **********************************************************************************************************************/
+
+const char* ConsumeChars(const char* s, char* dest, size_t cnt)
+{
+    if (strnlen(s, cnt) < cnt) {
+        return nullptr;
+    }
+
+    memcpy(dest, s, cnt);
+    dest[cnt] = '\0';
+
+    return s + cnt;
+}
+
+const char* ConsumeChar(const char* s, char ch)
+{
+    if (*s != ch) {
+        return nullptr;
+    }
+
+    return ++s;
+}
+
+const char* ConsumeDate(const char* s, struct tm* tm_time)
+{
+    char year[4 + 1];
+    char month[2 + 1];
+    char day[2 + 1];
+
+    s = ConsumeChars(s, year, 4);
+    if (!s) {
+        return nullptr;
+    }
+
+    s = ConsumeChar(s, '-');
+    if (!s) {
+        return nullptr;
+    }
+
+    s = ConsumeChars(s, month, 2);
+    if (!s) {
+        return nullptr;
+    }
+
+    s = ConsumeChar(s, '-');
+    if (!s) {
+        return nullptr;
+    }
+
+    s = ConsumeChars(s, day, 2);
+    if (!s) {
+        return nullptr;
+    }
+
+    tm_time->tm_year = atoi(year) - 1900;
+    tm_time->tm_mon  = atoi(month) - 1;
+    tm_time->tm_mday = atoi(day);
+
+    return s;
+}
+
+const char* ConsumeTime(const char* s, struct tm* tm_time)
+{
+    char hour[2 + 1];
+    char minute[2 + 1];
+    char second[2 + 1];
+
+    s = ConsumeChars(s, hour, 2);
+    if (!s) {
+        return nullptr;
+    }
+
+    s = ConsumeChar(s, ':');
+    if (!s) {
+        return nullptr;
+    }
+
+    s = ConsumeChars(s, minute, 2);
+    if (!s) {
+        return nullptr;
+    }
+
+    s = ConsumeChar(s, ':');
+    if (!s) {
+        return nullptr;
+    }
+
+    s = ConsumeChars(s, second, 2);
+    if (!s) {
+        return nullptr;
+    }
+
+    tm_time->tm_hour = atoi(hour);
+    tm_time->tm_min  = atoi(minute);
+    tm_time->tm_sec  = atoi(second);
+
+    return s;
+}
+
+Error ParseDateTime(const char* s, const char* format, struct tm* tm_time)
+{
+    if (strcmp(format, cUTCFormat) != 0) {
+        return Error(ErrorEnum::eInvalidArgument, "unsupported format");
+    }
+
+    s = ConsumeDate(s, tm_time);
+    if (!s) {
+        return AOS_ERROR_WRAP(Error(ErrorEnum::eFailed, "failed to parse date"));
+    }
+
+    s = ConsumeChar(s, 'T');
+    if (!s) {
+        return AOS_ERROR_WRAP(Error(ErrorEnum::eFailed, "failed to parse date"));
+    }
+
+    s = ConsumeTime(s, tm_time);
+    if (!s) {
+        return AOS_ERROR_WRAP(Error(ErrorEnum::eFailed, "failed to parse time"));
+    }
+
+    return ErrorEnum::eNone;
+}
+
+} // namespace
+
+/***********************************************************************************************************************
+ * Duration
+ **********************************************************************************************************************/
+
 /***********************************************************************************************************************
  * Public
  **********************************************************************************************************************/
@@ -92,4 +235,52 @@ StaticString<cTimeStrLen> Duration::ToISO8601String() const
     return result;
 }
 
+/***********************************************************************************************************************
+ * Time
+ **********************************************************************************************************************/
+
+/***********************************************************************************************************************
+ * Public
+ **********************************************************************************************************************/
+
+RetWithError<Time> Time::UTC(const String& utcTimeStr)
+{
+    struct tm timeInfo = {};
+
+    if (auto err = ParseDateTime(utcTimeStr.CStr(), cUTCFormat, &timeInfo); !err.IsNone()) {
+        return {{}, err};
+    }
+
+#if defined(__ZEPHYR__)
+    auto seconds = timeutil_timegm(&timeInfo);
+#else
+    auto seconds = timegm(&timeInfo);
+#endif
+
+    return Time::Unix(seconds);
+}
+
+RetWithError<StaticString<cTimeStrLen>> Time::ToUTCString() const
+{
+    tm                        buf;
+    StaticString<cTimeStrLen> utcTimeStr;
+
+    auto unixTime = UnixTime();
+
+    auto time = gmtime_r(&unixTime.tv_sec, &buf);
+
+    utcTimeStr.Resize(utcTimeStr.MaxSize());
+
+    size_t size = strftime(utcTimeStr.Get(), utcTimeStr.Size(), "%FT%TZ", time);
+    if (size == 0) {
+        return {{}, Error(ErrorEnum::eFailed, "failed to format time")};
+    }
+
+    if (auto err = utcTimeStr.Resize(size); !err.IsNone()) {
+        return {{}, AOS_ERROR_WRAP(err)};
+    }
+
+    return utcTimeStr;
+}
+
 } // namespace aos
diff --git a/tests/common/src/tools/fs_test.cpp b/tests/common/src/tools/fs_test.cpp
index 08c3b1754..a21f00ccd 100644
--- a/tests/common/src/tools/fs_test.cpp
+++ b/tests/common/src/tools/fs_test.cpp
@@ -5,12 +5,15 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
+#include <fcntl.h>
 #include <filesystem>
 #include <fstream>
+#include <stdio.h>
 
 #include <gtest/gtest.h>
 
 #include "aos/common/tools/fs.hpp"
+#include "aos/common/tools/memory.hpp"
 
 #include "aos/test/log.hpp"
 
@@ -296,6 +299,50 @@ TEST_F(FSTest, ReadFileToString)
     fs::RemoveAll(testFile.c_str());
 }
 
+TEST_F(FSTest, ReadLine)
+{
+    const auto testFile = cBaseTestDir / "read-line-test.txt";
+
+    const char text[] = "Hello World0\nHello World1\nHello World2\n";
+
+    CreateFile(testFile.c_str(), text);
+
+    StaticString<100> bigBuff;
+    StaticString<1>   smallBuff;
+
+    size_t filePos = 0;
+
+    auto fd = open(testFile.c_str(), O_RDONLY);
+    ASSERT_GE(fd, 0);
+
+    auto closeFile = DeferRelease(&fd, [](const int* fd) { close(*fd); });
+
+    EXPECT_FALSE(fs::ReadLine(fd, std::string::npos, smallBuff).IsNone());
+
+    EXPECT_EQ(fs::ReadLine(fd, filePos, smallBuff), ErrorEnum::eNotFound);
+
+    EXPECT_EQ(fs::ReadLine(fd, 0, bigBuff, "\t"), ErrorEnum::eNotFound);
+
+    EXPECT_TRUE(fs::ReadLine(fd, filePos, bigBuff).IsNone());
+    EXPECT_EQ(bigBuff, "Hello World0");
+
+    filePos += bigBuff.Size() + 1;
+
+    EXPECT_TRUE(fs::ReadLine(fd, filePos, bigBuff).IsNone());
+    EXPECT_EQ(bigBuff, "Hello World1");
+
+    filePos += bigBuff.Size() + 1;
+
+    EXPECT_TRUE(fs::ReadLine(fd, filePos, bigBuff).IsNone());
+    EXPECT_EQ(bigBuff, "Hello World2");
+
+    filePos += bigBuff.Size() + 1;
+
+    fs::RemoveAll(testFile.c_str());
+
+    EXPECT_FALSE(fs::ReadLine(fd, 0, smallBuff).IsNone());
+}
+
 TEST_F(FSTest, WriteFile)
 {
     const auto newFile      = cBaseTestDir / "write-file-new.txt";
diff --git a/tests/common/src/tools/time_test.cpp b/tests/common/src/tools/time_test.cpp
index 71f7d8a97..f5659b66b 100644
--- a/tests/common/src/tools/time_test.cpp
+++ b/tests/common/src/tools/time_test.cpp
@@ -128,3 +128,50 @@ TEST_F(TimeTest, GetDateTime)
     EXPECT_EQ(min, 00);
     EXPECT_EQ(sec, 00);
 }
+
+TEST_F(TimeTest, FromUTCString)
+{
+    constexpr auto cUTCString = "2024-01-31T12:00:00Z";
+
+    auto [time, timeErr] = Time::UTC(cUTCString);
+    ASSERT_EQ(timeErr, ErrorEnum::eNone);
+
+    int day, month, year, hour, min, sec;
+
+    EXPECT_TRUE(time.GetDate(&day, &month, &year).IsNone());
+    EXPECT_TRUE(time.GetTime(&hour, &min, &sec).IsNone());
+
+    EXPECT_EQ(day, 31);
+    EXPECT_EQ(month, 1);
+    EXPECT_EQ(year, 2024);
+    EXPECT_EQ(hour, 12);
+    EXPECT_EQ(min, 00);
+    EXPECT_EQ(sec, 00);
+
+    auto [utcString, stringErr] = time.ToUTCString();
+    ASSERT_EQ(stringErr, ErrorEnum::eNone);
+
+    EXPECT_STREQ(utcString.CStr(), "2024-01-31T12:00:00Z");
+}
+
+TEST_F(TimeTest, ToUTCString)
+{
+    auto t = Time::Unix(1706702400);
+
+    int day, month, year, hour, min, sec;
+
+    EXPECT_TRUE(t.GetDate(&day, &month, &year).IsNone());
+    EXPECT_TRUE(t.GetTime(&hour, &min, &sec).IsNone());
+
+    EXPECT_EQ(day, 31);
+    EXPECT_EQ(month, 1);
+    EXPECT_EQ(year, 2024);
+    EXPECT_EQ(hour, 12);
+    EXPECT_EQ(min, 00);
+    EXPECT_EQ(sec, 00);
+
+    auto [utcString, err] = t.ToUTCString();
+    ASSERT_EQ(err, ErrorEnum::eNone);
+
+    EXPECT_STREQ(utcString.CStr(), "2024-01-31T12:00:00Z");
+}


Reviews:
user: login: MykolaSuperman
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-13T09:32:09Z
user: login: al1img
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-13T16:31:07Z
user: login: MykolaSuperman
state: APPROVED
author_association: NONE
submitted_at: 2025-05-13T16:34:55Z

Review comments:
diff_hunk: @@ -504,22 +511,12 @@ class Time {
      */
     friend Log& operator<<(Log& log, const Time& obj)
     {
-        tm                        buf;
-        StaticString<cTimeStrLen> utcTimeStr;
-
-        auto time = gmtime_r(&obj.mTime.tv_sec, &buf);
-        assert(time != nullptr);
-
-        utcTimeStr.Resize(utcTimeStr.MaxSize());
-
-        size_t size = strftime(utcTimeStr.Get(), utcTimeStr.Size(), "%FT%TZ", time);
-        assert(size != 0);
-
-        utcTimeStr.Resize(size - 1);
-
-        log << utcTimeStr;
+        auto [utcTimeStr, err] = obj.ToUTCString();
+        if (!err.IsNone()) {
+            return log << "invalid time";
path: include/aos/common/tools/time.hpp
user: login: MykolaSuperman
body: maybe better to print `err` mesage?
created_at: 2025-05-13T09:28:24Z
author_association: NONE
diff_hunk: @@ -92,4 +96,35 @@ StaticString<cTimeStrLen> Duration::ToISO8601String() const
     return result;
 }
 
+/***********************************************************************************************************************
+ * Time
+ **********************************************************************************************************************/
+
+/***********************************************************************************************************************
+ * Public
+ **********************************************************************************************************************/
+
+RetWithError<StaticString<cTimeStrLen>> Time::ToUTCString() const
+{
+    tm                        buf;
+    StaticString<cTimeStrLen> utcTimeStr;
+
+    auto unixTime = UnixTime();
+
+    auto time = gmtime_r(&unixTime.tv_sec, &buf);
+
+    utcTimeStr.Resize(utcTimeStr.MaxSize());
+
+    size_t size = strftime(utcTimeStr.Get(), utcTimeStr.Size(), "%FT%TZ", time);
+    if (size == 0) {
+        return {{}, ErrorEnum::eFailed};
path: src/common/tools/time.cpp
user: login: MykolaSuperman
body: maybe here to add message like can't convert to UTC Time and on called side print err ? 
created_at: 2025-05-13T09:28:29Z
author_association: NONE
diff_hunk: @@ -4,10 +4,149 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
+#if defined(__ZEPHYR__)
+#include <zephyr/sys/timeutil.h>
+#endif
+
 #include "aos/common/tools/time.hpp"
 
 namespace aos {
 
+namespace {
+
+/***********************************************************************************************************************
+ * Constants
+ **********************************************************************************************************************/
+
+constexpr auto cUTCFormat = "%Y-%m-%dT%H:%M:%SZ";
+
+/***********************************************************************************************************************
+ * Static
+ **********************************************************************************************************************/
+
+const char* ConsumeChars(const char* s, char* dest, size_t cnt)
+{
+    if (strnlen(s, cnt) < cnt) {
+        return nullptr;
+    }
+
+    memcpy(dest, s, cnt);
+    dest[cnt] = '\0';
+
+    return s + cnt;
+}
+
+const char* ConsumeChar(const char* s, char ch)
+{
+    if (*s != ch) {
+        return nullptr;
+    }
+
+    return ++s;
+}
+
+const char* ConsumeDate(const char* s, struct tm* tm_time)
+{
+    char year[4 + 1];
+    char month[2 + 1];
+    char day[2 + 1];
+
+    s = ConsumeChars(s, year, 4);
+    if (!s) {
+        return nullptr;
+    }
+
+    s = ConsumeChar(s, '-');
+    if (!s) {
+        return nullptr;
+    }
+
+    s = ConsumeChars(s, month, 2);
+    if (!s) {
+        return nullptr;
+    }
+
+    s = ConsumeChar(s, '-');
+    if (!s) {
+        return nullptr;
+    }
+
+    s = ConsumeChars(s, day, 2);
+    if (!s) {
+        return nullptr;
+    }
+
+    tm_time->tm_year = atoi(year) - 1900;
+    tm_time->tm_mon  = atoi(month) - 1;
+    tm_time->tm_mday = atoi(day);
+
+    return s;
+}
+
+const char* ConsumeTime(const char* s, struct tm* tm_time)
+{
+    char hour[2 + 1];
+    char minute[2 + 1];
+    char second[2 + 1];
+
+    s = ConsumeChars(s, hour, 2);
+    if (!s) {
+        return nullptr;
+    }
+
+    s = ConsumeChar(s, ':');
+    if (!s) {
+        return nullptr;
+    }
+
+    s = ConsumeChars(s, minute, 2);
+    if (!s) {
+        return nullptr;
+    }
+
+    s = ConsumeChar(s, ':');
+    if (!s) {
+        return nullptr;
+    }
+
+    s = ConsumeChars(s, second, 2);
+    if (!s) {
+        return nullptr;
+    }
+
+    tm_time->tm_hour = atoi(hour);
+    tm_time->tm_min  = atoi(minute);
+    tm_time->tm_sec  = atoi(second);
+
+    return s;
+}
+
+Error ParseDateTime(const char* s, const char* format, struct tm* tm_time)
+{
+    if (strcmp(format, cUTCFormat) != 0) {
+        return ErrorEnum::eInvalidArgument;
+    }
+
+    s = ConsumeDate(s, tm_time);
+    if (!s) {
+        return ErrorEnum::eFailed;
+    }
+
+    s = ConsumeChar(s, 'T');
+    if (!s) {
+        return ErrorEnum::eFailed;
+    }
+
+    s = ConsumeTime(s, tm_time);
+    if (!s) {
+        return ErrorEnum::eFailed;
+    }
path: src/common/tools/time.cpp
user: login: MykolaSuperman
body: maybe will be helpfull to provide err message, not just fail to better understand the err reason?
created_at: 2025-05-13T09:30:02Z
author_association: NONE

PR comments:
user: login: codecov[bot]
created_at: 2025-05-12T09:43:00Z
body: ## [Codecov](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/pull/310?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge) Report
Attention: Patch coverage is `85.33333%` with `22 lines` in your changes missing coverage. Please review.
> Project coverage is 84.21%. Comparing base [(`1b4d01f`)](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/commit/1b4d01f3e51b1442ed8b1bb92b100a4447243446?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge) to head [(`2f93964`)](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/commit/2f939647292752fb9a74f68064515c2f1fd73fc2?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge).
> Report is 7 commits behind head on develop.

| [Files with missing lines](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/pull/310?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge) | Patch % | Lines |
|---|---|---|
| [src/common/tools/time.cpp](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/pull/310?src=pr&el=tree&filepath=src%2Fcommon%2Ftools%2Ftime.cpp&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge#diff-c3JjL2NvbW1vbi90b29scy90aW1lLmNwcA==) | 76.25% | [19 Missing :warning: ](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/pull/310?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge) |
| [src/common/tools/fs.cpp](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/pull/310?src=pr&el=tree&filepath=src%2Fcommon%2Ftools%2Ffs.cpp&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge#diff-c3JjL2NvbW1vbi90b29scy9mcy5jcHA=) | 84.61% | [2 Missing :warning: ](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/pull/310?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge) |
| [include/aos/common/tools/time.hpp](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/pull/310?src=pr&el=tree&filepath=include%2Faos%2Fcommon%2Ftools%2Ftime.hpp&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge#diff-aW5jbHVkZS9hb3MvY29tbW9uL3Rvb2xzL3RpbWUuaHBw) | 75.00% | [1 Missing :warning: ](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/pull/310?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff            @@
##           develop     #310    +/-   ##
=========================================
  Coverage    84.20%   84.21%            
=========================================
  Files          160      160            
  Lines        14926    15067   +141     
  Branches      1849     1873    +24     
=========================================
+ Hits         12569    12688   +119     
- Misses        2357     2379    +22     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/aosedge/aos_core_lib_cpp/pull/310?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aosedge).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-05-13T11:28:00Z
body: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=aosedge_aos_core_lib_cpp&pullRequest=310) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [43.2% Coverage on New Code](https://sonarcloud.io/component_measures?id=aosedge_aos_core_lib_cpp&pullRequest=310&metric=new_coverage&view=list) (required ≥ 80%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=aosedge_aos_core_lib_cpp&pullRequest=310)


author_association: NONE