mainloop: Make HwmonIO injectable dependency

HwmonIO was make into a interface object implementation.  This patch
transitions mainloop to receive a pointer to this interface to allow for
injection testing.

Signed-off-by: Patrick Venture <venture@google.com>
Change-Id: Iaa470fafccb42c4d7fbabac0dc92f96c8075faf2
diff --git a/hwmonio.hpp b/hwmonio.hpp
index f0c7248..b0b8617 100644
--- a/hwmonio.hpp
+++ b/hwmonio.hpp
@@ -109,6 +109,7 @@
   private:
     std::string _p;
 };
+
 } // namespace hwmonio
 
 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
diff --git a/mainloop.cpp b/mainloop.cpp
index 469a8d7..a5a818f 100644
--- a/mainloop.cpp
+++ b/mainloop.cpp
@@ -150,7 +150,7 @@
 
     /* Note: The sensor objects all share the same ioAccess object. */
     auto sensorObj =
-        std::make_unique<sensor::Sensor>(sensor.first, &_ioAccess, _devPath);
+        std::make_unique<sensor::Sensor>(sensor.first, _ioAccess, _devPath);
 
     // Get list of return codes for removing sensors on device
     auto devRmRCs = env::getEnv("REMOVERCS");
@@ -181,7 +181,7 @@
     catch (const std::system_error& e)
     {
         auto file =
-            sysfs::make_sysfs_path(_ioAccess.path(), sensor.first.first,
+            sysfs::make_sysfs_path(_ioAccess->path(), sensor.first.first,
                                    sensor.first.second, hwmon::entry::cinput);
 #ifndef REMOVE_ON_FAIL
         // Check sensorAdjusts for sensor removal RCs
@@ -250,11 +250,12 @@
 
 MainLoop::MainLoop(sdbusplus::bus::bus&& bus, const std::string& param,
                    const std::string& path, const std::string& devPath,
-                   const char* prefix, const char* root) :
+                   const char* prefix, const char* root,
+                   const hwmonio::HwmonIOInterface* ioIntf) :
     _bus(std::move(bus)),
     _manager(_bus, root), _pathParam(param), _hwmonRoot(), _instance(),
-    _devPath(devPath), _prefix(prefix), _root(root), _state(), _ioAccess(path),
-    _event(sdeventplus::Event::get_default()),
+    _devPath(devPath), _prefix(prefix), _root(root), _state(),
+    _ioAccess(ioIntf), _event(sdeventplus::Event::get_default()),
     _timer(_event, std::bind(&MainLoop::read, this))
 {
     // Strip off any trailing slashes.
@@ -380,7 +381,7 @@
                 auto it = obj.find(InterfaceType::STATUS);
                 if (it != obj.end())
                 {
-                    auto fault = _ioAccess.read(
+                    auto fault = _ioAccess->read(
                         i.first.first, i.first.second, hwmon::entry::fault,
                         hwmonio::retries, hwmonio::delay);
                     auto statusIface =
@@ -401,8 +402,9 @@
                     // RAII object for GPIO unlock / lock
                     sensor::GpioLock gpioLock(sensor->getGpio());
 
-                    value = _ioAccess.read(i.first.first, i.first.second, input,
-                                           hwmonio::retries, hwmonio::delay);
+                    value =
+                        _ioAccess->read(i.first.first, i.first.second, input,
+                                        hwmonio::retries, hwmonio::delay);
 
                     value = sensor->adjustValue(value);
                 }
@@ -436,7 +438,7 @@
             catch (const std::system_error& e)
             {
                 auto file = sysfs::make_sysfs_path(
-                    _ioAccess.path(), i.first.first, i.first.second,
+                    _ioAccess->path(), i.first.first, i.first.second,
                     hwmon::entry::cinput);
 #ifndef REMOVE_ON_FAIL
                 // Check sensorAdjusts for sensor removal RCs
@@ -526,7 +528,7 @@
 
                 // Sensor object added, erase entry from removal list
                 auto file = sysfs::make_sysfs_path(
-                    _ioAccess.path(), it->first.first, it->first.second,
+                    _ioAccess->path(), it->first.first, it->first.second,
                     hwmon::entry::cinput);
 
                 log<level::INFO>("Added sensor to dbus after successful read",
diff --git a/mainloop.hpp b/mainloop.hpp
index a50020d..07128b5 100644
--- a/mainloop.hpp
+++ b/mainloop.hpp
@@ -53,7 +53,8 @@
      */
     MainLoop(sdbusplus::bus::bus&& bus, const std::string& param,
              const std::string& path, const std::string& devPath,
-             const char* prefix, const char* root);
+             const char* prefix, const char* root,
+             const hwmonio::HwmonIOInterface* ioIntf);
 
     /** @brief Setup polling timer in a sd event loop and attach to D-Bus
      *         event loop.
@@ -106,7 +107,7 @@
     /** @brief Sleep interval in microseconds. */
     uint64_t _interval = default_interval;
     /** @brief Hwmon sysfs access. */
-    hwmonio::HwmonIO _ioAccess;
+    const hwmonio::HwmonIOInterface* _ioAccess;
     /** @brief the Event Loop structure */
     sdeventplus::Event _event;
     /** @brief Read Timer */
diff --git a/readd.cpp b/readd.cpp
index 7ac95fc..cba043e 100644
--- a/readd.cpp
+++ b/readd.cpp
@@ -15,6 +15,7 @@
  */
 #include "config.h"
 
+#include "hwmonio.hpp"
 #include "mainloop.hpp"
 #include "sysfs.hpp"
 
@@ -77,8 +78,9 @@
                         "Unable to determine callout path.");
     }
 
+    hwmonio::HwmonIO io(path);
     MainLoop loop(sdbusplus::bus::new_default(), param, path, calloutPath,
-                  BUSNAME_PREFIX, SENSOR_ROOT);
+                  BUSNAME_PREFIX, SENSOR_ROOT, &io);
     loop.run();
 
     return 0;
diff --git a/targets.hpp b/targets.hpp
index a954394..ffdb476 100644
--- a/targets.hpp
+++ b/targets.hpp
@@ -64,7 +64,7 @@
  */
 template <typename T>
 std::shared_ptr<T> addTarget(const SensorSet::key_type& sensor,
-                             const hwmonio::HwmonIO& ioAccess,
+                             const hwmonio::HwmonIOInterface* ioAccess,
                              const std::string& devPath, ObjectInfo& info)
 {
     std::shared_ptr<T> target;
@@ -97,7 +97,7 @@
     }
 
     sysfsFullPath =
-        sysfs::make_sysfs_path(ioAccess.path(), targetName, targetId, entry);
+        sysfs::make_sysfs_path(ioAccess->path(), targetName, targetId, entry);
     if (fs::exists(sysfsFullPath))
     {
         auto useTarget = true;
@@ -137,8 +137,8 @@
 
             try
             {
-                targetSpeed = ioAccess.read(targetName, targetId, entry,
-                                            hwmonio::retries, hwmonio::delay);
+                targetSpeed = ioAccess->read(targetName, targetId, entry,
+                                             hwmonio::retries, hwmonio::delay);
             }
             catch (const std::system_error& e)
             {
@@ -160,9 +160,11 @@
             static constexpr bool deferSignals = true;
             auto& bus = *std::get<sdbusplus::bus::bus*>(info);
 
-            // ioAccess.path() is a path like: /sys/class/hwmon/hwmon1
+            // ioAccess->path() is a path like: /sys/class/hwmon/hwmon1
+            // NOTE: When unit-testing, the target won't have an inject-ible
+            // ioAccess: fan_pwm/fan_speed.
             target = std::make_shared<T>(
-                std::move(std::make_unique<hwmonio::HwmonIO>(ioAccess.path())),
+                std::move(std::make_unique<hwmonio::HwmonIO>(ioAccess->path())),
                 devPath, targetId, bus, objPath.c_str(), deferSignals,
                 targetSpeed);
             obj[type] = target;