libmoost
/home/mhx/git/github/libmoost/test/pdl/test_pdl.cpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00028 #include <vector>
00029 #include <deque>
00030 #include <string>
00031 
00032 #include <boost/test/unit_test.hpp>
00033 
00034 #include "../../include/moost/pdl/dynamic_library.h"
00035 #include "../../include/moost/utils/foreach.hpp"
00036 #include "../../include/moost/testing/error_matcher.hpp"
00037 
00038 #include "test_interface.h"
00039 
00040 BOOST_AUTO_TEST_SUITE(moost_pdl)
00041 
00042 namespace
00043 {
00044 
00045 typedef moost::testing::error_matcher matches;
00046 
00047 std::deque<std::string> events;
00048 
00049 std::string next_event()
00050 {
00051    std::string event;
00052 
00053    if (!events.empty())
00054    {
00055       event = events.front();
00056       events.pop_front();
00057    }
00058 
00059    return event;
00060 }
00061 
00062 class other_test_interface : public moost::pdl::dynamic_class
00063 {
00064 public:
00065    virtual int bla() = 0;
00066 };
00067 
00068 typedef std::pair<std::string, int> class_t;
00069 
00070 void test_loader(const std::string& dir, const std::string& libname, const std::vector<class_t>& classvec)
00071 {
00072    std::string library = dir + '/' + libname;
00073 
00074    BOOST_REQUIRE(classvec.size() > 0);
00075    BOOST_REQUIRE_EQUAL(events.size(), 0);
00076 
00077    {
00078       moost::pdl::dynamic_library lib(library);
00079       BOOST_CHECK(lib.is_open());
00080    }
00081 
00082    BOOST_CHECK_EQUAL(events.size(), 2);
00083    BOOST_CHECK_EQUAL(next_event(), "load " + libname);
00084    BOOST_CHECK_EQUAL(next_event(), "unload " + libname);
00085 
00086    {
00087       moost::pdl::dynamic_library lib(library);
00088 
00089       BOOST_CHECK_EQUAL(events.size(), 1);
00090       BOOST_CHECK_EQUAL(next_event(), "load " + libname);
00091 
00092       foreach (const class_t& cls, classvec)
00093       {
00094          {
00095             boost::shared_ptr<my_test_interface> inst(lib.create<my_test_interface>(cls.first));
00096             BOOST_REQUIRE(inst != 0);
00097             BOOST_CHECK_EQUAL(events.size(), 1);
00098             BOOST_CHECK_EQUAL(next_event(), "ctor " + libname + ":" + cls.first + " 1");
00099 
00100             BOOST_CHECK_EQUAL(inst->do_it(), cls.second);
00101 
00102             boost::shared_ptr<other_test_interface> inst2;
00103             BOOST_CHECK_THROW(inst2 = lib.create<other_test_interface>(cls.first), moost::pdl::exception);
00104             BOOST_CHECK(inst2 == 0);
00105             BOOST_CHECK_EQUAL(events.size(), 2);
00106             BOOST_CHECK_EQUAL(next_event(), "ctor " + libname + ":" + cls.first + " 2");
00107             BOOST_CHECK_EQUAL(next_event(), "dtor " + libname + ":" + cls.first + " 2");
00108          }
00109 
00110          BOOST_CHECK_EQUAL(events.size(), 1);
00111          BOOST_CHECK_EQUAL(next_event(), "dtor " + libname + ":" + cls.first + " 1");
00112       }
00113    }
00114 
00115    BOOST_CHECK_EQUAL(events.size(), 1);
00116    BOOST_CHECK_EQUAL(next_event(), "unload " + libname);
00117 
00118    moost::pdl::dynamic_library lib;
00119    BOOST_CHECK(!lib.is_open());
00120 
00121    BOOST_CHECK_EQUAL(events.size(), 0);
00122 
00123    lib.open(library);
00124 
00125    BOOST_CHECK_EQUAL(events.size(), 1);
00126    BOOST_CHECK_EQUAL(next_event(), "load " + libname);
00127 
00128    lib.open(library);
00129 
00130    BOOST_CHECK_EQUAL(events.size(), 0);
00131    BOOST_CHECK(lib.is_open());
00132 
00133    foreach (const class_t& cls, classvec)
00134    {
00135       {
00136          boost::shared_ptr<my_test_interface> inst(lib.create<my_test_interface>(cls.first));
00137          BOOST_REQUIRE(inst != 0);
00138          BOOST_CHECK_EQUAL(events.size(), 1);
00139          BOOST_CHECK_EQUAL(next_event(), "ctor " + libname + ":" + cls.first + " 1");
00140 
00141          BOOST_CHECK_EQUAL(inst->do_it(), cls.second);
00142 
00143          boost::shared_ptr<other_test_interface> inst2;
00144          BOOST_CHECK_THROW(inst2 = lib.create<other_test_interface>(cls.first), moost::pdl::exception);
00145          BOOST_CHECK(inst2 == 0);
00146          BOOST_CHECK_EQUAL(events.size(), 2);
00147          BOOST_CHECK_EQUAL(next_event(), "ctor " + libname + ":" + cls.first + " 2");
00148          BOOST_CHECK_EQUAL(next_event(), "dtor " + libname + ":" + cls.first + " 2");
00149       }
00150 
00151       BOOST_CHECK_EQUAL(events.size(), 1);
00152       BOOST_CHECK_EQUAL(next_event(), "dtor " + libname + ":" + cls.first + " 1");
00153    }
00154 
00155    lib.close();
00156 
00157    BOOST_CHECK_EQUAL(events.size(), 1);
00158    BOOST_CHECK_EQUAL(next_event(), "unload " + libname);
00159    BOOST_CHECK(!lib.is_open());
00160 
00161    foreach (const class_t& cls, classvec)
00162    {
00163       {
00164          moost::pdl::dynamic_library(library).create<my_test_interface>(cls.first);
00165          BOOST_CHECK_EQUAL(events.size(), 4);
00166          BOOST_CHECK_EQUAL(next_event(), "load " + libname);
00167          BOOST_CHECK_EQUAL(next_event(), "ctor " + libname + ":" + cls.first + " 1");
00168          BOOST_CHECK_EQUAL(next_event(), "dtor " + libname + ":" + cls.first + " 1");
00169          BOOST_CHECK_EQUAL(next_event(), "unload " + libname);
00170 
00171          boost::shared_ptr<my_test_interface> inst = moost::pdl::dynamic_library(library).create<my_test_interface>(cls.first);
00172          BOOST_REQUIRE(inst != 0);
00173          BOOST_CHECK_EQUAL(events.size(), 2);
00174          BOOST_CHECK_EQUAL(next_event(), "load " + libname);
00175          BOOST_CHECK_EQUAL(next_event(), "ctor " + libname + ":" + cls.first + " 1");
00176 
00177          BOOST_CHECK_EQUAL(inst->do_it(), cls.second);
00178 
00179          boost::shared_ptr<other_test_interface> inst2;
00180          BOOST_CHECK_THROW(inst2 = moost::pdl::dynamic_library(library).create<other_test_interface>(cls.first), moost::pdl::exception);
00181          BOOST_CHECK(inst2 == 0);
00182          BOOST_CHECK_EQUAL(events.size(), 2);
00183          BOOST_CHECK_EQUAL(next_event(), "ctor " + libname + ":" + cls.first + " 2");
00184          BOOST_CHECK_EQUAL(next_event(), "dtor " + libname + ":" + cls.first + " 2");
00185       }
00186 
00187       BOOST_CHECK_EQUAL(events.size(), 2);
00188       BOOST_CHECK_EQUAL(next_event(), "dtor " + libname + ":" + cls.first + " 1");
00189       BOOST_CHECK_EQUAL(next_event(), "unload " + libname);
00190    }
00191 }
00192 
00193 }
00194 
00195 extern "C" void pdl_test_event(const std::string& event)
00196 {
00197    events.push_back(event);
00198 }
00199 
00200 BOOST_AUTO_TEST_CASE(load_library)
00201 {
00202    // Check loading, unloading, creating & destroying instances
00203 
00204    std::vector<class_t> classvec(2);
00205 
00206    classvec[0].first = "my_test_class1";
00207    classvec[1].first = "my_test_class2";
00208 
00209    classvec[0].second = 1;
00210    classvec[1].second = 2;
00211 
00212    test_loader("../lib", "test_module1", classvec);
00213 
00214    classvec[0].second = 3;
00215    classvec[1].second = 4;
00216 
00217    test_loader("../lib", "test_module2", classvec);
00218 }
00219 
00220 BOOST_AUTO_TEST_CASE(load_library_multi)
00221 {
00222    // Check that multiple library instances only load the shared object once
00223 
00224    {
00225       const std::string library("../lib/test_module1");
00226 
00227       moost::pdl::dynamic_library lib1(library);
00228       BOOST_CHECK_EQUAL(events.size(), 1);
00229       BOOST_CHECK_EQUAL(next_event(), "load test_module1");
00230 
00231       {
00232          moost::pdl::dynamic_library lib2(library);
00233          BOOST_CHECK_EQUAL(events.size(), 0);
00234       }
00235 
00236       BOOST_CHECK_EQUAL(events.size(), 0);
00237    }
00238 
00239    BOOST_CHECK_EQUAL(events.size(), 1);
00240    BOOST_CHECK_EQUAL(next_event(), "unload test_module1");
00241 }
00242 
00243 BOOST_AUTO_TEST_CASE(multi_instances)
00244 {
00245    // Check that every instance we create is distinct
00246 
00247    {
00248       boost::shared_ptr<my_test_interface> inst2;
00249 
00250       {
00251          moost::pdl::dynamic_library lib("../lib/test_module1");
00252          BOOST_CHECK_EQUAL(events.size(), 1);
00253          BOOST_CHECK_EQUAL(next_event(), "load test_module1");
00254 
00255          {
00256             boost::shared_ptr<my_test_interface> inst1;
00257 
00258             inst1 = lib.create<my_test_interface>("my_test_class1");
00259             BOOST_CHECK_EQUAL(events.size(), 1);
00260             BOOST_CHECK_EQUAL(next_event(), "ctor test_module1:my_test_class1 1");
00261 
00262             inst2 = lib.create<my_test_interface>("my_test_class1");
00263             BOOST_CHECK_EQUAL(events.size(), 1);
00264             BOOST_CHECK_EQUAL(next_event(), "ctor test_module1:my_test_class1 2");
00265 
00266             BOOST_CHECK_EQUAL(inst1->do_it(), 1);
00267             BOOST_CHECK_EQUAL(inst1->do_it(), 11);
00268             BOOST_CHECK_EQUAL(inst2->do_it(), 1);
00269             BOOST_CHECK_EQUAL(inst2->do_it(), 11);
00270             BOOST_CHECK_EQUAL(inst1->do_it(), 21);
00271             BOOST_CHECK_EQUAL(inst2->do_it(), 21);
00272          }
00273 
00274          BOOST_CHECK_EQUAL(events.size(), 1);
00275          BOOST_CHECK_EQUAL(next_event(), "dtor test_module1:my_test_class1 1");
00276 
00277          BOOST_CHECK_EQUAL(inst2->do_it(), 31);
00278       }
00279 
00280       BOOST_CHECK_EQUAL(events.size(), 0);
00281    }
00282 
00283    BOOST_CHECK_EQUAL(events.size(), 2);
00284    BOOST_CHECK_EQUAL(next_event(), "dtor test_module1:my_test_class1 2");
00285    BOOST_CHECK_EQUAL(next_event(), "unload test_module1");
00286 }
00287 
00288 BOOST_AUTO_TEST_CASE(pdl_error)
00289 {
00290    moost::pdl::dynamic_library dl;
00291 
00292    BOOST_CHECK_EXCEPTION(dl.create<my_test_interface>("foo"), moost::pdl::exception,
00293                          matches("no library loaded"));
00294 
00295    // XXX: This check won't necessarily work on Windows, as the error message is probably different
00296    BOOST_CHECK_EXCEPTION(dl.open("Does_Not_Exist"), moost::pdl::library_not_found_error, matches(".*Does_Not_Exist.*"));
00297 
00298    BOOST_CHECK(!dl.is_open());
00299 
00300    dl.open("../lib/test_module1");
00301 
00302    BOOST_CHECK(dl.is_open());
00303 
00304    BOOST_CHECK_EXCEPTION(dl.create<my_test_interface>("foo"), moost::pdl::class_not_found_error,
00305                          matches("class foo not found in ../lib/.*test_module1.*"));
00306 
00307    BOOST_CHECK_EXCEPTION(dl.create<my_test_interface>("my_fail_class"), moost::pdl::exception,
00308                          matches("failed to create instance of class my_fail_class"));
00309 
00310    BOOST_CHECK_EXCEPTION(dl.create<other_test_interface>("my_test_class1"), moost::pdl::exception,
00311                          matches("invalid type for class my_test_class1"));
00312 
00313    dl.close();
00314 
00315    BOOST_CHECK(!dl.is_open());
00316 
00317    BOOST_CHECK_EQUAL(events.size(), 4);
00318    BOOST_CHECK_EQUAL(next_event(), "load test_module1");
00319    BOOST_CHECK_EQUAL(next_event(), "ctor test_module1:my_test_class1 1");
00320    BOOST_CHECK_EQUAL(next_event(), "dtor test_module1:my_test_class1 1");
00321    BOOST_CHECK_EQUAL(next_event(), "unload test_module1");
00322 }
00323 
00324 BOOST_AUTO_TEST_SUITE_END()