regulators: Add remaining properties to Rail class

Enhance the C++ Rail class by adding the remaining properties from the
JSON config file:
* configuration
* sensor_monitoring

See rail.md for more information.

Signed-off-by: Shawn McCarney <shawnmm@us.ibm.com>
Change-Id: I9c2e46fe8bec39454b0ad3f703eee3b497efd82a
diff --git a/phosphor-regulators/src/rail.hpp b/phosphor-regulators/src/rail.hpp
index 247e8ee..19e8a58 100644
--- a/phosphor-regulators/src/rail.hpp
+++ b/phosphor-regulators/src/rail.hpp
@@ -15,7 +15,12 @@
  */
 #pragma once
 
+#include "configuration.hpp"
+#include "sensor_monitoring.hpp"
+
+#include <memory>
 #include <string>
+#include <utility>
 
 namespace phosphor::power::regulators
 {
@@ -43,12 +48,31 @@
      * Constructor.
      *
      * @param id unique rail ID
+     * @param configuration configuration changes to apply to this rail, if any
+     * @param sensorMonitoring sensor monitoring for this rail, if any
      */
-    explicit Rail(const std::string& id) : id{id}
+    explicit Rail(
+        const std::string& id,
+        std::unique_ptr<Configuration> configuration = nullptr,
+        std::unique_ptr<SensorMonitoring> sensorMonitoring = nullptr) :
+        id{id},
+        configuration{std::move(configuration)}, sensorMonitoring{std::move(
+                                                     sensorMonitoring)}
     {
     }
 
     /**
+     * Returns the configuration changes to apply to this rail, if any.
+     *
+     * @return Pointer to Configuration object.  Will equal nullptr if no
+     *         configuration changes are defined for this rail.
+     */
+    const std::unique_ptr<Configuration>& getConfiguration() const
+    {
+        return configuration;
+    }
+
+    /**
      * Returns the unique ID of this rail.
      *
      * @return rail ID
@@ -58,11 +82,34 @@
         return id;
     }
 
+    /**
+     * Returns the sensor monitoring for this rail, if any.
+     *
+     * @return Pointer to SensorMonitoring object.  Will equal nullptr if no
+     *         sensor monitoring is defined for this rail.
+     */
+    const std::unique_ptr<SensorMonitoring>& getSensorMonitoring() const
+    {
+        return sensorMonitoring;
+    }
+
   private:
     /**
      * Unique ID of this rail.
      */
     const std::string id{};
+
+    /**
+     * Configuration changes to apply to this rail, if any.  Set to nullptr if
+     * no configuration changes are defined for this rail.
+     */
+    std::unique_ptr<Configuration> configuration{};
+
+    /**
+     * Sensor monitoring for this rail, if any.  Set to nullptr if no sensor
+     * monitoring is defined for this rail.
+     */
+    std::unique_ptr<SensorMonitoring> sensorMonitoring{};
 };
 
 } // namespace phosphor::power::regulators
diff --git a/phosphor-regulators/test/rail_tests.cpp b/phosphor-regulators/test/rail_tests.cpp
index d5722fd..a12211d 100644
--- a/phosphor-regulators/test/rail_tests.cpp
+++ b/phosphor-regulators/test/rail_tests.cpp
@@ -13,7 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include "action.hpp"
+#include "configuration.hpp"
+#include "mock_action.hpp"
 #include "rail.hpp"
+#include "sensor_monitoring.hpp"
+
+#include <memory>
+#include <optional>
+#include <utility>
+#include <vector>
 
 #include <gtest/gtest.h>
 
@@ -21,12 +30,98 @@
 
 TEST(RailTests, Constructor)
 {
-    Rail rail("vdd0");
-    EXPECT_EQ(rail.getID(), "vdd0");
+    // Test where only required parameters are specified
+    {
+        Rail rail{"vdd0"};
+        EXPECT_EQ(rail.getID(), "vdd0");
+        EXPECT_EQ(rail.getConfiguration(), nullptr);
+        EXPECT_EQ(rail.getSensorMonitoring(), nullptr);
+    }
+
+    // Test where all parameters are specified
+    {
+        // Create Configuration
+        std::optional<double> volts{1.3};
+        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 SensorMonitoring
+        actions.clear();
+        actions.push_back(std::make_unique<MockAction>());
+        std::unique_ptr<SensorMonitoring> sensorMonitoring =
+            std::make_unique<SensorMonitoring>(std::move(actions));
+
+        // Create Rail
+        Rail rail{"vddr1", std::move(configuration),
+                  std::move(sensorMonitoring)};
+        EXPECT_EQ(rail.getID(), "vddr1");
+        EXPECT_NE(rail.getConfiguration(), nullptr);
+        EXPECT_EQ(rail.getConfiguration()->getVolts().has_value(), true);
+        EXPECT_EQ(rail.getConfiguration()->getVolts().value(), 1.3);
+        EXPECT_EQ(rail.getConfiguration()->getActions().size(), 2);
+        EXPECT_NE(rail.getSensorMonitoring(), nullptr);
+        EXPECT_EQ(rail.getSensorMonitoring()->getActions().size(), 1);
+    }
+}
+
+TEST(RailTests, GetConfiguration)
+{
+    // Test where Configuration was not specified in constructor
+    {
+        Rail rail{"vdd0"};
+        EXPECT_EQ(rail.getConfiguration(), nullptr);
+    }
+
+    // Test where Configuration was specified in constructor
+    {
+        // Create Configuration
+        std::optional<double> volts{3.2};
+        std::vector<std::unique_ptr<Action>> actions{};
+        actions.push_back(std::make_unique<MockAction>());
+        std::unique_ptr<Configuration> configuration =
+            std::make_unique<Configuration>(volts, std::move(actions));
+
+        // Create Rail
+        Rail rail{"vddr1", std::move(configuration)};
+        EXPECT_NE(rail.getConfiguration(), nullptr);
+        EXPECT_EQ(rail.getConfiguration()->getVolts().has_value(), true);
+        EXPECT_EQ(rail.getConfiguration()->getVolts().value(), 3.2);
+        EXPECT_EQ(rail.getConfiguration()->getActions().size(), 1);
+    }
 }
 
 TEST(RailTests, GetID)
 {
-    Rail rail("vio2");
+    Rail rail{"vio2"};
     EXPECT_EQ(rail.getID(), "vio2");
 }
+
+TEST(RailTests, GetSensorMonitoring)
+{
+    // Test where SensorMonitoring was not specified in constructor
+    {
+        Rail rail{"vdd0", nullptr, nullptr};
+        EXPECT_EQ(rail.getSensorMonitoring(), nullptr);
+    }
+
+    // Test where SensorMonitoring was specified in constructor
+    {
+        std::unique_ptr<Configuration> configuration{};
+
+        // Create SensorMonitoring
+        std::vector<std::unique_ptr<Action>> actions{};
+        actions.push_back(std::make_unique<MockAction>());
+        actions.push_back(std::make_unique<MockAction>());
+        std::unique_ptr<SensorMonitoring> sensorMonitoring =
+            std::make_unique<SensorMonitoring>(std::move(actions));
+
+        // Create Rail
+        Rail rail{"vddr1", std::move(configuration),
+                  std::move(sensorMonitoring)};
+        EXPECT_NE(rail.getSensorMonitoring(), nullptr);
+        EXPECT_EQ(rail.getSensorMonitoring()->getActions().size(), 2);
+    }
+}