regulators: Add remaining props to Device class

Enhance the C++ Device class by adding the remaining properties from the
JSON config file:
* presence_detection
* configuration
* rails

See device.md for more information.

Signed-off-by: Shawn McCarney <shawnmm@us.ibm.com>
Change-Id: Id5973da1e0f4f73145f0eb0d34a4c157e828b06e
diff --git a/phosphor-regulators/src/device.hpp b/phosphor-regulators/src/device.hpp
index b4c2af6..f7ad179 100644
--- a/phosphor-regulators/src/device.hpp
+++ b/phosphor-regulators/src/device.hpp
@@ -15,11 +15,15 @@
  */
 #pragma once
 
+#include "configuration.hpp"
 #include "i2c_interface.hpp"
+#include "presence_detection.hpp"
+#include "rail.hpp"
 
 #include <memory>
 #include <string>
 #include <utility>
+#include <vector>
 
 namespace phosphor::power::regulators
 {
@@ -47,34 +51,35 @@
      * @param isRegulator indicates whether this device is a voltage regulator
      * @param fru Field-Replaceable Unit (FRU) for this device
      * @param i2cInterface I2C interface to this device
+     * @param presenceDetection presence detection for this device, if any
+     * @param configuration configuration changes to apply to this device, if
+     *                      any
+     * @param rails voltage rails produced by this device, if any
      */
-    explicit Device(const std::string& id, bool isRegulator,
-                    const std::string& fru,
-                    std::unique_ptr<i2c::I2CInterface> i2cInterface) :
+    explicit Device(
+        const std::string& id, bool isRegulator, const std::string& fru,
+        std::unique_ptr<i2c::I2CInterface> i2cInterface,
+        std::unique_ptr<PresenceDetection> presenceDetection = nullptr,
+        std::unique_ptr<Configuration> configuration = nullptr,
+        std::vector<std::unique_ptr<Rail>> rails =
+            std::vector<std::unique_ptr<Rail>>{}) :
         id{id},
-        isRegulatorDevice{isRegulator}, fru{fru}, i2cInterface{
-                                                      std::move(i2cInterface)}
+        isRegulatorDevice{isRegulator}, fru{fru},
+        i2cInterface{std::move(i2cInterface)}, presenceDetection{std::move(
+                                                   presenceDetection)},
+        configuration{std::move(configuration)}, rails{std::move(rails)}
     {
     }
 
     /**
-     * Returns the unique ID of this device.
+     * Returns the configuration changes to apply to this device, if any.
      *
-     * @return device ID
+     * @return Pointer to Configuration object.  Will equal nullptr if no
+     *         configuration changes are defined for this device.
      */
-    const std::string& getID() const
+    const std::unique_ptr<Configuration>& getConfiguration() const
     {
-        return id;
-    }
-
-    /**
-     * Returns whether this device is a voltage regulator.
-     *
-     * @return true if device is a voltage regulator, false otherwise
-     */
-    bool isRegulator() const
-    {
-        return isRegulatorDevice;
+        return configuration;
     }
 
     /**
@@ -91,7 +96,7 @@
     }
 
     /**
-     * Gets the I2C interface to this device.
+     * Returns the I2C interface to this device.
      *
      * @return I2C interface to device
      */
@@ -100,6 +105,47 @@
         return *i2cInterface;
     }
 
+    /**
+     * Returns the unique ID of this device.
+     *
+     * @return device ID
+     */
+    const std::string& getID() const
+    {
+        return id;
+    }
+
+    /**
+     * Returns the presence detection for this device, if any.
+     *
+     * @return Pointer to PresenceDetection object.  Will equal nullptr if no
+     *         presence detection is defined for this device.
+     */
+    const std::unique_ptr<PresenceDetection>& getPresenceDetection() const
+    {
+        return presenceDetection;
+    }
+
+    /**
+     * Returns the voltage rails produced by this device, if any.
+     *
+     * @return voltage rails
+     */
+    const std::vector<std::unique_ptr<Rail>>& getRails() const
+    {
+        return rails;
+    }
+
+    /**
+     * Returns whether this device is a voltage regulator.
+     *
+     * @return true if device is a voltage regulator, false otherwise
+     */
+    bool isRegulator() const
+    {
+        return isRegulatorDevice;
+    }
+
   private:
     /**
      * Unique ID of this device.
@@ -123,6 +169,24 @@
      * I2C interface to this device.
      */
     std::unique_ptr<i2c::I2CInterface> i2cInterface{};
+
+    /**
+     * Presence detection for this device, if any.  Set to nullptr if no
+     * presence detection is defined for this device.
+     */
+    std::unique_ptr<PresenceDetection> presenceDetection{};
+
+    /**
+     * Configuration changes to apply to this device, if any.  Set to nullptr if
+     * no configuration changes are defined for this device.
+     */
+    std::unique_ptr<Configuration> configuration{};
+
+    /**
+     * Voltage rails produced by this device, if any.  Vector is empty if no
+     * voltage rails are defined for this device.
+     */
+    std::vector<std::unique_ptr<Rail>> rails{};
 };
 
 } // namespace phosphor::power::regulators
diff --git a/phosphor-regulators/test/device_tests.cpp b/phosphor-regulators/test/device_tests.cpp
index fb92fd7..955e6d8 100644
--- a/phosphor-regulators/test/device_tests.cpp
+++ b/phosphor-regulators/test/device_tests.cpp
@@ -13,12 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include "action.hpp"
+#include "configuration.hpp"
 #include "device.hpp"
 #include "i2c_interface.hpp"
-#include "mocked_i2c_interface.hpp"
+#include "mock_action.hpp"
+#include "presence_detection.hpp"
+#include "rail.hpp"
 
 #include <memory>
+#include <optional>
 #include <utility>
+#include <vector>
 
 #include <gtest/gtest.h>
 
@@ -38,28 +44,100 @@
 
 TEST(DeviceTests, Constructor)
 {
-    std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
-    i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
-    Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
-                  std::move(i2cInterface)};
-    EXPECT_EQ(device.getID(), "vdd_reg");
-    EXPECT_EQ(device.isRegulator(), true);
-    EXPECT_EQ(device.getFRU(), "/system/chassis/motherboard/reg2");
-    EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
+    // Test where only required parameters are specified
+    {
+        std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
+        i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
+        Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
+                      std::move(i2cInterface)};
+        EXPECT_EQ(device.getID(), "vdd_reg");
+        EXPECT_EQ(device.isRegulator(), true);
+        EXPECT_EQ(device.getFRU(), "/system/chassis/motherboard/reg2");
+        EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
+        EXPECT_EQ(device.getPresenceDetection(), nullptr);
+        EXPECT_EQ(device.getConfiguration(), nullptr);
+        EXPECT_EQ(device.getRails().size(), 0);
+    }
+
+    // Test where all parameters are specified
+    {
+        // Create I2CInterface
+        std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
+        i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
+
+        // Create PresenceDetection
+        std::vector<std::unique_ptr<Action>> actions{};
+        actions.push_back(std::make_unique<MockAction>());
+        std::unique_ptr<PresenceDetection> presenceDetection =
+            std::make_unique<PresenceDetection>(std::move(actions));
+
+        // Create Configuration
+        std::optional<double> volts{};
+        actions.clear();
+        actions.push_back(std::make_unique<MockAction>());
+        actions.push_back(std::make_unique<MockAction>());
+        std::unique_ptr<Configuration> configuration =
+            std::make_unique<Configuration>(volts, std::move(actions));
+
+        // Create vector of Rail objects
+        std::vector<std::unique_ptr<Rail>> rails{};
+        rails.push_back(std::make_unique<Rail>("vdd0"));
+        rails.push_back(std::make_unique<Rail>("vdd1"));
+
+        // Create Device
+        Device device{"vdd_reg",
+                      false,
+                      "/system/chassis/motherboard/reg1",
+                      std::move(i2cInterface),
+                      std::move(presenceDetection),
+                      std::move(configuration),
+                      std::move(rails)};
+        EXPECT_EQ(device.getID(), "vdd_reg");
+        EXPECT_EQ(device.isRegulator(), false);
+        EXPECT_EQ(device.getFRU(), "/system/chassis/motherboard/reg1");
+        EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
+        EXPECT_NE(device.getPresenceDetection(), nullptr);
+        EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1);
+        EXPECT_NE(device.getConfiguration(), nullptr);
+        EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), false);
+        EXPECT_EQ(device.getConfiguration()->getActions().size(), 2);
+        EXPECT_EQ(device.getRails().size(), 2);
+    }
 }
 
-TEST(DeviceTests, GetID)
+TEST(DeviceTests, GetConfiguration)
 {
-    Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2",
-                  std::move(createI2CInterface())};
-    EXPECT_EQ(device.getID(), "vdd_reg");
-}
+    // Test where Configuration was not specified in constructor
+    {
+        Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
+                      std::move(createI2CInterface())};
+        EXPECT_EQ(device.getConfiguration(), nullptr);
+    }
 
-TEST(DeviceTests, IsRegulator)
-{
-    Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2",
-                  std::move(createI2CInterface())};
-    EXPECT_EQ(device.isRegulator(), false);
+    // Test where Configuration was specified in constructor
+    {
+        std::unique_ptr<PresenceDetection> presenceDetection{};
+
+        // Create Configuration
+        std::optional<double> volts{3.2};
+        std::vector<std::unique_ptr<Action>> actions{};
+        actions.push_back(std::make_unique<MockAction>());
+        actions.push_back(std::make_unique<MockAction>());
+        std::unique_ptr<Configuration> configuration =
+            std::make_unique<Configuration>(volts, std::move(actions));
+
+        // Create Device
+        Device device{"vdd_reg",
+                      true,
+                      "/system/chassis/motherboard/reg2",
+                      std::move(createI2CInterface()),
+                      std::move(presenceDetection),
+                      std::move(configuration)};
+        EXPECT_NE(device.getConfiguration(), nullptr);
+        EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), true);
+        EXPECT_EQ(device.getConfiguration()->getVolts().value(), 3.2);
+        EXPECT_EQ(device.getConfiguration()->getActions().size(), 2);
+    }
 }
 
 TEST(DeviceTests, GetFRU)
@@ -77,3 +155,76 @@
                   std::move(i2cInterface)};
     EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
 }
+
+TEST(DeviceTests, GetID)
+{
+    Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2",
+                  std::move(createI2CInterface())};
+    EXPECT_EQ(device.getID(), "vdd_reg");
+}
+
+TEST(DeviceTests, GetPresenceDetection)
+{
+    // Test where PresenceDetection was not specified in constructor
+    {
+        Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
+                      std::move(createI2CInterface())};
+        EXPECT_EQ(device.getPresenceDetection(), nullptr);
+    }
+
+    // Test where PresenceDetection was specified in constructor
+    {
+        // Create PresenceDetection
+        std::vector<std::unique_ptr<Action>> actions{};
+        actions.push_back(std::make_unique<MockAction>());
+        std::unique_ptr<PresenceDetection> presenceDetection =
+            std::make_unique<PresenceDetection>(std::move(actions));
+
+        // Create Device
+        Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2",
+                      std::move(createI2CInterface()),
+                      std::move(presenceDetection)};
+        EXPECT_NE(device.getPresenceDetection(), nullptr);
+        EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1);
+    }
+}
+
+TEST(DeviceTests, GetRails)
+{
+    // Test where no rails were specified in constructor
+    {
+        Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
+                      std::move(createI2CInterface())};
+        EXPECT_EQ(device.getRails().size(), 0);
+    }
+
+    // Test where rails were specified in constructor
+    {
+        std::unique_ptr<PresenceDetection> presenceDetection{};
+        std::unique_ptr<Configuration> configuration{};
+
+        // Create vector of Rail objects
+        std::vector<std::unique_ptr<Rail>> rails{};
+        rails.push_back(std::make_unique<Rail>("vdd0"));
+        rails.push_back(std::make_unique<Rail>("vdd1"));
+
+        // Create Device
+        Device device{"vdd_reg",
+                      false,
+                      "/system/chassis/motherboard/reg2",
+                      std::move(createI2CInterface()),
+                      std::move(presenceDetection),
+                      std::move(configuration),
+                      std::move(rails)};
+        EXPECT_EQ(device.getRails().size(), 2);
+        EXPECT_EQ(device.getRails()[0]->getID(), "vdd0");
+        EXPECT_EQ(device.getRails()[1]->getID(), "vdd1");
+    }
+}
+
+TEST(DeviceTests, IsRegulator)
+{
+    Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2",
+                  std::move(createI2CInterface())};
+    EXPECT_EQ(device.isRegulator(), false);
+}