Fixes the "weirdness" with MSVC complaining about incomplete class specs, since forward declarations (SGMathFwd.hxx) are used in props.hxx only. Only the few extended (vector) property templates require including the full SGMath.hxx (with MSVC) - and these are used in few places.
212 lines
4.9 KiB
C++
212 lines
4.9 KiB
C++
#ifdef HAVE_CONFIG_H
|
|
# include <simgear_config.h>
|
|
#endif
|
|
|
|
#ifdef NDEBUG
|
|
// Always enable DEBUG mode in test application, otherwise "assert" test
|
|
// statements have no effect and don't actually test anything (catch 17 ;-) ).
|
|
#undef NDEBUG
|
|
#endif
|
|
|
|
#include <simgear/compiler.h>
|
|
|
|
#include <iostream>
|
|
#include <cassert>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
#include "propertyObject.hxx"
|
|
|
|
#include <simgear/structure/exception.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
|
|
if (ff != 12.0) cout << "Error: a/foo != 12!" << endl;
|
|
|
|
const float fff(12.0f);
|
|
assert(fff == aFoo); // comparion with float value
|
|
if (fff != aFoo) cout << "Error: 12 != a/foo" << endl;
|
|
|
|
return true;
|
|
}
|
|
|
|
void testRelative()
|
|
{
|
|
SGPropertyNode* n = testRoot->getNode("a");
|
|
assert(n);
|
|
|
|
PropertyObject<int> a1(n, "bar");
|
|
assert(a1 == 1234);
|
|
|
|
PropertyObject<int> a5(n, "some/child/path");
|
|
a5 = 4321;
|
|
assert(n->getIntValue("some/child/path") == 4321);
|
|
|
|
SGPropertyNode* m = testRoot->getNode("a/alice");
|
|
PropertyObject<std::string> a4(m);
|
|
assert(a4 == "aaaa");
|
|
}
|
|
|
|
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");
|
|
(void) v; // don't warn about unused variable
|
|
} catch (sg_exception& e) {
|
|
// expected
|
|
}
|
|
|
|
PropertyObject<std::string> s("also/missing");
|
|
try {
|
|
std::string s2 = s;
|
|
} catch (sg_exception& e) {
|
|
// expected
|
|
}
|
|
}
|
|
|
|
void testCreate()
|
|
{
|
|
PropertyObject<bool> a = PropertyObject<bool>::create("a/lemon", true);
|
|
assert(a == true);
|
|
assert(testRoot->getBoolValue("a/lemon") == true);
|
|
|
|
|
|
PropertyObject<int> b(PropertyObject<int>::create("a/pear", 3142));
|
|
assert(b == 3142);
|
|
|
|
PropertyObject<std::string> c(PropertyObject<std::string>::create("a/lime", "fofofo"));
|
|
assert(c == "fofofo");
|
|
|
|
// check overloads for string version
|
|
SGPropertyNode* n = testRoot->getNode("b", true);
|
|
PropertyObject<std::string> d(PropertyObject<std::string>::create(n, "grape", "xyz"));
|
|
assert(!strcmp(testRoot->getStringValue("b/grape"), "xyz"));
|
|
|
|
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
testRelative();
|
|
testReadMissing();
|
|
testString();
|
|
testAssignment();
|
|
testSTLContainer();
|
|
testCreate();
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|