test: Add test_Utils

Add the unit test to verify the findFiles() in utils, the tests creates
test directory structure like hwmon and peci and verify the result is
expected.

Tested: Verify the unit test passes.

Signed-off-by: Lei YU <yulei.sh@bytedance.com>
Change-Id: I11976399909235de509e09865af0b3421db6b565
diff --git a/tests/meson.build b/tests/meson.build
index 50eaf0e..e20eccf 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -49,3 +49,18 @@
     )
 )
 endif
+
+test(
+    'test_utils',
+    executable(
+        'test_utils',
+        'test_Utils.cpp',
+        '../src/Utils.cpp',
+        dependencies: [
+            sdbusplus,
+            gtest_dep,
+        ],
+        implicit_include_directories: false,
+        include_directories: '../include',
+    )
+)
diff --git a/tests/test_Utils.cpp b/tests/test_Utils.cpp
new file mode 100644
index 0000000..170e22d
--- /dev/null
+++ b/tests/test_Utils.cpp
@@ -0,0 +1,147 @@
+#include <Utils.hpp>
+
+#include <filesystem>
+#include <fstream>
+
+#include <gtest/gtest.h>
+
+namespace fs = std::filesystem;
+class TestUtils : public testing::Test
+{
+  public:
+    std::string testDir;
+    fs::path hwmonDir;
+    fs::path peciDir;
+    TestUtils()
+    {
+        // Create test environment
+        char dir[] = "./testDirXXXXXX";
+        testDir = mkdtemp(dir);
+
+        if (testDir.empty())
+        {
+            throw std::bad_alloc();
+        }
+        hwmonDir = fs::path(testDir) / "hwmon";
+        fs::create_directory(hwmonDir);
+        auto hwmon10 = hwmonDir / "hwmon10";
+        fs::create_directory(hwmonDir / "hwmon10");
+        std::ofstream{hwmon10 / "temp1_input"};
+        std::ofstream{hwmon10 / "temp1_min"};
+        std::ofstream{hwmon10 / "temp1_max"};
+        std::ofstream{hwmon10 / "temp2_input"};
+        createPECIDir();
+    }
+
+    ~TestUtils() override
+    {
+        fs::remove_all(testDir);
+    }
+
+    void createPECIDir()
+    {
+        peciDir = fs::path(testDir) / "peci";
+        auto peci0 =
+            peciDir / "peci-0/device/0-30/peci-cputemp.0/hwmon/hwmon25";
+        fs::create_directories(peci0);
+        std::ofstream{peci0 / "temp0_input"};
+        std::ofstream{peci0 / "temp1_input"};
+        std::ofstream{peci0 / "temp2_input"};
+        std::ofstream{peci0 / "name"};
+        auto devDir = peciDir / "peci-0/peci_dev/peci-0";
+        fs::create_directories(devDir);
+        fs::create_directory_symlink("../../../peci-0", devDir / "device");
+        fs::create_directory_symlink("device/0-30", peciDir / "peci-0/0-30");
+
+        // Let's keep this for debugging purpose
+        for (auto p = fs::recursive_directory_iterator(
+                 peciDir, fs::directory_options::follow_directory_symlink);
+             p != fs::recursive_directory_iterator(); ++p)
+        {
+            std::string path = p->path().string();
+            fprintf(stderr, "%s\n", path.c_str());
+            if (p.depth() >= 6)
+            {
+                p.disable_recursion_pending();
+            }
+        }
+    }
+};
+
+TEST_F(TestUtils, findFiles_non_exist)
+{
+    std::vector<fs::path> foundPaths;
+    auto ret = findFiles("non-exist", "", foundPaths);
+
+    EXPECT_FALSE(ret);
+    EXPECT_TRUE(foundPaths.empty());
+}
+
+TEST_F(TestUtils, findFiles_in_hwmon_no_match)
+{
+    std::vector<fs::path> foundPaths;
+    auto ret = findFiles(hwmonDir, R"(in\d+_input)", foundPaths);
+
+    EXPECT_TRUE(ret);
+    EXPECT_EQ(foundPaths.size(), 0u);
+}
+
+TEST_F(TestUtils, findFiles_in_hwmon_match)
+{
+    std::vector<fs::path> foundPaths;
+    auto ret = findFiles(hwmonDir, R"(temp\d+_input)", foundPaths);
+
+    EXPECT_TRUE(ret);
+    EXPECT_EQ(foundPaths.size(), 2u);
+}
+
+TEST_F(TestUtils, findFiles_in_peci_no_match)
+{
+    std::vector<fs::path> foundPaths;
+    auto ret =
+        findFiles(peciDir, R"(peci-\d+/\d+-.+/peci-.+/hwmon/hwmon\d+/aaa$)",
+                  foundPaths, 6);
+
+    EXPECT_TRUE(ret);
+    EXPECT_TRUE(foundPaths.empty());
+}
+
+TEST_F(TestUtils, findFiles_in_peci_match)
+{
+    std::vector<fs::path> foundPaths;
+    auto ret =
+        findFiles(peciDir, R"(peci-\d+/\d+-.+/peci-.+/hwmon/hwmon\d+/name$)",
+                  foundPaths, 6);
+    EXPECT_TRUE(ret);
+    EXPECT_EQ(foundPaths.size(), 1u);
+
+    foundPaths.clear();
+
+    ret = findFiles(peciDir,
+                    R"(peci-\d+/\d+-.+/peci-.+/hwmon/hwmon\d+/temp\d+_input)",
+                    foundPaths, 6);
+    EXPECT_TRUE(ret);
+    EXPECT_EQ(foundPaths.size(), 3u);
+}
+
+TEST_F(TestUtils, findFiles_hwmonPath_end_with_slash)
+{
+    std::string p = hwmonDir.string() + "/";
+    std::vector<fs::path> foundPaths;
+    auto ret = findFiles(p, R"(temp\d+_input)", foundPaths);
+
+    EXPECT_TRUE(ret);
+    EXPECT_EQ(foundPaths.size(), 2u);
+}
+
+TEST_F(TestUtils, findFiles_peciPath_end_with_slash)
+{
+    std::string p = peciDir.string() + "/";
+    std::vector<fs::path> foundPaths;
+    auto ret =
+        findFiles(p, R"(peci-\d+/\d+-.+/peci-.+/hwmon/hwmon\d+/temp\d+_input)",
+                  foundPaths, 6);
+
+    EXPECT_TRUE(ret);
+    EXPECT_EQ(foundPaths.size(), 3u);
+}