Back to index

nux  3.0.0
gtest-nuxcore-properties.cpp
Go to the documentation of this file.
00001 #include "NuxCore/Property.h"
00002 
00003 #include <boost/scoped_ptr.hpp>
00004 #include <sigc++/trackable.h>
00005 
00006 #include <gmock/gmock.h>
00007 #include <vector>
00008 #include <stdexcept>
00009 
00010 using namespace testing;
00011 
00012 namespace {
00013 
00014 template <typename T>
00015 T to_and_from_string(T const& value)
00016 {
00017   std::string temp = nux::type::PropertyTrait<T>::to_string(value);
00018   std::pair<T, bool> result = nux::type::PropertyTrait<T>::from_string(temp);
00019   if (!result.second) {
00020     throw std::runtime_error("Failed to convert.");
00021   }
00022   return result.first;
00023 }
00024 
00025 enum TestEnum
00026 {
00027   FirstValue,
00028   MiddleValue,
00029   LastValue,
00030 };
00031 
00032 struct TestClass
00033 {
00034   int value;
00035 };
00036 
00037 
00038 TEST(TestTypeTraits, TestSerialization) {
00039   EXPECT_EQ("hello", nux::type::PropertyTrait<std::string>::to_string("hello"));
00040   EXPECT_EQ("42", nux::type::PropertyTrait<int>::to_string(42));
00041   EXPECT_EQ("42", nux::type::PropertyTrait<unsigned>::to_string(42));
00042   EXPECT_EQ("true", nux::type::PropertyTrait<bool>::to_string(true));
00043   EXPECT_EQ("false", nux::type::PropertyTrait<bool>::to_string(false));
00044   EXPECT_EQ("0", nux::type::PropertyTrait<double>::to_string(0));
00045   EXPECT_EQ("25.5", nux::type::PropertyTrait<double>::to_string(25.5));
00046   EXPECT_EQ("1", nux::type::PropertyTrait<TestEnum>::to_string(MiddleValue));
00047 }
00048 
00049 TEST(TestTypeTraits, TestDeserialization) {
00050   std::pair<std::string, bool> sr = nux::type::PropertyTrait<std::string>::from_string("hello");
00051   EXPECT_EQ("hello", sr.first);
00052   EXPECT_TRUE(sr.second);
00053   std::pair<int, bool> int_result = nux::type::PropertyTrait<int>::from_string("42");
00054   EXPECT_EQ(42, int_result.first);
00055   EXPECT_TRUE(int_result.second);
00056   int_result = nux::type::PropertyTrait<int>::from_string("OMG!");
00057   EXPECT_EQ(0, int_result.first);
00058   EXPECT_FALSE(int_result.second);
00059 
00060   std::pair<unsigned, bool> unsigned_result = nux::type::PropertyTrait<unsigned>::from_string("42");
00061   EXPECT_EQ(42, unsigned_result.first);
00062   EXPECT_TRUE(unsigned_result.second);
00063   unsigned_result = nux::type::PropertyTrait<unsigned>::from_string("OMG!");
00064   EXPECT_EQ(0, unsigned_result.first);
00065   EXPECT_FALSE(unsigned_result.second);
00066 
00067   std::pair<bool, bool> bool_result = nux::type::PropertyTrait<bool>::from_string("true");
00068   EXPECT_TRUE(bool_result.first);
00069   EXPECT_TRUE(bool_result.second);
00070   bool_result = nux::type::PropertyTrait<bool>::from_string("false");
00071   EXPECT_FALSE(bool_result.first);
00072   EXPECT_TRUE(bool_result.second);
00073   bool_result = nux::type::PropertyTrait<bool>::from_string("what?");
00074   EXPECT_FALSE(bool_result.first);
00075   EXPECT_FALSE(bool_result.second);
00076   std::pair<double, bool> double_result = nux::type::PropertyTrait<double>::from_string("25.5");
00077   EXPECT_EQ(25.5, double_result.first);
00078   EXPECT_TRUE(double_result.second);
00079   double_result = nux::type::PropertyTrait<double>::from_string("2e6");
00080   EXPECT_EQ(2000000.0, double_result.first);
00081   EXPECT_TRUE(double_result.second);
00082   double_result = nux::type::PropertyTrait<double>::from_string("what?");
00083   EXPECT_EQ(0, double_result.first);
00084   EXPECT_FALSE(double_result.second);
00085 
00086   std::pair<TestEnum, bool> enum_result = nux::type::PropertyTrait<TestEnum>::from_string("0");
00087   EXPECT_EQ(FirstValue, enum_result.first);
00088   EXPECT_TRUE(enum_result.second);
00089   // This is tested to show behaviour even though it is undesirable (as there
00090   // isn't an enum value for 42).
00091   enum_result = nux::type::PropertyTrait<TestEnum>::from_string("42");
00092   EXPECT_EQ(42, enum_result.first);
00093   EXPECT_TRUE(enum_result.second);
00094 }
00095 
00096 TEST(TestTypeTraits, TestConversionHolds) {
00097   std::string string_value("Hello World!");
00098   EXPECT_EQ(string_value, to_and_from_string(string_value));
00099   double double_value = 34.345;
00100   EXPECT_EQ(double_value, to_and_from_string(double_value));
00101 }
00102 
00103 
00104 template <typename T>
00105 struct ChangeRecorder : sigc::trackable
00106 {
00107   typedef sigc::slot<void, T const&> Listener;
00108 
00109   Listener listener()
00110   {
00111     return sigc::mem_fun(this, &ChangeRecorder<T>::value_changed);
00112   }
00113 
00114   void value_changed(T const& value)
00115     {
00116       changed_values.push_back(value);
00117     }
00118   typedef std::vector<T> ChangedValues;
00119   ChangedValues changed_values;
00120 
00121   int size() const { return changed_values.size(); }
00122   T last() const { return *changed_values.rbegin(); }
00123 };
00124 
00125 
00126 TEST(TestProperty, TestDefaultConstructor) {
00127   nux::Property<std::string> string_prop;
00128   // Need either an assignment or static cast to check the operator VALUE_TYPE
00129   // due to google-mock's template matching.
00130   std::string value = string_prop;
00131   EXPECT_THAT(value, Eq(""));
00132   EXPECT_THAT(string_prop.Get(), Eq(""));
00133   EXPECT_THAT(string_prop(), Eq(""));
00134 }
00135 
00136 TEST(TestProperty, TestValueExplicitConstructor) {
00137   nux::Property<std::string> string_prop("Hello world!");
00138   // Need either an assignment or static cast to check the operator VALUE_TYPE
00139   // due to google-mock's template matching.
00140   std::string value = string_prop;
00141   EXPECT_THAT(value, Eq("Hello world!"));
00142   EXPECT_THAT(string_prop.Get(), Eq("Hello world!"));
00143   EXPECT_THAT(string_prop(), Eq("Hello world!"));
00144 }
00145 
00146 TEST(TestProperty, TestAssignment) {
00147   nux::Property<std::string> string_prop;
00148   // Need either an assignment or static cast to check the operator VALUE_TYPE
00149   // due to google-mock's template matching.
00150   string_prop = "Assignment operator";
00151   std::string value = string_prop;
00152   EXPECT_THAT(value, Eq("Assignment operator"));
00153   EXPECT_THAT(string_prop.Get(), Eq("Assignment operator"));
00154   EXPECT_THAT(string_prop(), Eq("Assignment operator"));
00155 
00156   string_prop.Set("Set method");
00157   value = string_prop;
00158   EXPECT_THAT(value, Eq("Set method"));
00159   EXPECT_THAT(string_prop.Get(), Eq("Set method"));
00160   EXPECT_THAT(string_prop(), Eq("Set method"));
00161 
00162   string_prop("Function call assignment");
00163   value = string_prop;
00164   EXPECT_THAT(value, Eq("Function call assignment"));
00165   EXPECT_THAT(string_prop.Get(), Eq("Function call assignment"));
00166   EXPECT_THAT(string_prop(), Eq("Function call assignment"));
00167 }
00168 
00169 TEST(TestProperty, TestChanged) {
00170   nux::Property<std::string> string_prop;
00171   ChangeRecorder<std::string> recorder;
00172   string_prop.changed.connect(recorder.listener());
00173 
00174   string_prop = "Hello world" ;
00175   EXPECT_THAT(1, Eq(recorder.size()));
00176   EXPECT_THAT("Hello world", Eq(recorder.last()));
00177   // No notification if not changed.
00178   string_prop = std::string("Hello world");
00179   EXPECT_THAT(1, Eq(recorder.size()));
00180 }
00181 
00182 TEST(TestProperty, TestEnableAndDisableNotifications) {
00183   nux::Property<std::string> string_prop;
00184   ChangeRecorder<std::string> recorder;
00185   string_prop.changed.connect(recorder.listener());
00186 
00187   string_prop.DisableNotifications();
00188   string_prop = "Hello world" ;
00189   EXPECT_THAT(0, Eq(recorder.size()));
00190 
00191   string_prop.EnableNotifications();
00192   // No notification if not changed.
00193   string_prop = "Hello world" ;
00194   EXPECT_THAT(0, Eq(recorder.size()));
00195 
00196   string_prop = "New value" ;
00197   EXPECT_THAT(1, Eq(recorder.size()));
00198   EXPECT_THAT("New value", Eq(recorder.last()));
00199 }
00200 
00201 bool string_prefix(std::string& target, std::string const& value)
00202 {
00203   bool changed = false;
00204   std::string prefixed("prefix-" + value);
00205   if (target != prefixed)
00206   {
00207     target = prefixed;
00208     changed = true;
00209   }
00210   return changed;
00211 }
00212 
00213 TEST(TestProperty, TestSetterConstructor) {
00214   nux::Property<std::string> string_prop("", sigc::ptr_fun(&string_prefix));
00215 
00216   string_prop = "foo";
00217   // Need either an assignment or static cast to check the operator VALUE_TYPE
00218   // due to google-mock's template matching.
00219   std::string value = string_prop;
00220   EXPECT_THAT(value, Eq("prefix-foo"));
00221   EXPECT_THAT(string_prop.Get(), Eq("prefix-foo"));
00222   EXPECT_THAT(string_prop(), Eq("prefix-foo"));
00223 }
00224 
00225 class FloatClamp
00226 {
00227 public:
00228   FloatClamp(float min, float max)
00229     : min_(min), max_(max)
00230     {
00231     }
00232   bool Set(float& target, float const& value)
00233     {
00234       bool changed = false;
00235       float new_val = std::min(max_, std::max(min_, value));
00236       if (target != new_val) {
00237         target = new_val;
00238         changed = true;
00239       }
00240       return changed;
00241     }
00242 private:
00243   float min_;
00244   float max_;
00245 };
00246 
00247 TEST(TestProperty, TestCustomSetterFunction) {
00248   nux::Property<float> float_prop;
00249   FloatClamp clamp(0, 1);
00250   float_prop.SetSetterFunction(sigc::mem_fun(&clamp, &FloatClamp::Set));
00251   ChangeRecorder<float> recorder;
00252   float_prop.changed.connect(recorder.listener());
00253 
00254   // Since the default value for a float is zero, and we clamp at zero,
00255   // setting to a negative value will result in setting to zero, which will
00256   // not signal a changed event.
00257   float_prop = -2;
00258   EXPECT_THAT(float_prop(), Eq(0));
00259   EXPECT_THAT(0, Eq(recorder.size()));
00260 
00261   float_prop = 0.5;
00262   EXPECT_THAT(float_prop(), Eq(0.5));
00263   EXPECT_THAT(1, Eq(recorder.size()));
00264   EXPECT_THAT(0.5, Eq(recorder.last()));
00265 
00266   float_prop = 4;
00267   EXPECT_THAT(float_prop(), Eq(1));
00268   EXPECT_THAT(2, Eq(recorder.size()));
00269   EXPECT_THAT(1, Eq(recorder.last()));
00270 }
00271 
00272 
00273 TEST(TestProperty, TestIntOperators) {
00274   nux::Property<int> int_prop(42);
00275 
00276   EXPECT_TRUE(int_prop == 42);
00277   EXPECT_TRUE(42 == int_prop);
00278   EXPECT_FALSE(int_prop != 42);
00279   EXPECT_FALSE(42 != int_prop);
00280 
00281   EXPECT_FALSE(int_prop == 5);
00282   EXPECT_FALSE(5 == int_prop);
00283   EXPECT_TRUE(int_prop != 5);
00284   EXPECT_TRUE(5 != int_prop);
00285 
00286   EXPECT_FALSE(int_prop < 5);
00287   EXPECT_FALSE(int_prop <= 5);
00288   EXPECT_TRUE(int_prop > 5);
00289   EXPECT_TRUE(int_prop >= 5);
00290 
00291   EXPECT_TRUE(5 < int_prop);
00292   EXPECT_TRUE(5 <= int_prop);
00293   EXPECT_FALSE(5 > int_prop);
00294   EXPECT_FALSE(5 >= int_prop);
00295 
00296   nux::Property<int> int_prop2(42);
00297   EXPECT_TRUE(int_prop2 == int_prop);
00298   EXPECT_FALSE(int_prop2 != int_prop);
00299 
00300   int_prop2 = 5;
00301 
00302   EXPECT_FALSE(int_prop2 == int_prop);
00303   EXPECT_TRUE(int_prop2 != int_prop);
00304 
00305   EXPECT_FALSE(int_prop < int_prop2);
00306   EXPECT_FALSE(int_prop <= int_prop2);
00307   EXPECT_TRUE(int_prop > int_prop2);
00308   EXPECT_TRUE(int_prop >= int_prop2);
00309 }
00310 
00311 // Only testing strings and ints, to show that the template classes work with
00312 // both primitive types and classes.
00313 TEST(TestProperty, TestStringOperators) {
00314   std::string value("Hello");
00315   nux::Property<std::string> str_prop(value);
00316 
00317   EXPECT_TRUE(str_prop == "Hello");
00318   EXPECT_TRUE("Hello" == str_prop);
00319   EXPECT_FALSE(str_prop != "Hello");
00320   EXPECT_FALSE("Hello" != str_prop);
00321   EXPECT_TRUE(str_prop == value);
00322   EXPECT_TRUE(value == str_prop);
00323   EXPECT_FALSE(str_prop != value);
00324   EXPECT_FALSE(value != str_prop);
00325 
00326   EXPECT_FALSE(str_prop == "World");
00327   EXPECT_FALSE("World" == str_prop);
00328   EXPECT_TRUE(str_prop != "World");
00329   EXPECT_TRUE("World" != str_prop);
00330 
00331   EXPECT_FALSE(str_prop < "Aardvark");
00332   EXPECT_FALSE(str_prop <= "Aardvark");
00333   EXPECT_TRUE(str_prop > "Aardvark");
00334   EXPECT_TRUE(str_prop >= "Aardvark");
00335 
00336   EXPECT_TRUE("Aardvark" < str_prop);
00337   EXPECT_TRUE("Aardvark" <= str_prop);
00338   EXPECT_FALSE("Aardvark" > str_prop);
00339   EXPECT_FALSE("Aardvark" >= str_prop);
00340 
00341   nux::Property<std::string> str_prop2(value);
00342   EXPECT_TRUE(str_prop2 == str_prop);
00343   EXPECT_FALSE(str_prop2 != str_prop);
00344 
00345   str_prop2 = "Aardvark";
00346 
00347   EXPECT_FALSE(str_prop2 == str_prop);
00348   EXPECT_TRUE(str_prop2 != str_prop);
00349 
00350   EXPECT_FALSE(str_prop < str_prop2);
00351   EXPECT_FALSE(str_prop <= str_prop2);
00352   EXPECT_TRUE(str_prop > str_prop2);
00353   EXPECT_TRUE(str_prop >= str_prop2);
00354 }
00355 
00356 TEST(TestROProperty, TestDefaultConstructor) {
00357   nux::ROProperty<int> int_prop;
00358   int value = int_prop;
00359   EXPECT_THAT(value, Eq(0));
00360   EXPECT_THAT(int_prop(), Eq(0));
00361   EXPECT_THAT(int_prop.Get(), Eq(0));
00362 
00363   nux::ROProperty<std::string> string_prop;
00364   std::string svalue = string_prop;
00365   EXPECT_THAT(svalue, Eq(""));
00366   EXPECT_THAT(string_prop(), Eq(""));
00367   EXPECT_THAT(string_prop.Get(), Eq(""));
00368 }
00369 
00370 int simple_int_result()
00371 {
00372   return 42;
00373 }
00374 
00375 TEST(TestROProperty, TestGetterConstructor) {
00376   nux::ROProperty<int> int_prop(sigc::ptr_fun(&simple_int_result));
00377   int value = int_prop;
00378   EXPECT_THAT(value, Eq(42));
00379   EXPECT_THAT(int_prop(), Eq(42));
00380   EXPECT_THAT(int_prop.Get(), Eq(42));
00381 }
00382 
00383 class Incrementer
00384 {
00385 public:
00386   Incrementer() : value_(0) {}
00387   int value() { return ++value_; }
00388 private:
00389   int value_;
00390 };
00391 
00392 TEST(TestROProperty, TestSetGetter) {
00393   nux::ROProperty<int> int_prop;
00394   Incrementer incrementer;
00395   int_prop.SetGetterFunction(sigc::mem_fun(&incrementer, &Incrementer::value));
00396 
00397   int value = int_prop;
00398   EXPECT_THAT(value, Eq(1));
00399   EXPECT_THAT(int_prop(), Eq(2));
00400   EXPECT_THAT(int_prop.Get(), Eq(3));
00401 }
00402 
00403 TEST(TestROProperty, TestChangedEvent) {
00404   // RO Properties have a changed event, but it is up to the continer of the
00405   // property to emit the events as nothing is done automatically.
00406   nux::ROProperty<int> int_prop;
00407 
00408   ChangeRecorder<int> recorder;
00409   int_prop.changed.connect(recorder.listener());
00410 
00411   int_prop.EmitChanged(42);
00412   EXPECT_THAT(1, Eq(recorder.size()));
00413   EXPECT_THAT(42, Eq(recorder.last()));
00414 }
00415 
00416 // A simple class that just has a reader functon.
00417 template <typename VALUE_TYPE>
00418 class ROPropHolder
00419 {
00420 public:
00421   ROPropHolder(VALUE_TYPE const& initial)
00422     : prop(sigc::mem_fun(this, &ROPropHolder<VALUE_TYPE>::get_prop))
00423     , prop_(initial)
00424     {}
00425   nux::ROProperty<VALUE_TYPE> prop;
00426 
00427   VALUE_TYPE get_prop() const { return prop_; }
00428   VALUE_TYPE prop_;
00429 
00430 };
00431 
00432 TEST(TestROProperty, TestIntOperators) {
00433   ROPropHolder<int> int_prop(42);
00434 
00435   EXPECT_TRUE(int_prop.prop == 42);
00436   EXPECT_TRUE(42 == int_prop.prop);
00437   EXPECT_FALSE(int_prop.prop != 42);
00438   EXPECT_FALSE(42 != int_prop.prop);
00439 
00440   EXPECT_FALSE(int_prop.prop == 5);
00441   EXPECT_FALSE(5 == int_prop.prop);
00442   EXPECT_TRUE(int_prop.prop != 5);
00443   EXPECT_TRUE(5 != int_prop.prop);
00444 
00445   EXPECT_FALSE(int_prop.prop < 5);
00446   EXPECT_FALSE(int_prop.prop <= 5);
00447   EXPECT_TRUE(int_prop.prop > 5);
00448   EXPECT_TRUE(int_prop.prop >= 5);
00449 
00450   EXPECT_TRUE(5 < int_prop.prop);
00451   EXPECT_TRUE(5 <= int_prop.prop);
00452   EXPECT_FALSE(5 > int_prop.prop);
00453   EXPECT_FALSE(5 >= int_prop.prop);
00454 
00455   ROPropHolder<int> int_prop2(42);
00456   EXPECT_TRUE(int_prop2.prop == int_prop.prop);
00457   EXPECT_FALSE(int_prop2.prop != int_prop.prop);
00458 
00459   int_prop2.prop_ = 5;
00460 
00461   EXPECT_FALSE(int_prop2.prop == int_prop.prop);
00462   EXPECT_TRUE(int_prop2.prop != int_prop.prop);
00463 
00464   EXPECT_FALSE(int_prop.prop < int_prop2.prop);
00465   EXPECT_FALSE(int_prop.prop <= int_prop2.prop);
00466   EXPECT_TRUE(int_prop.prop > int_prop2.prop);
00467   EXPECT_TRUE(int_prop.prop >= int_prop2.prop);
00468 }
00469 
00470 // Only testing strings and ints, to show that the template classes work with
00471 // both primitive types and classes.
00472 TEST(TestROProperty, TestStringOperators) {
00473   std::string value("Hello");
00474   ROPropHolder<std::string> str_prop(value);
00475 
00476   EXPECT_TRUE(str_prop.prop == "Hello");
00477   EXPECT_TRUE("Hello" == str_prop.prop);
00478   EXPECT_FALSE(str_prop.prop != "Hello");
00479   EXPECT_FALSE("Hello" != str_prop.prop);
00480   EXPECT_TRUE(str_prop.prop == value);
00481   EXPECT_TRUE(value == str_prop.prop);
00482   EXPECT_FALSE(str_prop.prop != value);
00483   EXPECT_FALSE(value != str_prop.prop);
00484 
00485   EXPECT_FALSE(str_prop.prop == "World");
00486   EXPECT_FALSE("World" == str_prop.prop);
00487   EXPECT_TRUE(str_prop.prop != "World");
00488   EXPECT_TRUE("World" != str_prop.prop);
00489 
00490   EXPECT_FALSE(str_prop.prop < "Aardvark");
00491   EXPECT_FALSE(str_prop.prop <= "Aardvark");
00492   EXPECT_TRUE(str_prop.prop > "Aardvark");
00493   EXPECT_TRUE(str_prop.prop >= "Aardvark");
00494 
00495   EXPECT_TRUE("Aardvark" < str_prop.prop);
00496   EXPECT_TRUE("Aardvark" <= str_prop.prop);
00497   EXPECT_FALSE("Aardvark" > str_prop.prop);
00498   EXPECT_FALSE("Aardvark" >= str_prop.prop);
00499 
00500   ROPropHolder<std::string> str_prop2(value);
00501   EXPECT_TRUE(str_prop2.prop == str_prop.prop);
00502   EXPECT_FALSE(str_prop2.prop != str_prop.prop);
00503 
00504   str_prop2.prop_ = "Aardvark";
00505 
00506   EXPECT_FALSE(str_prop2.prop == str_prop.prop);
00507   EXPECT_TRUE(str_prop2.prop != str_prop.prop);
00508 
00509   EXPECT_FALSE(str_prop.prop < str_prop2.prop);
00510   EXPECT_FALSE(str_prop.prop <= str_prop2.prop);
00511   EXPECT_TRUE(str_prop.prop > str_prop2.prop);
00512   EXPECT_TRUE(str_prop.prop >= str_prop2.prop);
00513 }
00514 
00515 
00516 TEST(TestRWProperty, TestDefaultConstructor) {
00517   nux::RWProperty<int> int_prop;
00518   ChangeRecorder<int> recorder;
00519   int_prop.changed.connect(recorder.listener());
00520 
00521   int_prop = 42;
00522   int value = int_prop;
00523   EXPECT_THAT(value, Eq(0));
00524   EXPECT_THAT(int_prop(), Eq(0));
00525   EXPECT_THAT(int_prop.Get(), Eq(0));
00526   EXPECT_THAT(recorder.size(), Eq(0));
00527 }
00528 
00529 bool is_even(int const& value)
00530 {
00531   return value % 2 == 0;
00532 }
00533 
00534 
00535 TEST(TestRWProperty, TestFunctionConstructor) {
00536   // This is a somewhat convoluted example.  The setter emits if the value is
00537   // even, but the value being emitted is controlled by the incrementer.
00538   Incrementer incrementer;
00539   nux::RWProperty<int> int_prop(sigc::mem_fun(&incrementer, &Incrementer::value),
00540                                 sigc::ptr_fun(&is_even));
00541   ChangeRecorder<int> recorder;
00542   int_prop.changed.connect(recorder.listener());
00543 
00544   int_prop = 42;
00545   EXPECT_THAT(recorder.size(), Eq(1));
00546   EXPECT_THAT(recorder.last(), Eq(1));
00547 
00548   // Catch the return value of the assignment.  The getter is called.
00549   int assign_result = int_prop = 13;
00550   EXPECT_THAT(recorder.size(), Eq(1));
00551   EXPECT_THAT(assign_result, Eq(2));
00552 
00553   // each access increments the value.
00554   int value = int_prop;
00555   EXPECT_THAT(value, Eq(3));
00556   EXPECT_THAT(int_prop(), Eq(4));
00557   EXPECT_THAT(int_prop.Get(), Eq(5));
00558 }
00559 
00560 // This bit would normally be in the header file.
00561 class HiddenImpl
00562 {
00563 public:
00564   HiddenImpl();
00565 
00566   nux::RWProperty<std::string> name;
00567 private:
00568   class Impl;
00569   boost::scoped_ptr<Impl> pimpl;
00570 };
00571 
00572 // This bit is in the implementation file.
00573 class HiddenImpl::Impl
00574 {
00575 public:
00576   bool set_name(std::string const& name) {
00577     bool changed = false;
00578     std::string new_name("Impl::" + name);
00579     if (name_ != new_name) {
00580       name_ = new_name;
00581       changed = true;
00582     }
00583     return changed;
00584   }
00585   std::string get_name() const {
00586     return name_;
00587   }
00588 
00589 private:
00590   std::string name_;
00591 };
00592 
00593 HiddenImpl::HiddenImpl()
00594   : pimpl(new Impl())
00595 {
00596   name.SetSetterFunction(sigc::mem_fun(pimpl.get(), &HiddenImpl::Impl::set_name));
00597   name.SetGetterFunction(sigc::mem_fun(pimpl.get(), &HiddenImpl::Impl::get_name));
00598 }
00599 
00600 
00601 TEST(TestRWProperty, TestPimplClassExample) {
00602   HiddenImpl hidden;
00603   ChangeRecorder<std::string> recorder;
00604   hidden.name.changed.connect(recorder.listener());
00605 
00606   hidden.name = "NewName";
00607   EXPECT_THAT(recorder.size(), Eq(1));
00608   EXPECT_THAT(recorder.last(), Eq("Impl::NewName"));
00609 
00610   // Since the name is updated before comparison, no event emitted.
00611   hidden.name = "NewName";
00612   EXPECT_THAT(recorder.size(), Eq(1));
00613 
00614   std::string value = hidden.name;
00615   EXPECT_THAT(value, Eq("Impl::NewName"));
00616   EXPECT_THAT(hidden.name(), Eq("Impl::NewName"));
00617   EXPECT_THAT(hidden.name.Get(), Eq("Impl::NewName"));
00618 }
00619 
00620 // A simple class that just has a reader and writer functon.
00621 template <typename VALUE_TYPE>
00622 class RWPropHolder
00623 {
00624 public:
00625   RWPropHolder(VALUE_TYPE const& initial)
00626     : prop(sigc::mem_fun(this, &RWPropHolder<VALUE_TYPE>::get_prop),
00627            sigc::mem_fun(this, &RWPropHolder<VALUE_TYPE>::set_prop))
00628     , prop_(initial)
00629     {}
00630   nux::RWProperty<VALUE_TYPE> prop;
00631 
00632 private:
00633   VALUE_TYPE get_prop() const { return prop_; }
00634   bool set_prop(VALUE_TYPE const& prop) { prop_ = prop; return true; }
00635 
00636   VALUE_TYPE prop_;
00637 
00638 };
00639 
00640 TEST(TestRWProperty, TestIntOperators) {
00641   RWPropHolder<int> int_prop(42);
00642 
00643   EXPECT_TRUE(int_prop.prop == 42);
00644   EXPECT_TRUE(42 == int_prop.prop);
00645   EXPECT_FALSE(int_prop.prop != 42);
00646   EXPECT_FALSE(42 != int_prop.prop);
00647 
00648   EXPECT_FALSE(int_prop.prop == 5);
00649   EXPECT_FALSE(5 == int_prop.prop);
00650   EXPECT_TRUE(int_prop.prop != 5);
00651   EXPECT_TRUE(5 != int_prop.prop);
00652 
00653   EXPECT_FALSE(int_prop.prop < 5);
00654   EXPECT_FALSE(int_prop.prop <= 5);
00655   EXPECT_TRUE(int_prop.prop > 5);
00656   EXPECT_TRUE(int_prop.prop >= 5);
00657 
00658   EXPECT_TRUE(5 < int_prop.prop);
00659   EXPECT_TRUE(5 <= int_prop.prop);
00660   EXPECT_FALSE(5 > int_prop.prop);
00661   EXPECT_FALSE(5 >= int_prop.prop);
00662 
00663   RWPropHolder<int> int_prop2(42);
00664   EXPECT_TRUE(int_prop2.prop == int_prop.prop);
00665   EXPECT_FALSE(int_prop2.prop != int_prop.prop);
00666 
00667   int_prop2.prop = 5;
00668 
00669   EXPECT_FALSE(int_prop2.prop == int_prop.prop);
00670   EXPECT_TRUE(int_prop2.prop != int_prop.prop);
00671 
00672   EXPECT_FALSE(int_prop.prop < int_prop2.prop);
00673   EXPECT_FALSE(int_prop.prop <= int_prop2.prop);
00674   EXPECT_TRUE(int_prop.prop > int_prop2.prop);
00675   EXPECT_TRUE(int_prop.prop >= int_prop2.prop);
00676 }
00677 
00678 // Only testing strings and ints, to show that the template classes work with
00679 // both primitive types and classes.
00680 TEST(TestRWProperty, TestStringOperators) {
00681   std::string value("Hello");
00682   RWPropHolder<std::string> str_prop(value);
00683 
00684   EXPECT_TRUE(str_prop.prop == "Hello");
00685   EXPECT_TRUE("Hello" == str_prop.prop);
00686   EXPECT_FALSE(str_prop.prop != "Hello");
00687   EXPECT_FALSE("Hello" != str_prop.prop);
00688   EXPECT_TRUE(str_prop.prop == value);
00689   EXPECT_TRUE(value == str_prop.prop);
00690   EXPECT_FALSE(str_prop.prop != value);
00691   EXPECT_FALSE(value != str_prop.prop);
00692 
00693   EXPECT_FALSE(str_prop.prop == "World");
00694   EXPECT_FALSE("World" == str_prop.prop);
00695   EXPECT_TRUE(str_prop.prop != "World");
00696   EXPECT_TRUE("World" != str_prop.prop);
00697 
00698   EXPECT_FALSE(str_prop.prop < "Aardvark");
00699   EXPECT_FALSE(str_prop.prop <= "Aardvark");
00700   EXPECT_TRUE(str_prop.prop > "Aardvark");
00701   EXPECT_TRUE(str_prop.prop >= "Aardvark");
00702 
00703   EXPECT_TRUE("Aardvark" < str_prop.prop);
00704   EXPECT_TRUE("Aardvark" <= str_prop.prop);
00705   EXPECT_FALSE("Aardvark" > str_prop.prop);
00706   EXPECT_FALSE("Aardvark" >= str_prop.prop);
00707 
00708   RWPropHolder<std::string> str_prop2(value);
00709   EXPECT_TRUE(str_prop2.prop == str_prop.prop);
00710   EXPECT_FALSE(str_prop2.prop != str_prop.prop);
00711 
00712   str_prop2.prop = "Aardvark";
00713 
00714   EXPECT_FALSE(str_prop2.prop == str_prop.prop);
00715   EXPECT_TRUE(str_prop2.prop != str_prop.prop);
00716 
00717   EXPECT_FALSE(str_prop.prop < str_prop2.prop);
00718   EXPECT_FALSE(str_prop.prop <= str_prop2.prop);
00719   EXPECT_TRUE(str_prop.prop > str_prop2.prop);
00720   EXPECT_TRUE(str_prop.prop >= str_prop2.prop);
00721 }
00722 
00723 struct TestProperties : nux::Introspectable
00724 {
00725   TestProperties()
00726     : name(this, "name")
00727     , index(this, "index")
00728     {}
00729 
00730   nux::SerializableProperty<std::string> name;
00731   nux::SerializableProperty<int> index;
00732 };
00733 
00734 TEST(TestIntrospectableProperty, TestSimplePropertyAccess) {
00735   TestProperties props;
00736   ChangeRecorder<std::string> recorder;
00737   props.name.changed.connect(recorder.listener());
00738   EXPECT_EQ("", props.name());
00739   EXPECT_EQ(0, props.index());
00740   props.name = "Testing";
00741   props.index = 5;
00742   EXPECT_EQ("Testing", props.name());
00743   props.name("New Value");
00744   EXPECT_EQ("New Value", props.name());
00745   props.name.Set("Another");
00746   EXPECT_EQ("Another", props.name());
00747 
00748   EXPECT_EQ(3, recorder.size());
00749   EXPECT_EQ("Testing", recorder.changed_values[0]);
00750   EXPECT_EQ("New Value", recorder.changed_values[1]);
00751   EXPECT_EQ("Another", recorder.changed_values[2]);
00752 }
00753 
00754 TEST(TestIntrospectableProperty, TestPropertyAccessByName) {
00755   TestProperties props;
00756   ChangeRecorder<std::string> name_recorder;
00757   ChangeRecorder<int> index_recorder;
00758   props.name.changed.connect(name_recorder.listener());
00759   props.index.changed.connect(index_recorder.listener());
00760 
00761   props.name = "Testing";
00762   props.index = 5;
00763   EXPECT_EQ("Testing", props.GetProperty<std::string>("name"));
00764   EXPECT_EQ("5", props.GetProperty<std::string>("index"));
00765   EXPECT_EQ(5, props.GetProperty<int>("index"));
00766 
00767   bool assigned = props.SetProperty("name", "New value");
00768   EXPECT_TRUE(assigned);
00769   EXPECT_EQ("New value", props.name());
00770   EXPECT_EQ("New value", props.GetProperty<std::string>("name"));
00771   // A little dangreous, but legal.
00772   EXPECT_EQ(0, props.GetProperty<int>("name"));
00773 
00774   assigned = props.SetProperty("name", 42);
00775   EXPECT_TRUE(assigned);
00776   EXPECT_EQ("42", props.name());
00777   EXPECT_EQ("42", props.GetProperty<std::string>("name"));
00778   // A little dangreous, but legal.
00779   EXPECT_EQ(42, props.GetProperty<int>("name"));
00780 
00781   assigned = props.SetProperty("index", 42);
00782   EXPECT_TRUE(assigned);
00783   EXPECT_EQ(42, props.index());
00784   EXPECT_EQ("42", props.GetProperty<std::string>("index"));
00785   EXPECT_EQ(42, props.GetProperty<int>("index"));
00786 
00787   assigned = props.SetProperty("index", "hello");
00788   EXPECT_FALSE(assigned);
00789   EXPECT_EQ(42, props.index());
00790   EXPECT_EQ("42", props.GetProperty<std::string>("index"));
00791   EXPECT_EQ(42, props.GetProperty<int>("index"));
00792 
00793   // Gettin a non-existant property returns a default constructed instance.
00794   std::string surname = props.GetProperty<std::string>("surname");
00795   EXPECT_EQ("", surname);
00796   int foo = props.GetProperty<int>("foo");
00797   EXPECT_EQ(0, foo);
00798 
00799   assigned = props.SetProperty("non-existant", "hello");
00800   EXPECT_FALSE(assigned);
00801 }
00802 
00803 
00804 }