nux-1.16.0
|
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 }