PropertyObject enhancements, unit-test for make check
This commit is contained in:
1
simgear/props/.gitignore
vendored
1
simgear/props/.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
props_test
|
||||
propertyObject_test
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<T>& aOther) :
|
||||
PropertyObjectBase(aOther)
|
||||
{
|
||||
}
|
||||
|
||||
// create() form creates the property immediately
|
||||
static PropertyObject<T> 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:
|
||||
};
|
||||
|
||||
|
||||
155
simgear/props/propertyObject_test.cxx
Normal file
155
simgear/props/propertyObject_test.cxx
Normal file
@@ -0,0 +1,155 @@
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include "propertyObject.hxx"
|
||||
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
|
||||
using namespace simgear;
|
||||
|
||||
SGPropertyNode* testRoot = NULL;
|
||||
|
||||
bool testBasic()
|
||||
{
|
||||
PropertyObject<int> aBar("a/bar");
|
||||
assert(aBar == 1234);
|
||||
|
||||
|
||||
PropertyObject<int> 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<double> 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<std::string> 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<int> a1("a/bar");
|
||||
PropertyObject<int> 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<int> a3(a1);
|
||||
assert(a1.node() == a3.node());
|
||||
a3 = 44;
|
||||
assert(a1 == 44);
|
||||
|
||||
}
|
||||
|
||||
void testSTLContainer()
|
||||
{
|
||||
std::vector<PropertyObject<int> > vec;
|
||||
// enlarging the vec causes the copy-constructor to be called,
|
||||
// when the storage is re-sized
|
||||
vec.push_back(PropertyObject<int>("a/thing[0]"));
|
||||
vec.push_back(PropertyObject<int>("a/thing[1]"));
|
||||
vec.push_back(PropertyObject<int>("a/thing[2]"));
|
||||
vec.push_back(PropertyObject<int>("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<int>(path));
|
||||
testRoot->setIntValue(path, i * 4);
|
||||
}
|
||||
|
||||
assert(vec[0] == 1234);
|
||||
assert(vec[3] == -11);
|
||||
}
|
||||
|
||||
void testReadMissing()
|
||||
{
|
||||
PropertyObject<bool> b("not/found/honest");
|
||||
|
||||
try {
|
||||
bool v = b;
|
||||
assert(false && "read of missing property didn't throw");
|
||||
} catch (sg_exception& e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
PropertyObject<std::string> 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user