Main Page | Namespace List | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Namespace Members | Data Fields | Globals

reflect/test/unit_test.cpp

Go to the documentation of this file.
00001 //
00002 // Copyright (c) 2003
00003 // Paul Hamilton; pHamtec P/L
00004 //
00005 // Permission to use, copy, modify, distribute and sell this software
00006 // and its documentation for any purpose is hereby granted without fee, 
00007 // provided that the above copyright notice appears in all copies and 
00008 // that both the copyright notice and this permission notice appear in 
00009 // supporting documentation. No representations are made about the 
00010 // suitability of this software for any purpose. It is provided "as is" 
00011 // without express or implied warranty.
00012 //
00013 // unit_test.cpp
00014 //
00015 // 4-Jul-2003  phamilton  Created
00016 //
00017 
00018 #include <iostream>
00019 #include <vector>
00020 #include <string>
00021 #include <boost/test/included/unit_test_framework.hpp>
00022 #include "../object_visitor.hpp"
00023 #include "../jscript_object_navigator.hpp"
00024 #include "../jscript_object_nav_errors.h"
00025 #include "../member_visitor.hpp"
00026 #include "root.hpp"
00027 #include "foo.hpp"
00028 #include "bar.hpp"
00029 
00030 using namespace ph::reflect;
00031 using namespace reflect_test;
00032 using boost::unit_test_framework::test_suite;
00033 using boost::test_toolbox::output_test_stream;
00034 
00035 static void set(base *obj, const std::string &name, const std::string &val)
00036 {
00037         set_member_visitor v(name, val);
00038         obj->accept(&v);
00039 }
00040 
00041 static std::string get(base *obj, const std::string &name)
00042 {
00043         ph::common::get_member_value_visitor v(name);
00044         obj->accept(&v);
00045         return v.get();
00046 }
00047 
00048 // here are some macros we use to test whether an object with a particular path has the correct name.
00049 // they are macros so that they will display the correct line number.
00050 
00051 #define TEST_OBJ_NAME(_obj_, _path_, _name_) \
00052 { \
00053         ph::common::object_base *o = nav.navigate(_obj_, _path_); \
00054         BOOST_CHECK(output.is_empty()); \
00055         BOOST_REQUIRE_MESSAGE(o, "could not find [" _path_ "]"); \
00056         std::string name; \
00057         BOOST_CHECK_MESSAGE(ph::common::get_visitable_obj_name(o, &name), \
00058                 "[" _path_ "] object does not have a name."); \
00059         BOOST_CHECK_MESSAGE(name == _name_, \
00060                 "[" _path_ "] was named [" + name + "] not [" _name_ "]"); \
00061 }
00062 
00063 #define TEST_BAD_PARSE(_obj_, _path_, _msg_, _name_) \
00064 { \
00065         BOOST_CHECK(nav.navigate(_obj_, _path_) == 0); \
00066         BOOST_CHECK_MESSAGE(output.is_equal( \
00067                 "Syntax Error. " _msg_ " [" _name_ "]\n"), "Syntax Error. " _msg_ " [" _name_ "]"); \
00068 }
00069 
00070 namespace reflect_test {
00071 
00072 class test_simple
00073 {
00074 public:
00075         void test()
00076         {
00077                 foo *o = new foo("foo", "foo");
00078                 BOOST_REQUIRE_MESSAGE(o, "could not create foo object.");
00079                 set(o, "x", "1");
00080                 set(o, "y", "2.1");
00081                 set(o, "z", "true");
00082                 BOOST_CHECK(get(o, "x") == "1");
00083                 BOOST_CHECK(get(o, "y") == "2.1");
00084                 BOOST_CHECK(get(o, "z") == "true");
00085                 delete o;
00086         }
00087 };
00088 
00089 class test_composite
00090 {
00091 public:
00092                         
00093         void test()
00094         {
00095                 {
00096                         // create a root object.
00097                         root *r = new root("root", "root");
00098                         
00099                         // now search for a particular object using the object parser.
00100                         output_test_stream output;
00101                         jscript_object_navigator nav(r, &output, false, false);
00102                         
00103                         // test adding new members to the composites.
00104                         ph::common::object_base *p = nav.navigate(r, "root().foos()");
00105                         BOOST_CHECK(output.is_empty());
00106                         BOOST_REQUIRE(p);
00107                         BOOST_REQUIRE_MESSAGE(p->composition(), 
00108                                 "object does not implement composite interface.");
00109                         ph::common::composite_object_base *c = 
00110                                 p->composition()->composite();
00111                         BOOST_REQUIRE_MESSAGE(c, "foos was not a composite object.");
00112                         
00113                         // create a new foo object.
00114                         foo *foo_1 = new foo("foo", "foo_1");
00115                         BOOST_REQUIRE_MESSAGE(foo_1, "could not create foo object.");
00116                         BOOST_CHECK(c->add(foo_1, true));
00117         
00118                         // make sure it's there.
00119                         TEST_OBJ_NAME(r, "root().foos(1)", "foo_1");
00120                         
00121                         // now remove it.
00122                         BOOST_CHECK(c->remove(foo_1));
00123                         
00124                         // make sure it's not there.
00125                         TEST_BAD_PARSE(r, "root().foos(1)", 
00126                                 "Object with numeric subscript was not found.", "1");
00127         
00128                         // test the singleton composite to make sure that errors working.
00129                         TEST_BAD_PARSE(r, "root().a_foo", "Singleton composite was empty.", "a_foo");
00130         
00131                         // now add foo onto the a_foo
00132                         p = nav.navigate(r, "root().a_foo()");
00133                         BOOST_CHECK(output.is_empty());
00134                         BOOST_REQUIRE(p);
00135                         BOOST_REQUIRE_MESSAGE(p->composition(), 
00136                                 "object does not implement composite interface.");
00137                         c = p->composition()->composite();
00138                         BOOST_REQUIRE_MESSAGE(c, "object was not a composite object.");
00139         
00140                         BOOST_CHECK(c->add(foo_1, true));
00141         
00142                         // make sure it's there.
00143                         TEST_OBJ_NAME(r, "root().a_foo", "foo_1");
00144         
00145                         delete r;
00146                 }
00147                 {
00148                         // create a root object.
00149                         root *r = new root("root", "root");
00150                         
00151                         // now search for a particular object using the object parser.
00152                         output_test_stream output;
00153                         jscript_object_navigator nav(r, &output, false);
00154                         
00155                         // now add a bunch of foos and bars to this object.
00156                         r->addfoosandbars();
00157 
00158                         // test the parent-relationship of composites.
00159                         ph::common::object_base *bar_2 = nav.navigate(r, "root().bars('bar_2')");
00160                         BOOST_CHECK(output.is_empty());
00161                         BOOST_CHECK(bar_2);
00162                         if (bar_2)
00163                         {
00164                                 // get bars
00165                                 ph::common::object_base *bars = nav.navigate(r, "root().bars()");
00166                                 BOOST_CHECK(output.is_empty());
00167                                 BOOST_CHECK(bars);
00168                                 if (bars)
00169                                         test_parents(bar_2, bars, "bars");
00170                         }
00171                         
00172                         // test the parent-relationship of references.
00173                         ph::common::object_base *foo_3 = nav.navigate(r, "root().a_foo");
00174                         BOOST_CHECK(output.is_empty());
00175                         BOOST_CHECK(foo_3);
00176                         if (foo_3)
00177                         {
00178                                 // get a_foo
00179                                 ph::common::object_base *a_foo = nav.navigate(r, "root().a_foo()");
00180                                 BOOST_CHECK(output.is_empty());
00181                                 BOOST_CHECK(a_foo);
00182                                 if (a_foo)
00183                                         test_parents(foo_3, a_foo, "a_foo");
00184                         }
00185 
00186                         delete r;
00187                 }
00188         }
00189         
00190         void test_parents(ph::common::object_base *obj, 
00191                         ph::common::object_base *composite, const std::string &parentname)
00192         /*
00193                 test the parent-relationship of composites.
00194         */
00195         {
00196                 // see what the name of the parent of this guy is.
00197                 BOOST_REQUIRE_MESSAGE(obj->outerable(), 
00198                         "object doesn't implement outer interface.");
00199                 ph::common::object_base *parent = obj->outerable()->outer();
00200                 BOOST_CHECK(parent);
00201                 if (parent)
00202                 {
00203                         // test comparable interface.
00204                         BOOST_REQUIRE_MESSAGE(parent->comparable(), 
00205                                 "parent doesn't implement comparable interface");
00206                         BOOST_CHECK(parent->comparable()->equal(composite));
00207                         
00208                         // now walk out and make sure all the parents are correct.
00209                         std::string name;
00210                         BOOST_CHECK_MESSAGE(ph::common::get_visitable_obj_name(parent, &name),
00211                                                 "object does not have a name.");
00212                         BOOST_CHECK(name == parentname);
00213                         BOOST_REQUIRE_MESSAGE(parent->outerable(), 
00214                                 "parent doesn't implement outer interface.");
00215                         parent = parent->outerable()->outer();
00216                         BOOST_CHECK(parent);
00217                         if (parent)
00218                         {
00219                                 BOOST_CHECK_MESSAGE(ph::common::get_visitable_obj_name(parent, &name),
00220                                                 "object does not have a name.");
00221                                 BOOST_CHECK(name == "root");
00222                                 BOOST_REQUIRE_MESSAGE(parent->outerable(), 
00223                                         "parent doesn't implement outer interface.");
00224                                 BOOST_CHECK(parent->outerable()->outer() == 0);
00225                         }
00226                 }
00227         }
00228 };
00229 
00230 class test_navigation
00231 {
00232 public:
00233 
00234         void test()
00235         {
00236                 // create a root object.
00237                 root *r = new root("root", "root");
00238                 
00239                 // now add a bunch of foos and bars to this object.
00240                 r->addfoosandbars();
00241                 
00242                 // now search for a particular object using the object parser.
00243                 output_test_stream output;
00244                 jscript_object_navigator nav(r, &output, false, false);
00245                 
00246                 // test root() navigation.
00247                 TEST_OBJ_NAME(r, "root()", "root");
00248         
00249                 // test sub-object navigation.
00250                 TEST_OBJ_NAME(r, "root().foos('foo_2')", "foo_2");
00251                 TEST_OBJ_NAME(r, "root().foos(1)", "foo_1");
00252                 TEST_OBJ_NAME(r, "root().foos(2)", "foo_2");
00253                 TEST_OBJ_NAME(r, "root().bars('bar_1')", "bar_1");
00254                 TEST_OBJ_NAME(r, "root().bars(1)", "bar_1");
00255                 TEST_OBJ_NAME(r, "root().bars(2)", "bar_2");
00256         
00257                 // test for invalid composites.
00258                 TEST_BAD_PARSE(r, "root().foos", 
00259                         "Object was not a singleton composite. Did you mean to use ()?.", "foos");
00260 
00261                 // test composite navigation.
00262                 TEST_OBJ_NAME(r, "root().foos()", "foos");
00263                 TEST_OBJ_NAME(r, "root().a_foo()", "a_foo");
00264 
00265                 // test for our object reference special case. 
00266                 // The name of the composite actually returns the 
00267                 // object attached.
00268                 TEST_OBJ_NAME(r, "root().a_foo", "foo_3");
00269                 
00270                 // test complicated queries.
00271                 TEST_OBJ_NAME(r, "root().foos('foo_2').parent().bars('bar_1')", "bar_1");
00272         
00273                 // test for gobbledegook.
00274                 
00275                 // no composites.
00276                 TEST_BAD_PARSE(r, "()", "No builtin or composite found.", "");
00277                 TEST_BAD_PARSE(r, "xxxxx()", "No builtin or composite found.", "xxxxx");
00278                 TEST_BAD_PARSE(r, "root().xxxxx()", "No builtin or composite found.", "xxxxx");
00279                 TEST_BAD_PARSE(r, "root().()", "No builtin or composite found.", "");
00280 
00281                 TEST_BAD_PARSE(r, "yyyy(1)", "No composite found.", "yyyy");
00282 
00283                 TEST_BAD_PARSE(r, "root().foos(1).parent('xxxx')", "Parent was not found.", "xxxx");
00284                 TEST_BAD_PARSE(r, "root().foos(1).parent(2)", 
00285                         "Parent with subscript was not found.", "2");
00286 
00287                 TEST_BAD_PARSE(r, "root().foos(5)", 
00288                         "Object with numeric subscript was not found.", "5");
00289 
00290                 TEST_BAD_PARSE(r, "root().foos('xxxx')", 
00291                         "Object with name subscript was not found.", "'xxxx'");
00292 
00293                 // couldn't find objects.
00294                 TEST_BAD_PARSE(r, "xxxxx", "No composite found.", "xxxxx");
00295                 TEST_BAD_PARSE(r, "root().xxxxx", "No composite found.", "xxxxx");
00296                 TEST_BAD_PARSE(r, "root().foos('foo_1", "No composite found.", "foos('foo_1");
00297                 TEST_BAD_PARSE(r, "root().foos('foo_1'", "No composite found.", "foos('foo_1'");
00298                 TEST_BAD_PARSE(r, "root().foos('", "No composite found.", "foos('");
00299                 TEST_BAD_PARSE(r, "root().foos(", "No composite found.", "foos(");
00300                 TEST_BAD_PARSE(r, "root(", "No composite found.", "root(");
00301                 
00302                 // couldn't parse.
00303                 TEST_BAD_PARSE(r, "....", "Empty part. Couldn't Parse.", "....");
00304 
00305                 delete r;
00306         }
00307 };
00308 
00309 class test_dump
00310 {
00311 public:
00312         test_dump(const std::string &filename) :
00313                 _filename(filename)
00314                         {};
00315                         
00316         void test()
00317         {
00318                 // create a root object.
00319                 root *r = new root("root", "root");
00320                 
00321                 // now add a bunch of foos and bars to this object.
00322                 r->addfoosandbars();
00323                 
00324                 {
00325                         output_test_stream output(_filename, true);
00326                         {
00327                                 dump_object_visitor v(&output);
00328                                 BOOST_CHECK(r->accept(&v));
00329                         }
00330                         BOOST_CHECK(output.match_pattern());
00331                 }
00332         
00333                 delete r;
00334         }
00335 
00336 private:
00337         std::string _filename;
00338 };
00339 
00340 };
00341 
00342 test_suite *init_unit_test_suite(int argc, char* argv[]) 
00343 {
00344     test_suite * test = BOOST_TEST_SUITE("reflect units tests");
00345     
00346         test->add(BOOST_CLASS_TEST_CASE(&test_simple::test, 
00347                 boost::shared_ptr<test_simple>(new test_simple())));
00348         test->add(BOOST_CLASS_TEST_CASE(&test_composite::test, 
00349                 boost::shared_ptr<test_composite>(new test_composite())));      
00350         test->add(BOOST_CLASS_TEST_CASE(&test_navigation::test, 
00351                 boost::shared_ptr<test_navigation>(new test_navigation())));
00352         test->add(BOOST_CLASS_TEST_CASE(&test_dump::test, 
00353                 boost::shared_ptr<test_dump>(new test_dump(argv[1]))));
00354 
00355     return test;
00356 }

Generated on Wed Apr 5 22:03:26 2006 for cppxmlobj by  doxygen 1.4.3