replace boost::ifind_first with std::ranges::search

Use a custom case-insensitive search to remove Boost dependency and
reduce compilation memory usage, keeping original string replacement
behavior.

Change-Id: I5778b208dfdb0082515e92f7bda335beb94c21cb
Signed-off-by: George Liu <liuxiwei@ieisystem.com>
diff --git a/test/meson.build b/test/meson.build
index a22fd31..50f0901 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -54,3 +54,14 @@
         link_with: gpio_presence_lib,
     ),
 )
+
+test(
+    'test_utils',
+    executable(
+        'test_utils',
+        'test_utils.cpp',
+        '../src/utils.cpp',
+        include_directories: test_include_dir,
+        dependencies: [gtest, phosphor_logging_dep],
+    ),
+)
diff --git a/test/test_utils.cpp b/test/test_utils.cpp
new file mode 100644
index 0000000..76570df
--- /dev/null
+++ b/test/test_utils.cpp
@@ -0,0 +1,52 @@
+#include "utils.hpp"
+
+#include <gtest/gtest.h>
+
+TEST(IfindFirstTest, BasicMatch)
+{
+    auto [firstIndex, lastIndex] = iFindFirst("Hello World", "World");
+    EXPECT_EQ(firstIndex, 6);
+    EXPECT_EQ(lastIndex, 11);
+}
+
+TEST(IfindFirstTest, CaseInsensitiveMatch)
+{
+    auto [firstIndex, lastIndex] = iFindFirst("Hello World", "world");
+    EXPECT_EQ(firstIndex, 6);
+    EXPECT_EQ(lastIndex, 11);
+}
+
+TEST(IfindFirstTest, NoMatch)
+{
+    auto [firstIndex, lastIndex] = iFindFirst("Hello World", "Planet");
+    EXPECT_EQ(firstIndex, std::string_view::npos);
+    EXPECT_EQ(lastIndex, std::string_view::npos);
+}
+
+TEST(IfindFirstTest, MatchAtStart)
+{
+    auto [firstIndex, lastIndex] = iFindFirst("Hello World", "HeLLo");
+    EXPECT_EQ(firstIndex, 0);
+    EXPECT_EQ(lastIndex, 5);
+}
+
+TEST(IfindFirstTest, MatchAtEnd)
+{
+    auto [firstIndex, lastIndex] = iFindFirst("Hello World", "LD");
+    EXPECT_EQ(firstIndex, 9);
+    EXPECT_EQ(lastIndex, 11);
+}
+
+TEST(IfindFirstTest, EmptySubstring)
+{
+    auto [firstIndex, lastIndex] = iFindFirst("Hello", "");
+    EXPECT_EQ(firstIndex, std::string_view::npos);
+    EXPECT_EQ(lastIndex, std::string_view::npos);
+}
+
+TEST(IfindFirstTest, EmptyString)
+{
+    auto [firstIndex, lastIndex] = iFindFirst("", "Hello");
+    EXPECT_EQ(firstIndex, std::string_view::npos);
+    EXPECT_EQ(lastIndex, std::string_view::npos);
+}