Test cases for VPD-Manager read functionalities

Implementation of test cases for read functionalities provided
by VPD-Manager app.

Signed-off-by: Sunny Srivastava <sunnsr25@in.ibm.com>
Change-Id: I83ad6757934a4c28ae26eb11f0b1f380e2c82aa8
diff --git a/meson.build b/meson.build
index e72ab81..9603762 100644
--- a/meson.build
+++ b/meson.build
@@ -12,6 +12,7 @@
 
 sdbusplus = dependency('sdbusplus')
 phosphor_logging = dependency('phosphor-logging')
+phosphor_dbus_interfaces = dependency('phosphor-dbus-interfaces')
 
 compiler = meson.get_compiler('cpp')
 python = find_program('python3', required:true)
diff --git a/test/meson.build b/test/meson.build
index a8f9793..eab0c67 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -11,50 +11,37 @@
 else
   dynamic_linker = []
 endif
-
 gmock = dependency('gmock', disabler: true, required: build_tests)
 gtest = dependency('gtest', main: true, disabler: true, required: build_tests)
+dependecy_list = [gtest, gmock, sdbusplus, phosphor_logging, phosphor_dbus_interfaces]
 
-application_src = ['../impl.cpp']
+configuration_inc = include_directories('..', '../vpd-manager', 'vpd-manager-test')
 
-test('store_test', executable('store_test',
-        ['store/store.cpp', application_src],
-build_rpath: get_option('oe-sdk').enabled() ? rpath : '',
+vpd_test = ['store/store.cpp',
+            'ipz_parser/parser.cpp',
+            'keyword_vpd_parser_test/kw_vpd_test.cpp',
+            'vpd-manager-test/reader_test.cpp',
+           ]
 
-link_args: dynamic_linker,
-dependencies: [
-            gtest,
-            gmock,
-            sdbusplus,
-            phosphor_logging,
-    ],
-include_directories: '..'
-),
-workdir: meson.current_source_dir())
+application_src =['../impl.cpp',
+                   '../vpdecc/vpdecc.c',
+                   '../vpdecc/vpdecc_support.c',
+                   '../parser.cpp',
+                   '../utils.cpp',
+                   '../vpd-manager/reader_impl.cpp',
+                   '../keyword_vpd_parser.cpp',
+                  ]
 
-vpd_test = ['ipz_parser/parser.cpp',
-                'keyword_vpd_parser_test/kw_vpd_test.cpp'
-    ]
-application_src += ['../keyword_vpd_parser.cpp',
-  '../vpdecc/vpdecc.c',
-  '../vpdecc/vpdecc_support.c'
-    ]
 foreach t : vpd_test
     test(t, executable(t.underscorify(),
             [t, application_src],
     build_rpath: get_option('oe-sdk').enabled() ? rpath : '',
-
     link_args: dynamic_linker,
-    cpp_args: '-DIPZ_PARSER',
+    cpp_args: ['-DIPZ_PARSER', '-DManagerTest'],
     c_args: ['-Wno-unused-parameter',
       '-Wno-unused-variable'],
-    dependencies: [
-                gtest,
-                gmock,
-                sdbusplus,
-                phosphor_logging,
-        ],
-    include_directories: '..'
+    dependencies: dependecy_list,
+    include_directories: configuration_inc
     ),
     workdir: meson.current_source_dir())
 endforeach
diff --git a/test/vpd-manager-test/reader_test.cpp b/test/vpd-manager-test/reader_test.cpp
new file mode 100644
index 0000000..b6cf80c
--- /dev/null
+++ b/test/vpd-manager-test/reader_test.cpp
@@ -0,0 +1,254 @@
+#include "reader_test.hpp"
+
+#include "const.hpp"
+#include "reader_impl.hpp"
+#include "types.hpp"
+
+#include <fstream>
+#include <nlohmann/json.hpp>
+#include <tuple>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace openpower::vpd::manager::reader;
+using namespace openpower::vpd::inventory;
+using namespace openpower::vpd::constants;
+
+class vpdManagerReaderTest : public ::testing::Test
+{
+  protected:
+    nlohmann::json jsonFile;
+
+    // map to hold the mapping of location code and inventory path
+    LocationCodeMap fruLocationCode;
+
+    // dummy value of node number
+    const uint8_t nodeNumber = 1;
+
+  public:
+    // constructor
+    vpdManagerReaderTest()
+    {
+        processJson();
+    }
+
+    void processJson();
+};
+
+using namespace openpower::vpd;
+
+void vpdManagerReaderTest::processJson()
+{
+    // read the json file and parse it
+    std::ifstream json("vpd-manager-test/vpd_reader_test.json",
+                       std::ios::binary);
+
+    if (!json)
+    {
+        throw std::runtime_error("json file not found");
+    }
+
+    jsonFile = nlohmann::json::parse(json);
+
+    if (jsonFile.find("frus") == jsonFile.end())
+    {
+        throw std::runtime_error("frus group not found in json");
+    }
+
+    const nlohmann::json& groupFRUS =
+        jsonFile["frus"].get_ref<const nlohmann::json::object_t&>();
+    for (const auto& itemFRUS : groupFRUS.items())
+    {
+        const std::vector<nlohmann::json>& groupEEPROM =
+            itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
+        for (const auto& itemEEPROM : groupEEPROM)
+        {
+            fruLocationCode.emplace(
+                itemEEPROM["extraInterfaces"][LOCATION_CODE_INF]["LocationCode"]
+                    .get_ref<const nlohmann::json::string_t&>(),
+                itemEEPROM["inventoryPath"]
+                    .get_ref<const nlohmann::json::string_t&>());
+        }
+    }
+}
+
+TEST_F(vpdManagerReaderTest, isValidLocationCode_invalid)
+{
+    // No MTS or FCS in the collapsed location code
+    std::string unexpandedLocationCode_Invalid = "Uabc-X0";
+
+    MockUtilCalls uCalls;
+    ReaderImpl read(uCalls);
+    EXPECT_ANY_THROW({
+        read.getExpandedLocationCode(unexpandedLocationCode_Invalid, nodeNumber,
+                                     fruLocationCode);
+    });
+
+    // not starting with U
+    unexpandedLocationCode_Invalid = "Mabc-X0";
+    EXPECT_ANY_THROW({
+        read.getExpandedLocationCode(unexpandedLocationCode_Invalid, nodeNumber,
+                                     fruLocationCode);
+    });
+}
+
+TEST_F(vpdManagerReaderTest, getExpandedLocationCode_Invalid)
+{
+    std::string unexpandedLocationCode_Invalid = "Uabc-X0";
+
+    MockUtilCalls uCalls;
+    ReaderImpl read(uCalls);
+    EXPECT_ANY_THROW({
+        read.getExpandedLocationCode(unexpandedLocationCode_Invalid, nodeNumber,
+                                     fruLocationCode);
+    });
+}
+
+TEST_F(vpdManagerReaderTest, getExpandedLocationCode_Valid)
+{
+    // mock the call to read bus property
+    MockUtilCalls uCalls;
+    EXPECT_CALL(uCalls, readBusProperty("/system/chassis/motherboard",
+                                        LOCATION_CODE_INF, "LocationCode"))
+        .Times(1)
+        .WillOnce(testing::Return("U78DA.ND1.1234567-P0"));
+
+    std::string unexpandedLocationCode = "Ufcs-P0";
+    ReaderImpl read(uCalls);
+    std::string res = read.getExpandedLocationCode(unexpandedLocationCode,
+                                                   nodeNumber, fruLocationCode);
+
+    EXPECT_EQ(res, "U78DA.ND1.1234567-P0");
+}
+
+TEST_F(vpdManagerReaderTest, getFrusAtLocation_Invalid)
+{
+    // invalid lication code
+    std::string unexpandedLocationCode = "Uabc-X0";
+
+    MockUtilCalls uCalls;
+    ReaderImpl read(uCalls);
+    EXPECT_ANY_THROW({
+        read.getFrusAtLocation(unexpandedLocationCode, nodeNumber,
+                               fruLocationCode);
+    });
+
+    // map to hold the mapping of location code and inventory path, empty in
+    // this case
+    LocationCodeMap mapLocationCode;
+    unexpandedLocationCode = "Ufcs-P0";
+    EXPECT_ANY_THROW({
+        read.getFrusAtLocation(unexpandedLocationCode, nodeNumber,
+                               mapLocationCode);
+    });
+}
+
+TEST_F(vpdManagerReaderTest, getFrusAtLocation_Valid)
+{
+    std::string LocationCode = "Ufcs-P0";
+
+    MockUtilCalls uCalls;
+    ReaderImpl read(uCalls);
+    ListOfPaths paths =
+        read.getFrusAtLocation(LocationCode, nodeNumber, fruLocationCode);
+    std::string expected =
+        "/xyz/openbmc_project/inventory/system/chassis/motherboard";
+    EXPECT_EQ(paths.at(0), expected);
+}
+
+TEST_F(vpdManagerReaderTest, getFRUsByExpandedLocationCode_invalid)
+{
+    // not starting from U
+    std::string locationCode = "9105.22A.SIMP10R";
+
+    MockUtilCalls uCalls;
+    ReaderImpl read(uCalls);
+    ListOfPaths paths;
+    EXPECT_ANY_THROW({
+        paths =
+            read.getFRUsByExpandedLocationCode(locationCode, fruLocationCode);
+    });
+
+    // unused variable warning
+    (void)paths;
+
+    // length is les sthan 17 for expanded location code
+    locationCode = "U9105.22A.SIMP10";
+    EXPECT_ANY_THROW({
+        paths =
+            read.getFRUsByExpandedLocationCode(locationCode, fruLocationCode);
+    });
+
+    // Invalid location code. No "."
+    locationCode = "U78DAND11234567-P0";
+
+    // Mock readBUsproperty call
+    EXPECT_CALL(uCalls,
+                readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VCEN", "FC"))
+        .Times(1)
+        .WillOnce(
+            testing::Return("78DAPQRS")); // return a dummy value for FC keyword
+
+    // unused variable warning
+    (void)paths;
+    EXPECT_ANY_THROW({
+        paths =
+            read.getFRUsByExpandedLocationCode(locationCode, fruLocationCode);
+    });
+}
+
+TEST_F(vpdManagerReaderTest, getFRUsByExpandedLocationCode_Valid_FC)
+{
+    // valid location code with FC kwd.
+    std::string validLocationCode = "U78DA.ND1.1234567-P0";
+
+    // Mock readBUsproperty call
+    MockUtilCalls uCalls;
+    EXPECT_CALL(uCalls,
+                readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VCEN", "FC"))
+        .WillRepeatedly(
+            testing::Return("78DAPQRS")); // return a dummy value for FC keyword
+
+    ReaderImpl read(uCalls);
+    ListOfPaths paths =
+        read.getFRUsByExpandedLocationCode(validLocationCode, fruLocationCode);
+
+    std::string expected =
+        "/xyz/openbmc_project/inventory/system/chassis/motherboard";
+    EXPECT_EQ(paths.at(0), expected);
+}
+
+TEST_F(vpdManagerReaderTest, getFRUsByExpandedLocationCode_Valid_TM)
+{
+    // valid location code with TM kwd.
+    std::string validLocationCode = "U9105.22A.SIMP10R";
+
+    // Mock readBUsproperty call
+    MockUtilCalls uCalls;
+    EXPECT_CALL(uCalls,
+                readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VCEN", "FC"))
+        .Times(1)
+        .WillOnce(
+            testing::Return("78DAPQRS")); // return a dummy value for FC keyword
+
+    EXPECT_CALL(uCalls,
+                readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VSYS", "TM"))
+        .Times(1)
+        .WillOnce(
+            testing::Return("9105PQRS")); // return a dummy value for TM keyword
+
+    ReaderImpl read(uCalls);
+    ListOfPaths paths =
+        read.getFRUsByExpandedLocationCode(validLocationCode, fruLocationCode);
+
+    std::string expected = "/xyz/openbmc_project/inventory/system";
+    EXPECT_EQ(paths.at(0), expected);
+}
+
+int main(int argc, char** argv)
+{
+    ::testing::InitGoogleTest(&argc, argv);
+
+    return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/test/vpd-manager-test/reader_test.hpp b/test/vpd-manager-test/reader_test.hpp
new file mode 100644
index 0000000..85d458f
--- /dev/null
+++ b/test/vpd-manager-test/reader_test.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "utilInterface.hpp"
+
+#include <gmock/gmock.h>
+
+using namespace openpower::vpd::utils::interface;
+
+class MockUtilCalls : public UtilityInterface
+{
+  public:
+    MOCK_METHOD(std::string, readBusProperty,
+                (const string& obj, const string& inf, const string& prop),
+                (override));
+};
diff --git a/test/vpd-manager-test/vpd_reader_test.json b/test/vpd-manager-test/vpd_reader_test.json
new file mode 100644
index 0000000..f74e05a
--- /dev/null
+++ b/test/vpd-manager-test/vpd_reader_test.json
@@ -0,0 +1,172 @@
+{
+  "commonInterfaces": {
+    "xyz.openbmc_project.Inventory.Decorator.Asset": {
+      "PartNumber": {
+        "recordName": "VINI",
+        "keywordName": "PN"
+      },
+      "SerialNumber": {
+        "recordName": "VINI",
+        "keywordName": "SN"
+      },
+      "BuildDate": {
+        "recordName": "VR10",
+        "keywordName": "DC",
+        "encoding": "DATE"
+      }
+    },
+    "xyz.openbmc_project.Inventory.Item": {
+      "PrettyName": {
+        "recordName": "VINI",
+        "keywordName": "DR"
+      },
+     "Present": true
+    }
+  },
+  "frus": {
+    "/sys/bus/i2c/drivers/at24/8-0050/eeprom": [
+      {
+        "inventoryPath": "/system/chassis/motherboard",
+        "isSystemVpd": true,
+        "extraInterfaces": {
+          "xyz.openbmc_project.Inventory.Item.Board.Motherboard": null,
+          "com.ibm.ipzvpd.Location" : {
+              "LocationCode" : "Ufcs-P0"
+          }
+        }
+      },
+      {
+        "inventoryPath": "/system",
+        "inherit": false,
+        "isSystemVpd": true,
+        "extraInterfaces": {
+          "xyz.openbmc_project.Inventory.Item.System": null,
+          "xyz.openbmc_project.Inventory.Decorator.Asset": {
+            "SerialNumber": {
+              "recordName": "VSYS",
+              "keywordName": "SE"
+            },
+            "Model": {
+              "recordName": "VSYS",
+              "keywordName": "TM"
+            }
+          },
+          "com.ibm.ipzvpd.Location" : {
+              "LocationCode" : "Umts"
+          }
+        }
+      },
+      {
+        "inventoryPath": "/system/chassis",
+        "inherit": false,
+        "isSystemVpd": true,
+        "extraInterfaces": {
+          "xyz.openbmc_project.Inventory.Item.Chassis": null,
+          "com.ibm.ipzvpd.Location" : {
+              "LocationCode" : "Ufcs"
+          }
+        }
+      }
+    ],
+    "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a480.i2c-bus/i2c-8/8-0051/8-00510/nvmem": [
+      {
+        "inventoryPath": "/system/chassis/motherboard/ebmc_card_bmc",
+        "extraInterfaces": {
+          "xyz.openbmc_project.Inventory.Item.Bmc": null,
+          "com.ibm.ipzvpd.Location" : {
+              "LocationCode" : "Ufcs-P0-C5"
+          }
+        }
+      },
+      {
+        "inventoryPath": "/system/chassis/motherboard/ebmc_card_bmc/ethernet0",
+        "inherit": false,
+        "extraInterfaces": {
+          "xyz.openbmc_project.Inventory.Item.Ethernet": null,
+          "com.ibm.ipzvpd.Location" : {
+              "LocationCode" : "Ufcs-P0-C5-T0"
+          },
+          "xyz.openbmc_project.Inventory.Item.NetworkInterface": {
+            "MACAddress": {
+              "recordName": "VCFG",
+              "keywordName": "Z0",
+              "encoding": "MAC"
+            }
+          }
+        }
+      },
+      {
+        "inventoryPath": "/system/chassis/motherboard/ebmc_card_bmc/ethernet1",
+        "inherit": false,
+        "extraInterfaces": {
+          "xyz.openbmc_project.Inventory.Item.Ethernet": null,
+          "com.ibm.ipzvpd.Location" : {
+              "LocationCode" : "Ufcs-P0-C5-T1"
+          },
+          "xyz.openbmc_project.Inventory.Item.NetworkInterface": {
+            "MACAddress": {
+              "recordName": "VCFG",
+              "keywordName": "Z1",
+              "encoding": "MAC"
+            }
+          }
+        }
+      }
+    ],
+    "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a080.i2c-bus/i2c-0/0-0051/0-00510/nvmem": [
+      {
+        "inventoryPath": "/system/chassis/motherboard/tpm_wilson",
+        "extraInterfaces": {
+          "xyz.openbmc_project.Inventory.Item.Tpm": null,
+          "com.ibm.ipzvpd.Location" : {
+              "LocationCode" : "Ufcs-P0-C22"
+          }
+        }
+      }
+    ],
+    "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a400.i2c-bus/i2c-7/7-0050/7-00500/nvmem": [
+      {
+        "inventoryPath": "/system/chassis/motherboard/base_op_panel_blyth",
+        "extraInterfaces": {
+          "xyz.openbmc_project.Inventory.Item.Panel": null,
+          "com.ibm.ipzvpd.Location" : {
+              "LocationCode" : "Ufcs-D0"
+          }
+        }
+      }
+    ],
+    "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a400.i2c-bus/i2c-7/7-0051/7-00510/nvmem": [
+      {
+        "inventoryPath": "/system/chassis/motherboard/lcd_op_panel_hill",
+        "extraInterfaces": {
+          "xyz.openbmc_project.Inventory.Item.Panel": null,
+          "com.ibm.ipzvpd.Location" : {
+              "LocationCode" : "Ufcs-D1"
+          }
+        }
+      }
+    ],
+    "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a500.i2c-bus/i2c-9/9-0050/9-00500/nvmem": [
+      {
+        "inventoryPath": "/system/chassis/motherboard/vdd_vrm0",
+        "extraInterfaces": {
+          "xyz.openbmc_project.Inventory.Item.Vrm": null,
+          "com.ibm.ipzvpd.Location" : {
+              "LocationCode" : "Ufcs-P0-C14"
+          }
+        }
+      }
+    ],
+    "/sys/devices/platform/ahb/ahb:apb/ahb:apb:bus@1e78a000/1e78a580.i2c-bus/i2c-10/10-0050/10-00500/nvmem": [
+      {
+        "inventoryPath": "/system/chassis/motherboard/vdd_vrm1",
+        "extraInterfaces": {
+          "xyz.openbmc_project.Inventory.Item.Vrm": null,
+          "com.ibm.ipzvpd.Location" : {
+              "LocationCode" : "Ufcs-P0-C23"
+          }
+        }
+      }
+    ]
+  }
+}
diff --git a/utilInterface.hpp b/utilInterface.hpp
new file mode 100644
index 0000000..4f6009b
--- /dev/null
+++ b/utilInterface.hpp
@@ -0,0 +1,44 @@
+#pragma once
+#include "utils.hpp"
+
+#include <string>
+
+namespace openpower
+{
+namespace vpd
+{
+namespace utils
+{
+namespace interface
+{
+
+class UtilityInterface
+{
+  public:
+    virtual ~UtilityInterface()
+    {
+    }
+
+    virtual std::string readBusProperty(const std::string& obj,
+                                        const std::string& inf,
+                                        const std::string& prop) = 0;
+};
+
+class utility : public UtilityInterface
+{
+  public:
+    virtual ~utility()
+    {
+    }
+
+    std::string readBusProperty(const std::string& obj, const std::string& inf,
+                                const std::string& prop) override
+    {
+        return readBusProperty(obj, inf, prop);
+    }
+};
+
+} // namespace interface
+} // namespace utils
+} // namespace vpd
+} // namespace openpower
diff --git a/vpd-manager/reader_impl.cpp b/vpd-manager/reader_impl.cpp
index f1b5c6b..4da02be 100644
--- a/vpd-manager/reader_impl.cpp
+++ b/vpd-manager/reader_impl.cpp
@@ -11,6 +11,10 @@
 #include <vector>
 #include <xyz/openbmc_project/Common/error.hpp>
 
+#ifdef ManagerTest
+#include "reader_test.hpp"
+#endif
+
 namespace openpower
 {
 namespace vpd
@@ -23,6 +27,7 @@
 using namespace phosphor::logging;
 using namespace openpower::vpd::inventory;
 using namespace openpower::vpd::constants;
+using namespace openpower::vpd::utils::interface;
 
 using InvalidArgument =
     sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument;
@@ -46,13 +51,14 @@
     const LocationCode& locationCode, const NodeNumber& nodeNumber,
     const LocationCodeMap& frusLocationCode) const
 {
+    // unused at this moment. Hence to avoid warnings
+    (void)nodeNumber;
     if (!isValidLocationCode(locationCode))
     {
         // argument is not valid
         elog<InvalidArgument>(Argument::ARGUMENT_NAME("LOCATIONCODE"),
                               Argument::ARGUMENT_VALUE(locationCode.c_str()));
     }
-
     auto iterator = frusLocationCode.find(locationCode);
     if (iterator == frusLocationCode.end())
     {
@@ -64,8 +70,12 @@
                               Argument::ARGUMENT_VALUE(locationCode.c_str()));
     }
 
-    std::string expandedLocationCode =
-        readBusProperty(iterator->second, LOCATION_CODE_INF, "LocationCode");
+    std::string expandedLocationCode{};
+#ifndef ManagerTest
+    utility utilObj;
+#endif
+    expandedLocationCode = utilObj.readBusProperty(
+        iterator->second, LOCATION_CODE_INF, "LocationCode");
     return expandedLocationCode;
 }
 
@@ -74,6 +84,9 @@
                                   const NodeNumber& nodeNumber,
                                   const LocationCodeMap& frusLocationCode) const
 {
+    // unused at this moment, to avoid compilation warning
+    (void)nodeNumber;
+
     // TODO:Implementation related to node number
     if (!isValidLocationCode(locationCode))
     {
@@ -116,8 +129,12 @@
                               Argument::ARGUMENT_VALUE(locationCode.c_str()));
     }
 
-    std::string fc =
-        readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VCEN", "FC");
+    std::string fc{};
+#ifndef ManagerTest
+    utility utilObj;
+#endif
+
+    fc = utilObj.readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VCEN", "FC");
 
     // get the first part of expanded location code to check for FC or TM
     std::string firstKeyword = locationCode.substr(1, 4);
@@ -169,9 +186,11 @@
     }
     else
     {
+        std::string tm{};
         // read TM kwd value
-        std::string tm =
-            readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VSYS", "TM");
+        tm =
+            utilObj.readBusProperty(SYSTEM_OBJECT, "com.ibm.ipzvpd.VSYS", "TM");
+        ;
 
         // check if the substr matches to TM kwd
         if (tm.substr(0, 4) ==
diff --git a/vpd-manager/reader_impl.hpp b/vpd-manager/reader_impl.hpp
index dab8b8e..4de3c9b 100644
--- a/vpd-manager/reader_impl.hpp
+++ b/vpd-manager/reader_impl.hpp
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "types.hpp"
+#include "utilInterface.hpp"
 
 namespace openpower
 {
@@ -11,6 +12,7 @@
 namespace reader
 {
 
+using IUtil = openpower::vpd::utils::interface::UtilityInterface;
 /** @class ReaderImpl
  *  @brief Implements functionalities related to reading of VPD related data
  *  from the system.
@@ -19,12 +21,18 @@
 {
   public:
     ReaderImpl() = default;
-    ReaderImpl(const ReaderImpl&) = delete;
+    ReaderImpl(const ReaderImpl&) = default;
     ReaderImpl& operator=(const ReaderImpl&) = delete;
-    ReaderImpl(ReaderImpl&&) = delete;
+    ReaderImpl(ReaderImpl&&) = default;
     ReaderImpl& operator=(ReaderImpl&&) = delete;
     ~ReaderImpl() = default;
 
+#ifdef ManagerTest
+    explicit ReaderImpl(IUtil& obj) : utilObj(obj)
+    {
+    }
+#endif
+
     /** @brief An API to expand a given unexpanded location code.
      *  @param[in] locationCode - unexpanded location code.
      *  @param[in] nodeNumber - node on which we are looking for location code.
@@ -72,6 +80,9 @@
     std::tuple<inventory::LocationCode, inventory::NodeNumber>
         getCollapsedLocationCode(
             const inventory::LocationCode& locationCode) const;
+#ifdef ManagerTest
+    IUtil& utilObj;
+#endif
 
 }; // class ReaderImpl