From 12aa76143362d8ddf53b3b0ed410dd9db9362469 Mon Sep 17 00:00:00 2001
From: Gennady Pospelov <g.pospelov@fz-juelich.de>
Date: Fri, 13 Mar 2015 12:41:31 +0100
Subject: [PATCH] RealParameterWrapper::setValue now respect limits attribute,
 corresponding unit tests.

---
 Core/Tools/inc/AttLimits.h                    | 65 +++++++++++++----
 Core/Tools/inc/RealParameterWrapper.h         | 17 ++++-
 Core/Tools/src/RealParameterWrapper.cpp       | 12 ++-
 Tests/UnitTests/TestCore/AttLimitsTest.h      | 73 +++++++++++++++++--
 .../TestCore/RealParameterWrapperTest.h       | 28 +++++++
 5 files changed, 173 insertions(+), 22 deletions(-)

diff --git a/Core/Tools/inc/AttLimits.h b/Core/Tools/inc/AttLimits.h
index bdc542c2d33..ffd63c8674c 100644
--- a/Core/Tools/inc/AttLimits.h
+++ b/Core/Tools/inc/AttLimits.h
@@ -29,38 +29,49 @@ class BA_CORE_API_ AttLimits
 {
  public:
     AttLimits() : m_has_lower_limit(false), m_has_upper_limit(false), m_is_fixed(false), m_lower_limit(0), m_upper_limit(0) {}
-    virtual ~AttLimits(){}
+    ~AttLimits(){}
 
     //! if has lower limit
-    virtual bool hasLowerLimit() const { return m_has_lower_limit; }
+    bool hasLowerLimit() const { return m_has_lower_limit; }
+
     //! Returns lower limit
-    virtual double getLowerLimit() const { return m_lower_limit; }
+    double getLowerLimit() const { return m_lower_limit; }
+
     //! Sets lower limit
-    virtual void setLowerLimit(double value) { m_lower_limit = value; m_has_lower_limit = true; }
+    void setLowerLimit(double value) { m_lower_limit = value; m_has_lower_limit = true; }
+
     //! remove lower limit
-    virtual void removeLowerLimit() { m_lower_limit = 0.0; m_has_lower_limit = false; }
+    void removeLowerLimit() { m_lower_limit = 0.0; m_has_lower_limit = false; }
 
     //! if has upper limit
-    virtual bool hasUpperLimit() const { return m_has_upper_limit; }
+    bool hasUpperLimit() const { return m_has_upper_limit; }
+
     //! Returns upper limit
-    virtual double getUpperLimit() const { return m_upper_limit; }
+    double getUpperLimit() const { return m_upper_limit; }
+
     //! Sets upper limit
-    virtual void setUpperLimit(double value) { m_upper_limit = value; m_has_upper_limit = true; }
+    void setUpperLimit(double value) { m_upper_limit = value; m_has_upper_limit = true; }
+
     //! remove upper limit
-    virtual void removeUpperLimit() { m_upper_limit = 0.0; m_has_upper_limit = false; }
+    void removeUpperLimit() { m_upper_limit = 0.0; m_has_upper_limit = false; }
 
     //! if has lower and upper limit
-    virtual bool hasLowerAndUpperLimits() const { return (m_has_lower_limit && m_has_upper_limit); }
+    bool hasLowerAndUpperLimits() const { return (m_has_lower_limit && m_has_upper_limit); }
 
     //! Sets object fixed
-    virtual void setFixed(bool is_fixed) { m_is_fixed = is_fixed; }
+    void setFixed(bool is_fixed) { m_is_fixed = is_fixed; }
+
     //! if object is fixed at some value
-    virtual bool isFixed() const { return m_is_fixed; }
+    bool isFixed() const { return m_is_fixed; }
 
     //! Sets lower and upper limits
-    virtual void setLimits(double xmin, double xmax) { setLowerLimit(xmin); setUpperLimit(xmax); }
+    void setLimits(double xmin, double xmax) { setLowerLimit(xmin); setUpperLimit(xmax); }
+
     //! remove limits
-    virtual void removeLimits() { removeLowerLimit(); removeUpperLimit(); }
+    void removeLimits() { removeLowerLimit(); removeUpperLimit(); }
+
+    //! returns true if proposed value is in limits range
+    bool isInRange(double value) const;
 
     // ---------
     // static creation methods
@@ -83,6 +94,9 @@ class BA_CORE_API_ AttLimits
     //! Prints class
     friend std::ostream& operator<<(std::ostream& ostr, const AttLimits& m) { m.print(ostr); return ostr; }
 
+    bool operator==(const AttLimits &other) const;
+    bool operator!=(const AttLimits &other) const;
+
  protected:
     AttLimits(bool has_lower_limit, bool has_upper_limit, bool is_fixed, double lower_limit, double upper_limit)
         : m_has_lower_limit(has_lower_limit)
@@ -115,6 +129,29 @@ class BA_CORE_API_ AttLimits
     }
 };
 
+
+inline bool AttLimits::isInRange(double value) const
+{
+    if(hasLowerLimit() && value < m_lower_limit) return false;
+    if(hasUpperLimit() && value >= m_upper_limit) return false;
+    return true;
+}
+
+inline bool AttLimits::operator==(const AttLimits &other) const
+{
+    return (m_has_lower_limit == other.m_has_lower_limit) &&
+            (m_has_upper_limit == other.m_has_upper_limit) &&
+            (m_lower_limit == other.m_lower_limit) &&
+            (m_upper_limit == other.m_upper_limit);
+
+}
+
+inline bool AttLimits::operator!=(const AttLimits &other) const
+{
+    return !(*this == other);
+}
+
+
 #endif // LIMITS_H
 
 
diff --git a/Core/Tools/inc/RealParameterWrapper.h b/Core/Tools/inc/RealParameterWrapper.h
index 7eb4dbb9879..8b0b6577df3 100644
--- a/Core/Tools/inc/RealParameterWrapper.h
+++ b/Core/Tools/inc/RealParameterWrapper.h
@@ -52,6 +52,11 @@ public:
         ostr << p.m_data; return ostr;
     }
 
+    AttLimits getAttLimits() const { return m_limits; }
+
+    bool operator==(const RealParameterWrapper &other) const;
+    bool operator!=(const RealParameterWrapper &other) const;
+
 private:
     //! swap function
     void swapContent(RealParameterWrapper& other);
@@ -75,7 +80,17 @@ inline void RealParameterWrapper::checkNull() const
 {
     if(isNull())
         throw NullPointerException(
-            "RealParameterWrapper::getValue() -> Attempt to access uninitialised pointer.");
+                "RealParameterWrapper::getValue() -> Attempt to access uninitialised pointer.");
+}
+
+inline bool RealParameterWrapper::operator==(const RealParameterWrapper &other) const
+{
+    return (m_limits == other.m_limits) && (m_data == other.m_data);
+}
+
+inline bool RealParameterWrapper::operator!=(const RealParameterWrapper &other) const
+{
+    return !(*this == other);
 }
 
 
diff --git a/Core/Tools/src/RealParameterWrapper.cpp b/Core/Tools/src/RealParameterWrapper.cpp
index 3cbd1884d2f..aa77cf6d1eb 100644
--- a/Core/Tools/src/RealParameterWrapper.cpp
+++ b/Core/Tools/src/RealParameterWrapper.cpp
@@ -19,7 +19,11 @@ RealParameterWrapper::RealParameterWrapper(double *par, const AttLimits &limits)
     : m_data(par)
     , m_limits(limits)
 {
-
+    if(par && !m_limits.isInRange(getValue())) {
+        throw OutOfBoundsException(
+            "RealParameterWrapper::RealParameterWrapper() -> Error. Initial value is out of bounds"
+                    );
+    }
 }
 
 RealParameterWrapper::RealParameterWrapper(const RealParameterWrapper& other )
@@ -42,7 +46,11 @@ bool RealParameterWrapper::setValue(double value)
     bool success(true);
     checkNull();
     if(value != *m_data) {
-        *m_data = value;
+        if(m_limits.isInRange(value) && !m_limits.isFixed()) {
+            *m_data = value;
+        } else {
+            success = false;
+        }
     }
     return success;
 }
diff --git a/Tests/UnitTests/TestCore/AttLimitsTest.h b/Tests/UnitTests/TestCore/AttLimitsTest.h
index 7acf045956d..8d376ece6f9 100644
--- a/Tests/UnitTests/TestCore/AttLimitsTest.h
+++ b/Tests/UnitTests/TestCore/AttLimitsTest.h
@@ -2,6 +2,7 @@
 #define ATTLIMITSTEST_H
 
 #include "AttLimits.h"
+#include <limits>
 
 #include "gtest/gtest.h"
 
@@ -30,38 +31,63 @@ TEST_F(AttLimitsTest, AttLimitsSetLimit)
 {
     AttLimits attLimits;
 
-    //set limit
+    //set limit [-1.0, 10.0[
     attLimits.setLimits(-1.0,10.0);
     EXPECT_TRUE(attLimits.hasLowerLimit());
     EXPECT_TRUE(attLimits.hasUpperLimit());
     EXPECT_TRUE(attLimits.hasLowerAndUpperLimits());
     EXPECT_FALSE(attLimits.isFixed());
 
-    //lower limit
     EXPECT_EQ(-1.0,attLimits.getLowerLimit());
+    EXPECT_EQ(10.0,attLimits.getUpperLimit());
+
+    EXPECT_FALSE(attLimits.isInRange(-2.0));
+    EXPECT_TRUE(attLimits.isInRange(-1.0));
+    EXPECT_TRUE(attLimits.isInRange(0.0));
+    EXPECT_TRUE(attLimits.isInRange(9.0));
+    EXPECT_FALSE(attLimits.isInRange(10.0));
+    EXPECT_FALSE(attLimits.isInRange(20.0));
 
+    // [inf, -10.0[
     attLimits.removeLowerLimit();
     EXPECT_FALSE(attLimits.hasLowerAndUpperLimits());
     EXPECT_FALSE(attLimits.hasLowerLimit());
     EXPECT_EQ(0.0,attLimits.getLowerLimit());
 
+    EXPECT_TRUE(attLimits.isInRange(-std::numeric_limits<double>::infinity()));
+    EXPECT_TRUE(attLimits.isInRange(-2.0));
+    EXPECT_TRUE(attLimits.isInRange(9.0));
+    EXPECT_FALSE(attLimits.isInRange(10.0));
+    EXPECT_FALSE(attLimits.isInRange(std::numeric_limits<double>::infinity()));
+
+    // [2.1, -10.0[
     attLimits.setLowerLimit(2.1);
     EXPECT_TRUE(attLimits.hasLowerLimit());
     EXPECT_EQ(2.1,attLimits.getLowerLimit());
 
-    //upper limit
-    EXPECT_EQ(10.0,attLimits.getUpperLimit());
+    EXPECT_FALSE(attLimits.isInRange(-std::numeric_limits<double>::infinity()));
+    EXPECT_FALSE(attLimits.isInRange(2.0));
+    EXPECT_TRUE(attLimits.isInRange(2.1));
 
+    //[2.1, inf]
     attLimits.removeUpperLimit();
     EXPECT_FALSE(attLimits.hasLowerAndUpperLimits());
     EXPECT_FALSE(attLimits.hasUpperLimit());
     EXPECT_EQ(0.0,attLimits.getUpperLimit());
 
+    EXPECT_FALSE(attLimits.isInRange(-std::numeric_limits<double>::infinity()));
+    EXPECT_FALSE(attLimits.isInRange(2.0));
+    EXPECT_TRUE(attLimits.isInRange(2.1));
+    EXPECT_TRUE(attLimits.isInRange(20.0));
+    EXPECT_TRUE(attLimits.isInRange(std::numeric_limits<double>::infinity()));
+
+    // [2.1, 2.2[
     attLimits.setUpperLimit(2.2);
     EXPECT_TRUE(attLimits.hasUpperLimit());
     EXPECT_EQ(2.2,attLimits.getUpperLimit());
-
     EXPECT_TRUE(attLimits.hasLowerAndUpperLimits());
+    EXPECT_TRUE(attLimits.isInRange(2.15));
+    EXPECT_FALSE(attLimits.isInRange(2.2));
 
     //remove limit
     attLimits.removeLimits();
@@ -70,6 +96,9 @@ TEST_F(AttLimitsTest, AttLimitsSetLimit)
     EXPECT_FALSE(attLimits.hasLowerAndUpperLimits());
     EXPECT_FALSE(attLimits.isFixed());
 
+    EXPECT_TRUE(attLimits.isInRange(-std::numeric_limits<double>::infinity()));
+    EXPECT_TRUE(attLimits.isInRange(std::numeric_limits<double>::infinity()));
+
 }
 
 TEST_F(AttLimitsTest, AttLimitsLowerLimited)
@@ -134,5 +163,39 @@ TEST_F(AttLimitsTest, AttLimitsFixed)
     EXPECT_FALSE(attLimits.isFixed());
 }
 
+TEST_F(AttLimitsTest, ComparisonOperators)
+{
+    AttLimits lim1 = AttLimits::limited(1.0, 2.0);
+    AttLimits lim2 = AttLimits::limited(1.0, 2.0);
+    EXPECT_TRUE(lim1 == lim2);
+    EXPECT_FALSE(lim1 != lim2);
+
+    AttLimits lim3 = AttLimits::limitless();
+    AttLimits lim4 = AttLimits::limitless();
+    EXPECT_TRUE(lim3 == lim4);
+    EXPECT_FALSE(lim3 != lim4);
+
+    AttLimits lim5 = AttLimits::lowerLimited(1.0);
+    AttLimits lim6 = AttLimits::lowerLimited(1.0);
+    EXPECT_TRUE(lim5 == lim6);
+    EXPECT_FALSE(lim5 != lim6);
+
+    AttLimits lim7 = AttLimits::upperLimited(1.0);
+    AttLimits lim8 = AttLimits::upperLimited(1.0);
+    EXPECT_TRUE(lim7 == lim8);
+    EXPECT_FALSE(lim7 != lim8);
+}
+
+TEST_F(AttLimitsTest, CopyConstructor)
+{
+    AttLimits lim1 = AttLimits::limited(1.0, 2.0);
+    AttLimits lim2 = lim1;
+    EXPECT_TRUE(lim1 == lim2);
+    EXPECT_FALSE(lim1 != lim2);
+
+    AttLimits lim3(lim1);
+    EXPECT_TRUE(lim1 == lim3);
+    EXPECT_FALSE(lim1 != lim3);
+}
 
 #endif // ATTLIMITSTEST_H
diff --git a/Tests/UnitTests/TestCore/RealParameterWrapperTest.h b/Tests/UnitTests/TestCore/RealParameterWrapperTest.h
index 98d36ef5c0d..b7e4dc63c8e 100644
--- a/Tests/UnitTests/TestCore/RealParameterWrapperTest.h
+++ b/Tests/UnitTests/TestCore/RealParameterWrapperTest.h
@@ -44,6 +44,8 @@ TEST_F(RealParameterWrapperTest, InitialState)
     EXPECT_TRUE( par.isNull() );
     ASSERT_THROW( par.getValue(), NullPointerException );
     ASSERT_THROW( par.setValue(1.0), NullPointerException );
+
+    EXPECT_EQ(par.getAttLimits(), AttLimits::limitless());
 }
 
 TEST_F(RealParameterWrapperTest, ParameterAccess)
@@ -90,5 +92,31 @@ TEST_F(RealParameterWrapperTest, ParameterAccess)
 //    EXPECT_FALSE( obj2.m_status );
 //}
 
+TEST_F(RealParameterWrapperTest, LimitedParameter)
+{
+    m_real_parameter = 1.0;
+    EXPECT_THROW(RealParameterWrapper(&m_real_parameter, AttLimits::limited(10.0, 20.0)), OutOfBoundsException);
+    EXPECT_THROW(RealParameterWrapper(&m_real_parameter, AttLimits::lowerLimited(2.0)), OutOfBoundsException);
+    EXPECT_THROW(RealParameterWrapper(&m_real_parameter, AttLimits::upperLimited(0.0)), OutOfBoundsException);
+
+    m_real_parameter = 15.0;
+    AttLimits limits = AttLimits::limited(10, 20);
+    RealParameterWrapper par1(&m_real_parameter, limits);
+
+    EXPECT_TRUE(par1.setValue(16.0));
+    EXPECT_EQ(16.0, m_real_parameter);
+
+    EXPECT_FALSE(par1.setValue(21.0));
+    EXPECT_EQ(16.0, m_real_parameter);
+
+    RealParameterWrapper par2(par1);
+    EXPECT_TRUE(par1 == par2);
+
+    EXPECT_FALSE(par1.setValue(21.0));
+    EXPECT_EQ(16.0, m_real_parameter);
+
+    EXPECT_TRUE(par1.setValue(11.0));
+    EXPECT_EQ(11.0, m_real_parameter);
+}
 
 #endif // REALPARAMETERWRAPPERTEST_H
-- 
GitLab