added property SupportedOperationTypes

- removed OperationType::single
- for backward compatibility incomming OperationType::single alted to
  produce same output functionality
- added property SupportedOperationTypes to ReportManager interface

Tested:
- In cases where OperationType::single is used same MetricValues are
  produced
- New property is visible on dbus

Change-Id: I838581c954abc0d8401e0ed530ce7e9c8013860b
Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
diff --git a/src/details/collection_function.cpp b/src/details/collection_function.cpp
index 360f082..5134b0e 100644
--- a/src/details/collection_function.cpp
+++ b/src/details/collection_function.cpp
@@ -5,23 +5,6 @@
 namespace details
 {
 
-class FunctionSingle : public CollectionFunction
-{
-  public:
-    double calculate(const std::vector<ReadingItem>& readings,
-                     Milliseconds) const override
-    {
-        return readings.back().second;
-    }
-
-    double calculateForStartupInterval(std::vector<ReadingItem>& readings,
-                                       Milliseconds) const override
-    {
-        readings.assign({readings.back()});
-        return readings.back().second;
-    }
-};
-
 class FunctionMinimum : public CollectionFunction
 {
   public:
@@ -175,8 +158,6 @@
 
     switch (operationType)
     {
-        case OperationType::single:
-            return std::make_shared<FunctionSingle>();
         case OperationType::min:
             return std::make_shared<FunctionMinimum>();
         case OperationType::max:
diff --git a/src/report_factory.cpp b/src/report_factory.cpp
index df71fa0..261fc75 100644
--- a/src/report_factory.cpp
+++ b/src/report_factory.cpp
@@ -97,6 +97,12 @@
         {
             operationType = utils::enumToString(OperationType::avg);
         }
+        else if (operationType == "SINGLE")
+        {
+            operationType = utils::enumToString(OperationType::avg);
+            collectionTimeScope =
+                utils::enumToString(CollectionTimeScope::point);
+        }
 
         if (collectionTimeScope.empty())
         {
diff --git a/src/report_manager.cpp b/src/report_manager.cpp
index df60075..31363c4 100644
--- a/src/report_manager.cpp
+++ b/src/report_manager.cpp
@@ -52,6 +52,15 @@
             dbusIface.register_property_r(
                 "MinInterval", uint64_t{}, sdbusplus::vtable::property_::const_,
                 [](const auto&) -> uint64_t { return minInterval.count(); });
+            dbusIface.register_property_r(
+                "SupportedOperationTypes", std::vector<std::string>{},
+                sdbusplus::vtable::property_::const_,
+                [](const auto&) -> std::vector<std::string> {
+                    return utils::transform<std::vector<std::string>>(
+                        utils::convDataOperationType, [](const auto& item) {
+                            return std::string(item.first);
+                        });
+                });
 
             dbusIface.register_method(
                 "AddReport", [this](boost::asio::yield_context& yield,
diff --git a/src/types/operation_type.hpp b/src/types/operation_type.hpp
index 29bceb4..6d19620 100644
--- a/src/types/operation_type.hpp
+++ b/src/types/operation_type.hpp
@@ -8,7 +8,6 @@
 
 enum class OperationType : uint32_t
 {
-    single,
     max,
     min,
     avg,
@@ -18,18 +17,15 @@
 namespace utils
 {
 
-constexpr std::array<std::pair<std::string_view, OperationType>, 5>
-    convDataOperationType = {
-        {std::make_pair<std::string_view, OperationType>("SINGLE",
-                                                         OperationType::single),
-         std::make_pair<std::string_view, OperationType>("Maximum",
-                                                         OperationType::max),
-         std::make_pair<std::string_view, OperationType>("Minimum",
-                                                         OperationType::min),
-         std::make_pair<std::string_view, OperationType>("Average",
-                                                         OperationType::avg),
-         std::make_pair<std::string_view, OperationType>("Summation",
-                                                         OperationType::sum)}};
+constexpr std::array<std::pair<std::string_view, OperationType>, 4>
+    convDataOperationType = {{std::make_pair<std::string_view, OperationType>(
+                                  "Maximum", OperationType::max),
+                              std::make_pair<std::string_view, OperationType>(
+                                  "Minimum", OperationType::min),
+                              std::make_pair<std::string_view, OperationType>(
+                                  "Average", OperationType::avg),
+                              std::make_pair<std::string_view, OperationType>(
+                                  "Summation", OperationType::sum)}};
 
 inline OperationType
     toOperationType(std::underlying_type_t<OperationType> value)
diff --git a/src/utils/transform.hpp b/src/utils/transform.hpp
index b354b0f..4a28950 100644
--- a/src/utils/transform.hpp
+++ b/src/utils/transform.hpp
@@ -9,34 +9,19 @@
 {
 
 template <class T>
-struct has_member_reserve
+concept has_member_reserve = requires(T t)
 {
-    template <class U>
-    static U& ref();
-
-    template <class U>
-    static std::true_type check(decltype(ref<U>().reserve(size_t{}))*);
-
-    template <class>
-    static std::false_type check(...);
-
-    static constexpr bool value =
-        decltype(check<std::decay_t<T>>(nullptr))::value;
+    t.reserve(size_t{});
 };
 
-template <class T>
-constexpr bool has_member_reserve_v = has_member_reserve<T>::value;
-
 } // namespace detail
 
-template <template <class, class...> class Container, class T, class... Args,
-          class F>
-auto transform(const Container<T, Args...>& container, F&& functor)
+template <class R, class Container, class F>
+auto transform(const Container& container, F&& functor)
 {
-    using R = decltype(functor(*container.begin()));
+    auto result = R{};
 
-    Container<R> result;
-    if constexpr (detail::has_member_reserve_v<Container<T, Args...>>)
+    if constexpr (detail::has_member_reserve<decltype(result)>)
     {
         result.reserve(container.size());
     }
@@ -46,4 +31,12 @@
     return result;
 }
 
+template <template <class, class...> class Container, class T, class... Args,
+          class F>
+auto transform(const Container<T, Args...>& container, F&& functor)
+{
+    using R = Container<decltype(functor(*container.begin()))>;
+    return transform<R>(container, std::forward<F>(functor));
+}
+
 } // namespace utils
diff --git a/tests/src/params/report_params.hpp b/tests/src/params/report_params.hpp
index 19ea519..56f619a 100644
--- a/tests/src/params/report_params.hpp
+++ b/tests/src/params/report_params.hpp
@@ -121,7 +121,7 @@
              {LabeledSensorInfo{"Service",
                                 "/xyz/openbmc_project/sensors/power/p1",
                                 "metadata1"}},
-             OperationType::single,
+             OperationType::avg,
              "MetricId1",
              CollectionTimeScope::point,
              CollectionDuration(Milliseconds(0u))},
@@ -129,7 +129,7 @@
              {LabeledSensorInfo{"Service",
                                 "/xyz/openbmc_project/sensors/power/p2",
                                 "metadata2"}},
-             OperationType::single,
+             OperationType::avg,
              "MetricId2",
              CollectionTimeScope::point,
              CollectionDuration(Milliseconds(0u))}}};
diff --git a/tests/src/test_metric.cpp b/tests/src/test_metric.cpp
index fcb2ded..31eabc6 100644
--- a/tests/src/test_metric.cpp
+++ b/tests/src/test_metric.cpp
@@ -173,41 +173,29 @@
     }
 };
 
-MetricParams defaultSingleParams()
+MetricParams defaultCollectionFunctionParams()
 {
     return MetricParams()
-        .operationType(OperationType::single)
         .readings(TestMetricCalculationFunctions::defaultReadings())
         .expectedReading(systemTimestamp + 16ms, 7.0);
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    OperationSingleReturnsLastReading, TestMetricCalculationFunctions,
-    Values(
-        defaultSingleParams().collectionTimeScope(CollectionTimeScope::point),
-        defaultSingleParams()
-            .collectionTimeScope(CollectionTimeScope::interval)
-            .collectionDuration(CollectionDuration(100ms)),
-        defaultSingleParams().collectionTimeScope(
-            CollectionTimeScope::startup)));
-
 MetricParams defaultPointParams()
 {
-    return defaultSingleParams().collectionTimeScope(
+    return defaultCollectionFunctionParams().collectionTimeScope(
         CollectionTimeScope::point);
 }
 
 INSTANTIATE_TEST_SUITE_P(
     TimeScopePointReturnsLastReading, TestMetricCalculationFunctions,
-    Values(defaultPointParams().operationType(OperationType::single),
-           defaultPointParams().operationType(OperationType::min),
+    Values(defaultPointParams().operationType(OperationType::min),
            defaultPointParams().operationType(OperationType::max),
            defaultPointParams().operationType(OperationType::sum),
            defaultPointParams().operationType(OperationType::avg)));
 
 MetricParams defaultMinParams()
 {
-    return defaultSingleParams().operationType(OperationType::min);
+    return defaultCollectionFunctionParams().operationType(OperationType::min);
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -226,7 +214,7 @@
 
 MetricParams defaultMaxParams()
 {
-    return defaultSingleParams().operationType(OperationType::max);
+    return defaultCollectionFunctionParams().operationType(OperationType::max);
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -249,7 +237,7 @@
 
 MetricParams defaultSumParams()
 {
-    return defaultSingleParams().operationType(OperationType::sum);
+    return defaultCollectionFunctionParams().operationType(OperationType::sum);
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -275,7 +263,7 @@
 
 MetricParams defaultAvgParams()
 {
-    return defaultSingleParams().operationType(OperationType::avg);
+    return defaultCollectionFunctionParams().operationType(OperationType::avg);
 }
 
 INSTANTIATE_TEST_SUITE_P(
diff --git a/tests/src/test_report.cpp b/tests/src/test_report.cpp
index 4e3ce8d..765f8e4 100644
--- a/tests/src/test_report.cpp
+++ b/tests/src/test_report.cpp
@@ -364,7 +364,7 @@
                         {tstring::Path::str(),
                          "/xyz/openbmc_project/sensors/power/p1"},
                         {tstring::Metadata::str(), "metadata1"}}}},
-                     {tstring::OperationType::str(), OperationType::single},
+                     {tstring::OperationType::str(), OperationType::avg},
                      {tstring::Id::str(), "MetricId1"},
                      {tstring::CollectionTimeScope::str(),
                       CollectionTimeScope::point},
@@ -374,7 +374,7 @@
                         {tstring::Path::str(),
                          "/xyz/openbmc_project/sensors/power/p2"},
                         {tstring::Metadata::str(), "metadata2"}}}},
-                     {tstring::OperationType::str(), OperationType::single},
+                     {tstring::OperationType::str(), OperationType::avg},
                      {tstring::Id::str(), "MetricId2"},
                      {tstring::CollectionTimeScope::str(),
                       CollectionTimeScope::point},
diff --git a/tests/src/test_report_manager.cpp b/tests/src/test_report_manager.cpp
index fca6451..f4ce184 100644
--- a/tests/src/test_report_manager.cpp
+++ b/tests/src/test_report_manager.cpp
@@ -103,6 +103,13 @@
                 Eq(ReportManager::maxReports));
 }
 
+TEST_F(TestReportManager, returnsPropertySupportedOperationTypes)
+{
+    EXPECT_THAT(
+        getProperty<std::vector<std::string>>("SupportedOperationTypes"),
+        UnorderedElementsAre("Maximum", "Minimum", "Average", "Summation"));
+}
+
 TEST_F(TestReportManager, addReport)
 {
     EXPECT_CALL(reportFactoryMock, convertMetricParams(_, _));
@@ -220,7 +227,7 @@
             {LabeledSensorInfo{"Service",
                                "/xyz/openbmc_project/sensors/power/p1",
                                "Metadata1"}},
-            OperationType::single,
+            OperationType::avg,
             "MetricId1",
             CollectionTimeScope::point,
             CollectionDuration(Milliseconds(0u))}}});
@@ -254,7 +261,7 @@
     {
         metricParams.emplace_back(
             LabeledMetricParameters{{},
-                                    OperationType::single,
+                                    OperationType::avg,
                                     "MetricId1",
                                     CollectionTimeScope::point,
                                     CollectionDuration(Milliseconds(0u))});
@@ -369,9 +376,8 @@
 };
 
 INSTANTIATE_TEST_SUITE_P(_, TestReportManagerWithAggregationOperationType,
-                         Values(OperationType::single, OperationType::max,
-                                OperationType::min, OperationType::avg,
-                                OperationType::sum));
+                         Values(OperationType::max, OperationType::min,
+                                OperationType::avg, OperationType::sum));
 
 TEST_P(TestReportManagerWithAggregationOperationType,
        addReportWithDifferentOperationTypes)
diff --git a/tests/src/test_transform.cpp b/tests/src/test_transform.cpp
index 66fa855..3f7c5f9 100644
--- a/tests/src/test_transform.cpp
+++ b/tests/src/test_transform.cpp
@@ -13,7 +13,8 @@
     std::vector<int> input = {1, 2, 3};
     std::vector<std::string> output =
         utils::transform(input, [](int v) { return std::to_string(v); });
-    EXPECT_TRUE(utils::detail::has_member_reserve_v<std::vector<std::string>>);
+    EXPECT_TRUE(utils::detail::has_member_reserve<decltype(input)>);
+    EXPECT_TRUE(utils::detail::has_member_reserve<decltype(output)>);
     ASSERT_THAT(output, ElementsAre("1", "2", "3"));
 }
 
@@ -22,6 +23,18 @@
     std::set<int> input = {1, 2, 3};
     std::set<std::string> output =
         utils::transform(input, [](int v) { return std::to_string(v); });
-    EXPECT_FALSE(utils::detail::has_member_reserve_v<std::set<std::string>>);
+    EXPECT_FALSE(utils::detail::has_member_reserve<decltype(input)>);
+    EXPECT_FALSE(utils::detail::has_member_reserve<decltype(output)>);
+    ASSERT_THAT(output, ElementsAre("1", "2", "3"));
+}
+
+TEST(TestTransform, transformsArrayToVector)
+{
+    std::array<int, 3> input = {1, 2, 3};
+    std::vector<std::string> output =
+        utils::transform<std::vector<std::string>>(
+            input, [](int v) { return std::to_string(v); });
+    EXPECT_FALSE(utils::detail::has_member_reserve<decltype(input)>);
+    EXPECT_TRUE(utils::detail::has_member_reserve<decltype(output)>);
     ASSERT_THAT(output, ElementsAre("1", "2", "3"));
 }