From ac535de2fa614e7ee18b766874c937ddc6476af6 Mon Sep 17 00:00:00 2001 From: James Turner Date: Sat, 20 Nov 2010 02:49:04 -0800 Subject: [PATCH] PropertyObject enhancements, unit-test for make check --- simgear/props/.gitignore | 1 + simgear/props/Makefile.am | 12 +- simgear/props/propertyObject.cxx | 35 ++---- simgear/props/propertyObject.hxx | 38 ++++++- simgear/props/propertyObject_test.cxx | 155 ++++++++++++++++++++++++++ 5 files changed, 208 insertions(+), 33 deletions(-) create mode 100644 simgear/props/propertyObject_test.cxx diff --git a/simgear/props/.gitignore b/simgear/props/.gitignore index 671825c5..8da794e8 100644 --- a/simgear/props/.gitignore +++ b/simgear/props/.gitignore @@ -1,2 +1,3 @@ props_test +propertyObject_test diff --git a/simgear/props/Makefile.am b/simgear/props/Makefile.am index c39bd0a0..23666451 100644 --- a/simgear/props/Makefile.am +++ b/simgear/props/Makefile.am @@ -17,7 +17,8 @@ libsgprops_a_SOURCES = \ AtomicChangeListener.cxx \ propertyObject.cxx -check_PROGRAMS = props_test +check_PROGRAMS = props_test propertyObject_test +TESTS = propertyObject_test props_test_SOURCES = props_test.cxx props_test_LDADD = \ @@ -27,6 +28,15 @@ props_test_LDADD = \ $(top_builddir)/simgear/debug/libsgdebug.a \ $(top_builddir)/simgear/structure/libsgstructure.a +propertyObject_test_SOURCES = propertyObject_test.cxx +propertyObject_test_LDADD = \ + libsgprops.a \ + $(top_builddir)/simgear/xml/libsgxml.a \ + $(top_builddir)/simgear/misc/libsgmisc.a \ + $(top_builddir)/simgear/debug/libsgdebug.a \ + $(top_builddir)/simgear/structure/libsgstructure.a + + if HAVE_FRAMEWORK_OSG props_test_LDFLAGS = $(openthreads_FRAMEWORK) else diff --git a/simgear/props/propertyObject.cxx b/simgear/props/propertyObject.cxx index ff90ce77..0685ae91 100644 --- a/simgear/props/propertyObject.cxx +++ b/simgear/props/propertyObject.cxx @@ -31,6 +31,14 @@ void PropertyObjectBase::setDefaultRoot(SGPropertyNode* aRoot) static_defaultRoot = aRoot; } +PropertyObjectBase::PropertyObjectBase(const PropertyObjectBase& aOther) : + _base(aOther._base), + _path(aOther._path), + _prop(aOther._prop) +{ + +} + PropertyObjectBase::PropertyObjectBase(const char* aChild) : _base(NULL), _path(aChild), @@ -62,30 +70,3 @@ SGPropertyNode* PropertyObjectBase::node(bool aCreate) const } // of namespace simgear -void test() -{ - SGPropObjDouble foo("/bar/foo"); - - SGPropertyNode* zoob; - - SGPropObjDouble foo2 = SGPropObjDouble::create(zoob, "foo2", 42.0); - - foo = 1123.0; - foo2 = 43; - - std::string s("lalala"); - - foo = "lalal"; - - - SGPropObjString sp(zoob); - sp = "fooo"; - s = sp; - - - SGPropObjBool bp("/some nice big path"); - bp = false; - - bp = 456; - int i5 = bp; -} diff --git a/simgear/props/propertyObject.hxx b/simgear/props/propertyObject.hxx index 0067cb5e..7aeb0337 100644 --- a/simgear/props/propertyObject.hxx +++ b/simgear/props/propertyObject.hxx @@ -29,6 +29,8 @@ class PropertyObjectBase public: static void setDefaultRoot(SGPropertyNode* aRoot); + PropertyObjectBase(const PropertyObjectBase& aOther); + PropertyObjectBase(const char* aChild); PropertyObjectBase(SGPropertyNode* aNode, const char* aChild = NULL); @@ -61,6 +63,12 @@ public: } +// copy-constructor + PropertyObject(const PropertyObject& aOther) : + PropertyObjectBase(aOther) + { + } + // create() form creates the property immediately static PropertyObject create(const char* aPath, T aValue) { @@ -86,7 +94,7 @@ public: // conversion operators operator T () const { - SGPropertyNode* n = node(false); + SGPropertyNode* n = node(); if (!n) { throw sg_exception("read of undefined property:", _path); } @@ -96,7 +104,7 @@ public: T operator=(const T& aValue) { - SGPropertyNode* n = node(true); + SGPropertyNode* n = PropertyObjectBase::node(true); if (!n) { return aValue; } @@ -105,6 +113,10 @@ public: return aValue; } + SGPropertyNode* node() const + { + return PropertyObjectBase::node(false); + } }; // of template PropertyObject @@ -130,7 +142,7 @@ public: operator std::string () const { - SGPropertyNode* n = node(false); + SGPropertyNode* n = node(); if (!n) { throw sg_exception("read of undefined property:", _path); } @@ -140,7 +152,7 @@ public: const char* operator=(const char* aValue) { - SGPropertyNode* n = node(true); + SGPropertyNode* n = PropertyObjectBase::node(true); if (!n) { return aValue; } @@ -151,7 +163,7 @@ public: std::string operator=(const std::string& aValue) { - SGPropertyNode* n = node(true); + SGPropertyNode* n = PropertyObjectBase::node(true); if (!n) { return aValue; } @@ -160,6 +172,22 @@ public: return aValue; } + bool operator==(const char* value) const + { + std::string s(*this); + return (s == value); + } + + bool operator==(const std::string& value) const + { + std::string s(*this); + return (s == value); + } + + SGPropertyNode* node() const + { + return PropertyObjectBase::node(false); + } private: }; diff --git a/simgear/props/propertyObject_test.cxx b/simgear/props/propertyObject_test.cxx new file mode 100644 index 00000000..38e925e8 --- /dev/null +++ b/simgear/props/propertyObject_test.cxx @@ -0,0 +1,155 @@ + +#include + +#include +#include +#include + +#include "propertyObject.hxx" + +using std::cout; +using std::cerr; +using std::endl; + +using namespace simgear; + +SGPropertyNode* testRoot = NULL; + +bool testBasic() +{ + PropertyObject aBar("a/bar"); + assert(aBar == 1234); + + + PropertyObject aWib("a/wib"); // doesn't exist + aWib = 999; // create + set + assert(aWib == 999); // read back + assert(testRoot->getIntValue("a/wib") == 999); + + assert(aWib < 1000); + assert(998 < aWib); + + PropertyObject aFoo("a/foo"); + assert(aFoo == 12.0); + + double ff(aFoo); + assert(ff == 12.0); // comparison with literal + + const float fff(12.0f); + assert(fff == aFoo); // comparion with float value + + return true; +} + +void testString() +{ + PropertyObject sp("a/alice"); + assert(sp == "aaaa"); // read + + sp = "xxxx"; // assignment from char* literal + assert(!strcmp(testRoot->getStringValue("a/alice"), "xxxx")); + + std::string d = "yyyy"; + sp = d; // assignment from std::string + assert(sp == d); // comaprisom with std::string + + std::string e(sp), f; // check construction-conversion + assert(e == "yyyy"); + f = sp; // assignment conversion + assert(f == "yyyy"); +} + +void testAssignment() +{ + PropertyObject a1("a/bar"); + PropertyObject a2("b/blah/foo[1]"); + + // ensure assignment between property objects copies values, *not* + // copies the property reference + a2 = a1 = 88; // a2 should *not* point to a/bar after this! + assert(testRoot->getIntValue("b/blah/foo[1]") == 88); + assert(a2.node() == testRoot->getNode("b/blah/foo[1]")); + a2 = 99; + assert(a2 == 99); + assert(a1 == 88); + + PropertyObject a3(a1); + assert(a1.node() == a3.node()); + a3 = 44; + assert(a1 == 44); + +} + +void testSTLContainer() +{ + std::vector > vec; +// enlarging the vec causes the copy-constructor to be called, +// when the storage is re-sized + vec.push_back(PropertyObject("a/thing[0]")); + vec.push_back(PropertyObject("a/thing[1]")); + vec.push_back(PropertyObject("a/thing[2]")); + vec.push_back(PropertyObject("a/thing[3]")); + + vec[0] = 1234; + vec[1] = 2345; + vec[2] = 6789; + vec[3] = -11; + + assert(testRoot->getIntValue("a/thing[2]") == 6789); + assert(testRoot->getIntValue("a/thing[3]") == -11); + assert(testRoot->getIntValue("a/thing[0]") == 1234); + + for (int i=0; i<100; ++i) { + char path[128]; + ::snprintf(path, 128, "d/foo[%d]", i); + vec.push_back(PropertyObject(path)); + testRoot->setIntValue(path, i * 4); + } + + assert(vec[0] == 1234); + assert(vec[3] == -11); +} + +void testReadMissing() +{ + PropertyObject b("not/found/honest"); + + try { + bool v = b; + assert(false && "read of missing property didn't throw"); + } catch (sg_exception& e) { + // expected + } + + PropertyObject s("also/missing"); + try { + std::string s2 = s; + } catch (sg_exception& e) { + // expected + } +} + +int main(int argc, char* argv[]) +{ + testRoot = new SGPropertyNode(); + simgear::PropertyObjectBase::setDefaultRoot(testRoot); + +// create some properties 'manually' + testRoot->setDoubleValue("a/foo", 12.0); + testRoot->setIntValue("a/bar", 1234); + testRoot->setBoolValue("a/flags[3]", true); + testRoot->setStringValue("a/alice", "aaaa"); + +// basic reading / setting + if (!testBasic()) { + return EXIT_FAILURE; + } + + testReadMissing(); + testString(); + testAssignment(); + testSTLContainer(); + + return EXIT_SUCCESS; +} + -- 2.39.5