main: Fix getSubTree & getSubTreePaths partial match

Due to us popping out the trailing "/" in our "reqPath", partial matches
satisfied the "boost::starts_with(" searches for paths - leading to
"core1X" for example, matching a reqPath of "core1" or "core1/".

Since we do not want to return the base reqPath anyway, add a trailing
"/" in the reqPath for the match to ensure complete match.

Tested:
dbus-send --system --print-reply --dest=xyz.openbmc_project.ObjectMapper /xyz/openbmc_project/object_mapper xyz.openbmc_project.ObjectMapper.GetSubTreePaths string:"/xyz/openbmc_oject/inventory/system/chassis/motherboard/cpu0/core1" int32:0 array:string:"xyz.openbmc_project.Inventory.Item.CpuThread"

Without the fix:
   array [
      string "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu0/core1/thread0"
      string "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu0/core11/thread0"
      string "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu0/core12/thread0"
      string "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu0/core13/thread0"
      string "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu0/core14/thread0"
      string "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu0/core15/thread0"
      string "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu0/core16/thread0"
      string "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu0/core17/thread0"
      string "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu0/core18/thread0"
      string "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu0/core19/thread0"
   ]

With the fix:
   array [
      string "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu0/core1/thread0"
   ]

Similar results with GetSubTree, results not pasted as it's too long:
dbus-send --system --print-reply --dest=xyz.openbmc_project.ObjectMapper /xyz/openbmc_project/object_mapper xyz.openbmc_project.ObjectMapper.GetSubTree string:"/xyz/openbmc_proje/inventory/system/chassis/motherboard/cpu0/core1" int32:0 array:string:"xyz.openbmc_project.Inventory.Item.CpuThread"

-------------
Also verified that "depth" remained the same using print outs:

Before change:
mapperx[12580]: thisPath: /xyz/openbmc_project/sensors/power
mapperx[12580]: reqPath:
mapperx[12580]: thisDepth: 4

mapperx[12580]: thisPath: /xyz/openbmc_project/sensors/temperature
mapperx[12580]: reqPath: /xyz/openbmc_project
mapperx[12580]: thisDepth: 2

After:
mapperx[30959]: thisPath: /xyz/openbmc_project/network
mapperx[30959]: reqPath: /
mapperx[30959]: thisDepth: 3

mapperx[30959]: thisPath: /xyz/openbmc_project/inventory/system/board
mapperx[30959]: reqPath: /xyz/openbmc_project/inventory/system/
mapperx[30959]: thisDepth: 1

Signed-off-by: Brandon Kim <brandonkim@google.com>
Change-Id: If488402a3839de21c50b4585e51fa156016e768d
diff --git a/src/main.cpp b/src/main.cpp
index 64031b8..1e3883f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -18,6 +18,8 @@
 #include <exception>
 #include <iomanip>
 #include <iostream>
+#include <string>
+#include <string_view>
 #include <utility>
 
 AssociationMaps associationMaps;
@@ -545,11 +547,17 @@
     // Interfaces need to be sorted for intersect to function
     std::sort(interfaces.begin(), interfaces.end());
 
-    if (boost::ends_with(reqPath, "/"))
+    // reqPath is now guaranteed to have a trailing "/" while reqPathStripped
+    // will be guaranteed not to have a trailing "/"
+    if (!boost::ends_with(reqPath, "/"))
     {
-        reqPath.pop_back();
+        reqPath += "/";
     }
-    if (!reqPath.empty() && interfaceMap.find(reqPath) == interfaceMap.end())
+    std::string_view reqPathStripped =
+        std::string_view(reqPath).substr(0, reqPath.size() - 1);
+
+    if (!reqPathStripped.empty() &&
+        interfaceMap.find(reqPathStripped) == interfaceMap.end())
     {
         throw sdbusplus::xyz::openbmc_project::Common::Error::
             ResourceNotFound();
@@ -560,16 +568,17 @@
     {
         const auto& thisPath = objectPath.first;
 
-        if (thisPath == reqPath)
+        // Skip exact match on stripped search term
+        if (thisPath == reqPathStripped)
         {
             continue;
         }
 
         if (boost::starts_with(thisPath, reqPath))
         {
-            // count the number of slashes past the search term
-            int32_t thisDepth = std::count(thisPath.begin() + reqPath.size(),
-                                           thisPath.end(), '/');
+            // count the number of slashes past the stripped search term
+            int32_t thisDepth = std::count(
+                thisPath.begin() + reqPathStripped.size(), thisPath.end(), '/');
             if (thisDepth <= depth)
             {
                 for (const auto& interfaceMap : objectPath.second)
@@ -600,11 +609,17 @@
     // Interfaces need to be sorted for intersect to function
     std::sort(interfaces.begin(), interfaces.end());
 
-    if (boost::ends_with(reqPath, "/"))
+    // reqPath is now guaranteed to have a trailing "/" while reqPathStripped
+    // will be guaranteed not to have a trailing "/"
+    if (!boost::ends_with(reqPath, "/"))
     {
-        reqPath.pop_back();
+        reqPath += "/";
     }
-    if (!reqPath.empty() && interfaceMap.find(reqPath) == interfaceMap.end())
+    std::string_view reqPathStripped =
+        std::string_view(reqPath).substr(0, reqPath.size() - 1);
+
+    if (!reqPathStripped.empty() &&
+        interfaceMap.find(reqPathStripped) == interfaceMap.end())
     {
         throw sdbusplus::xyz::openbmc_project::Common::Error::
             ResourceNotFound();
@@ -615,16 +630,17 @@
     {
         const auto& thisPath = objectPath.first;
 
-        if (thisPath == reqPath)
+        // Skip exact match on stripped search term
+        if (thisPath == reqPathStripped)
         {
             continue;
         }
 
         if (boost::starts_with(thisPath, reqPath))
         {
-            // count the number of slashes past the search term
-            int thisDepth = std::count(thisPath.begin() + reqPath.size(),
-                                       thisPath.end(), '/');
+            // count the number of slashes past the stripped search term
+            int thisDepth = std::count(
+                thisPath.begin() + reqPathStripped.size(), thisPath.end(), '/');
             if (thisDepth <= depth)
             {
                 bool add = interfaces.empty();