00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
00049
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
00097 root *r = new root("root", "root");
00098
00099
00100 output_test_stream output;
00101 jscript_object_navigator nav(r, &output, false, false);
00102
00103
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
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
00119 TEST_OBJ_NAME(r, "root().foos(1)", "foo_1");
00120
00121
00122 BOOST_CHECK(c->remove(foo_1));
00123
00124
00125 TEST_BAD_PARSE(r, "root().foos(1)",
00126 "Object with numeric subscript was not found.", "1");
00127
00128
00129 TEST_BAD_PARSE(r, "root().a_foo", "Singleton composite was empty.", "a_foo");
00130
00131
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
00143 TEST_OBJ_NAME(r, "root().a_foo", "foo_1");
00144
00145 delete r;
00146 }
00147 {
00148
00149 root *r = new root("root", "root");
00150
00151
00152 output_test_stream output;
00153 jscript_object_navigator nav(r, &output, false);
00154
00155
00156 r->addfoosandbars();
00157
00158
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
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
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
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
00194
00195 {
00196
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
00204 BOOST_REQUIRE_MESSAGE(parent->comparable(),
00205 "parent doesn't implement comparable interface");
00206 BOOST_CHECK(parent->comparable()->equal(composite));
00207
00208
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
00237 root *r = new root("root", "root");
00238
00239
00240 r->addfoosandbars();
00241
00242
00243 output_test_stream output;
00244 jscript_object_navigator nav(r, &output, false, false);
00245
00246
00247 TEST_OBJ_NAME(r, "root()", "root");
00248
00249
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
00258 TEST_BAD_PARSE(r, "root().foos",
00259 "Object was not a singleton composite. Did you mean to use ()?.", "foos");
00260
00261
00262 TEST_OBJ_NAME(r, "root().foos()", "foos");
00263 TEST_OBJ_NAME(r, "root().a_foo()", "a_foo");
00264
00265
00266
00267
00268 TEST_OBJ_NAME(r, "root().a_foo", "foo_3");
00269
00270
00271 TEST_OBJ_NAME(r, "root().foos('foo_2').parent().bars('bar_1')", "bar_1");
00272
00273
00274
00275
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
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
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
00319 root *r = new root("root", "root");
00320
00321
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 }