[ros-class-loader] 01/03: New upstream version 0.3.5

Jochen Sprickerhof jspricke at moszumanska.debian.org
Sat Sep 24 15:55:58 UTC 2016


This is an automated email from the git hooks/post-receive script.

jspricke pushed a commit to annotated tag debian/0.3.5-1
in repository ros-class-loader.

commit 6e352ea6a5742558c1efb8eda9fe78fd1fd6333a
Author: Jochen Sprickerhof <git at jochen.sprickerhof.de>
Date:   Sat Sep 24 15:14:01 2016 +0200

    New upstream version 0.3.5
---
 CHANGELOG.rst                                     |  11 +
 include/class_loader/class_loader.h               | 112 +++++++---
 include/class_loader/multi_library_class_loader.h |  97 +++++---
 package.xml                                       |   2 +-
 test/CMakeLists.txt                               |  11 +
 test/unique_ptr_test.cpp                          | 255 ++++++++++++++++++++++
 6 files changed, 431 insertions(+), 57 deletions(-)

diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index a15289c..06a873a 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -2,6 +2,17 @@
 Changelog for package class_loader
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+0.3.5 (2016-09-20)
+------------------
+* Add ClassLoader::createUniqueInstance (`#38 <https://github.com/ros/class_loader/issues/38>`_)
+  * Wrap comments on createInstance and friend.
+  * Delegate createInstance and createUnmanagedInstance to private impl.
+  * Add ClassLoader::createUniqueInstance.
+  * MultiLibraryClassLoader: Factor out getClassLoaderForClass.
+  * MultiLibraryClassLoader: Add unique_ptr API.
+  * Add tests for unique_ptr API.
+* Contributors: Maarten de Vries
+
 0.3.4 (2016-06-22)
 ------------------
 * cleanup: don't use active_class_loaders\_[library_path] for existence test (`#35 <https://github.com/ros/class_loader/issues/35>`_)
diff --git a/include/class_loader/class_loader.h b/include/class_loader/class_loader.h
index 003ed3c..110e856 100644
--- a/include/class_loader/class_loader.h
+++ b/include/class_loader/class_loader.h
@@ -39,6 +39,11 @@
 #include "class_loader/class_loader_register_macro.h"
 #include "class_loader/class_loader_core.h"
 
+#if __cplusplus >= 201103L
+#  include<memory>
+#  include<functional>
+#endif
+
 namespace class_loader
 {
 
@@ -47,8 +52,6 @@ namespace class_loader
 */
 std::string systemLibrarySuffix();
 
-
-
 /**
  * @class ClassLoader
  * @brief This class allows loading and unloading of dynamically linked libraries which contain class definitions from which objects can be created/destroyed during runtime (i.e. class_loader). Libraries loaded by a ClassLoader are only accessible within scope of that ClassLoader object.
@@ -56,6 +59,14 @@ std::string systemLibrarySuffix();
 class ClassLoader
 {
   public:
+#if __cplusplus >= 201103L
+    template<typename Base>
+    using DeleterType = std::function<void (Base *)>;
+
+    template<typename Base>
+    using UniquePtr = std::unique_ptr<Base, DeleterType<Base>>;
+#endif
+
     /**
      * @brief  Constructor for ClassLoader
      * @param library_path - The path of the runtime library to load
@@ -84,45 +95,58 @@ class ClassLoader
     std::string getLibraryPath(){return(library_path_);}
 
     /**
-     * @brief  Generates an instance of loadable classes (i.e. class_loader). It is not necessary for the user to call loadLibrary() as it will be invoked automatically if the library is not yet loaded (which typically happens when in "On Demand Load/Unload" mode).
+     * @brief  Generates an instance of loadable classes (i.e. class_loader).
+     *
+     * It is not necessary for the user to call loadLibrary() as it will be invoked automatically
+     * if the library is not yet loaded (which typically happens when in "On Demand Load/Unload" mode).
+     *
      * @param  derived_class_name The name of the class we want to create (@see getAvailableClasses())
      * @return A boost::shared_ptr<Base> to newly created plugin object
      */
-    template <class Base>    
+    template <class Base>
     boost::shared_ptr<Base> createInstance(const std::string& derived_class_name)
     {
-      if(ClassLoader::hasUnmanagedInstanceBeenCreated() && isOnDemandLoadUnloadEnabled())
-        logInform("class_loader::ClassLoader: An attempt is being made to create a managed plugin instance (i.e. boost::shared_ptr), however an unmanaged instance was created within this process address space. This means libraries for the managed instances will not be shutdown automatically on final plugin destruction if on demand (lazy) loading/unloading mode is used.");
-
-      if(!isLibraryLoaded())
-        loadLibrary();
-
-      Base* obj = class_loader::class_loader_private::createInstance<Base>(derived_class_name, this);
-      assert(obj != NULL); //Unreachable assertion if createInstance() throws on failure
-
-      boost::recursive_mutex::scoped_lock lock(plugin_ref_count_mutex_);
-      plugin_ref_count_ = plugin_ref_count_ + 1;
+      return boost::shared_ptr<Base>(createRawInstance<Base>(derived_class_name, true),
+                                     boost::bind(&ClassLoader::onPluginDeletion<Base>, this, _1));
+    }
 
-      boost::shared_ptr<Base> smart_obj(obj, boost::bind(&class_loader::ClassLoader::onPluginDeletion<Base>, this, _1));
-      return(smart_obj);
+#if __cplusplus >= 201103L
+    /**
+     * @brief  Generates an instance of loadable classes (i.e. class_loader).
+     *
+     * It is not necessary for the user to call loadLibrary() as it will be invoked automatically
+     * if the library is not yet loaded (which typically happens when in "On Demand Load/Unload" mode).
+     *
+     * If you release the wrapped pointer you must manually call the original
+     * deleter when you want to destroy the released pointer.
+     *
+     * @param  derived_class_name The name of the class we want to create (@see getAvailableClasses())
+     * @return A std::unique_ptr<Base> to newly created plugin object
+     */
+    template<class Base>
+    UniquePtr<Base> createUniqueInstance(const std::string& derived_class_name)
+    {
+      Base* raw = createRawInstance<Base>(derived_class_name, true);
+      return std::unique_ptr<Base, DeleterType<Base>>(raw, boost::bind(&ClassLoader::onPluginDeletion<Base>, this, _1));
     }
+#endif
 
     /**
-     * @brief  Generates an instance of loadable classes (i.e. class_loader). It is not necessary for the user to call loadLibrary() as it will be invoked automatically if the library is not yet loaded (which typically happens when in "On Demand Load/Unload" mode).
+     * @brief  Generates an instance of loadable classes (i.e. class_loader).
+     *
+     * It is not necessary for the user to call loadLibrary() as it will be invoked automatically
+     * if the library is not yet loaded (which typically happens when in "On Demand Load/Unload" mode).
+     *
+     * Creating an unmanaged instance disables dynamically unloading libraries when
+     * managed pointers go out of scope for all class loaders in this process.
+     *
      * @param derived_class_name The name of the class we want to create (@see getAvailableClasses())
      * @return An unmanaged (i.e. not a shared_ptr) Base* to newly created plugin object.
      */
     template <class Base>
     Base* createUnmanagedInstance(const std::string& derived_class_name)
     {
-      has_unmananged_instance_been_created_ = true;
-      if(!isLibraryLoaded())
-        loadLibrary();
-
-      Base* obj = class_loader::class_loader_private::createInstance<Base>(derived_class_name, this);
-      assert(obj != NULL); //Unreachable assertion if createInstance() throws on failure
-
-      return(obj);
+      return createRawInstance<Base>(derived_class_name, false);
     }
 
     /**
@@ -173,7 +197,7 @@ class ClassLoader
      * @brief Callback method when a plugin created by this class loader is destroyed
      * @param obj - A pointer to the deleted object
      */
-    template <class Base>    
+    template <class Base>
     void onPluginDeletion(Base* obj)
     {
       logDebug("class_loader::ClassLoader: Calling onPluginDeletion() for obj ptr = %p.\n", obj);
@@ -194,6 +218,40 @@ class ClassLoader
     }
 
     /**
+     * @brief  Generates an instance of loadable classes (i.e. class_loader).
+     *
+     * It is not necessary for the user to call loadLibrary() as it will be invoked automatically
+     * if the library is not yet loaded (which typically happens when in "On Demand Load/Unload" mode).
+     *
+     * @param  derived_class_name The name of the class we want to create (@see getAvailableClasses())
+     * @param  managed If true, the returned pointer is assumed to be wrapped in a smart pointer by the caller.
+     * @return A Base* to newly created plugin object
+     */
+    template <class Base>
+    Base* createRawInstance(const std::string& derived_class_name, bool managed)
+    {
+      if (!managed)
+        has_unmananged_instance_been_created_ = true;
+
+      if (managed && ClassLoader::hasUnmanagedInstanceBeenCreated() && isOnDemandLoadUnloadEnabled())
+        logInform("class_loader::ClassLoader: An attempt is being made to create a managed plugin instance (i.e. boost::shared_ptr), however an unmanaged instance was created within this process address space. This means libraries for the managed instances will not be shutdown automatically on final plugin destruction if on demand (lazy) loading/unloading mode is used.");
+
+      if (!isLibraryLoaded())
+        loadLibrary();
+
+      Base* obj = class_loader::class_loader_private::createInstance<Base>(derived_class_name, this);
+      assert(obj != NULL); //Unreachable assertion if createInstance() throws on failure
+
+      if (managed)
+      {
+        boost::recursive_mutex::scoped_lock lock(plugin_ref_count_mutex_);
+        plugin_ref_count_ = plugin_ref_count_ + 1;
+      }
+
+      return obj;
+    }
+
+    /**
     * @brief Getter for if an unmanaged (i.e. unsafe) instance has been created flag
     */
     static bool hasUnmanagedInstanceBeenCreated();
diff --git a/include/class_loader/multi_library_class_loader.h b/include/class_loader/multi_library_class_loader.h
index 17aa27e..f4a167d 100644
--- a/include/class_loader/multi_library_class_loader.h
+++ b/include/class_loader/multi_library_class_loader.h
@@ -69,17 +69,10 @@ class MultiLibraryClassLoader
     boost::shared_ptr<Base> createInstance(const std::string& class_name)
     {
       logDebug("class_loader::MultiLibraryClassLoader: Attempting to create instance of class type %s.", class_name.c_str());
-      ClassLoaderVector active_loaders = getAllAvailableClassLoaders();
-      for(unsigned int c = 0; c < active_loaders.size(); c++)
-      {
-        ClassLoader* current = active_loaders.at(c);
-        if (!current->isLibraryLoaded())
-          current->loadLibrary();
-        if(current->isClassAvailable<Base>(class_name))
-          return(current->createInstance<Base>(class_name));
-      }
-
-      throw(class_loader::CreateClassException("MultiLibraryClassLoader: Could not create object of class type " + class_name + " as no factory exists for it. Make sure that the library exists and was explicitly loaded through MultiLibraryClassLoader::loadLibrary()"));
+      ClassLoader* loader = getClassLoaderForClass<Base>(class_name);
+      if (loader == NULL)
+        throw class_loader::CreateClassException("MultiLibraryClassLoader: Could not create object of class type " + class_name + " as no factory exists for it. Make sure that the library exists and was explicitly loaded through MultiLibraryClassLoader::loadLibrary()");
+      return loader->createInstance<Base>(class_name);
     }
 
     /**
@@ -92,13 +85,48 @@ class MultiLibraryClassLoader
      */
     template <class Base>
     boost::shared_ptr<Base> createInstance(const std::string& class_name, const std::string& library_path)
-    {   
+    {
       ClassLoader* loader = getClassLoaderForLibrary(library_path);
-      if(loader)
-        return(loader->createInstance<Base>(class_name));
-      else
+      if (loader == NULL)
+        throw class_loader::NoClassLoaderExistsException("Could not create instance as there is no ClassLoader in MultiLibraryClassLoader bound to library " + library_path + " Ensure you called MultiLibraryClassLoader::loadLibrary()");
+      return loader->createInstance<Base>(class_name);
+    }
+
+#if __cplusplus >= 201103L
+    /**
+     * @brief Creates an instance of an object of given class name with ancestor class Base
+     * This version does not look in a specific library for the factory, but rather the first open library that defines the classs
+     * @param Base - polymorphic type indicating base class
+     * @param class_name - the name of the concrete plugin class we want to instantiate
+     * @return A unique pointer to newly created plugin
+     */
+    template <class Base>
+    ClassLoader::UniquePtr<Base> createUniqueInstance(const std::string& class_name)
+    {
+      logDebug("class_loader::MultiLibraryClassLoader: Attempting to create instance of class type %s.", class_name.c_str());
+      ClassLoader* loader = getClassLoaderForClass<Base>(class_name);
+      if (loader == nullptr)
+        throw class_loader::CreateClassException("MultiLibraryClassLoader: Could not create object of class type " + class_name + " as no factory exists for it. Make sure that the library exists and was explicitly loaded through MultiLibraryClassLoader::loadLibrary()");
+      return loader->createUniqueInstance<Base>(class_name);
+    }
+
+    /**
+     * @brief Creates an instance of an object of given class name with ancestor class Base
+     * This version takes a specific library to make explicit the factory being used
+     * @param Base - polymorphic type indicating base class
+     * @param class_name - the name of the concrete plugin class we want to instantiate
+     * @param library_path - the library from which we want to create the plugin
+     * @return A unique pointer to newly created plugin
+     */
+    template <class Base>
+    ClassLoader::UniquePtr<Base> createUniqueInstance(const std::string& class_name, const std::string& library_path)
+    {
+      ClassLoader* loader = getClassLoaderForLibrary(library_path);
+      if (loader == nullptr)
         throw class_loader::NoClassLoaderExistsException("Could not create instance as there is no ClassLoader in MultiLibraryClassLoader bound to library " + library_path + " Ensure you called MultiLibraryClassLoader::loadLibrary()");
+      return loader->createUniqueInstance<Base>(class_name);
     }
+#endif
 
     /**
      * @brief Creates an instance of an object of given class name with ancestor class Base
@@ -111,17 +139,10 @@ class MultiLibraryClassLoader
     template <class Base>
     Base* createUnmanagedInstance(const std::string& class_name)
     {
-      ClassLoaderVector active_loaders = getAllAvailableClassLoaders();
-      for(unsigned int c = 0; c < active_loaders.size(); c++)
-      {
-        ClassLoader* current = active_loaders.at(c);
-        if (!current->isLibraryLoaded())
-          current->loadLibrary();
-        if(current->isClassAvailable<Base>(class_name))
-          return(current->createUnmanagedInstance<Base>(class_name));
-      }
-
-      throw(class_loader::CreateClassException("MultiLibraryClassLoader: Could not create class of type " + class_name));
+      ClassLoader* loader = getClassLoaderForClass<Base>(class_name);
+      if (loader == NULL)
+        throw class_loader::CreateClassException("MultiLibraryClassLoader: Could not create class of type " + class_name);
+      return loader->createUnmanagedInstance<Base>(class_name);
     }
 
     /**
@@ -136,10 +157,9 @@ class MultiLibraryClassLoader
     Base* createUnmanagedInstance(const std::string& class_name, const std::string& library_path)
     {
       ClassLoader* loader = getClassLoaderForLibrary(library_path);
-      if(loader)
-        return(loader->createUnmanagedInstance<Base>(class_name));
-      else
+      if (loader == NULL)
         throw class_loader::NoClassLoaderExistsException("Could not create instance as there is no ClassLoader in MultiLibraryClassLoader bound to library " + library_path + " Ensure you called MultiLibraryClassLoader::loadLibrary()");
+      return loader->createUnmanagedInstance<Base>(class_name);
     }
 
     /**
@@ -233,6 +253,25 @@ class MultiLibraryClassLoader
     ClassLoader* getClassLoaderForLibrary(const std::string& library_path);
 
     /**
+     * @brief Gets a handle to the class loader corresponding to a specific class
+     * @param class_name - name of class for which we want to create instance
+     * @return A pointer to the ClassLoader*, == NULL if not found
+     */
+    template<typename Base>
+    ClassLoader* getClassLoaderForClass(const std::string& class_name)
+    {
+      ClassLoaderVector loaders = getAllAvailableClassLoaders();
+      for (ClassLoaderVector::iterator i = loaders.begin(); i != loaders.end(); ++i)
+      {
+        if (!(*i)->isLibraryLoaded())
+          (*i)->loadLibrary();
+        if ((*i)->isClassAvailable<Base>(class_name))
+          return *i;
+      }
+      return NULL;
+    }
+
+    /**
      * @brief Gets all class loaders loaded within scope
      */
     ClassLoaderVector getAllAvailableClassLoaders();
diff --git a/package.xml b/package.xml
index 3bbd501..70d0794 100644
--- a/package.xml
+++ b/package.xml
@@ -1,6 +1,6 @@
 <package>
   <name>class_loader</name>
-  <version>0.3.4</version>
+  <version>0.3.5</version>
   <description>
     The class_loader package is a ROS-independent package for loading plugins during runtime and the foundation of the higher level ROS "pluginlib" library. class_loader utilizes the host operating system's runtime loader to open runtime libraries (e.g. .so/.dll files), introspect the library for exported plugin classes, and allows users to instantiate objects of said exported classes without the explicit declaration (i.e. header file) for those classes.
   </description>
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index d24a384..a8845f9 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -17,3 +17,14 @@ if(TARGET ${PROJECT_NAME}_utest)
   target_link_libraries(${PROJECT_NAME}_utest ${Boost_LIBRARIES} ${class_loader_LIBRARIES})
   add_dependencies(${PROJECT_NAME}_utest ${PROJECT_NAME}_TestPlugins1 ${PROJECT_NAME}_TestPlugins2)
 endif()
+
+include(CheckCXXCompilerFlag)
+CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
+if(COMPILER_SUPPORTS_CXX11)
+  catkin_add_gtest(${PROJECT_NAME}_unique_ptr_test unique_ptr_test.cpp)
+  if(TARGET ${PROJECT_NAME}_unique_ptr_test)
+    target_link_libraries(${PROJECT_NAME}_unique_ptr_test ${Boost_LIBRARIES} ${class_loader_LIBRARIES})
+	set_target_properties(${PROJECT_NAME}_unique_ptr_test PROPERTIES COMPILE_FLAGS -std=c++11 LINK_FLAGS -std=c++11)
+    add_dependencies(${PROJECT_NAME}_unique_ptr_test ${PROJECT_NAME}_TestPlugins1 ${PROJECT_NAME}_TestPlugins2)
+  endif()
+endif()
diff --git a/test/unique_ptr_test.cpp b/test/unique_ptr_test.cpp
new file mode 100644
index 0000000..a5559df
--- /dev/null
+++ b/test/unique_ptr_test.cpp
@@ -0,0 +1,255 @@
+#include "base.h"
+#include <class_loader/class_loader.h>
+#include <class_loader/multi_library_class_loader.h>
+
+#include <gtest/gtest.h>
+#include <boost/thread.hpp>
+
+#include <functional>
+#include <iostream>
+
+const std::string LIBRARY_1 = "libclass_loader_TestPlugins1.so";
+const std::string LIBRARY_2 = "libclass_loader_TestPlugins2.so";
+
+using class_loader::ClassLoader;
+
+/*****************************************************************************/
+TEST(ClassLoaderUniquePtrTest, basicLoad)
+{
+  try
+  {
+    ClassLoader loader1(LIBRARY_1, false);
+    loader1.createUniqueInstance<Base>("Cat")->saySomething(); //See if lazy load works
+    SUCCEED();
+  }
+  catch(class_loader::ClassLoaderException& e)
+  {
+    FAIL() << "ClassLoaderException: " << e.what() << "\n";
+  }
+}
+
+/*****************************************************************************/
+TEST(ClassLoaderUniquePtrTest, correctLazyLoadUnload)
+{
+  try
+  {
+    ASSERT_FALSE(class_loader::class_loader_private::isLibraryLoadedByAnybody(LIBRARY_1));
+    ClassLoader loader1(LIBRARY_1, true);
+    ASSERT_FALSE(class_loader::class_loader_private::isLibraryLoadedByAnybody(LIBRARY_1));
+    ASSERT_FALSE(loader1.isLibraryLoaded());
+
+    {
+      ClassLoader::UniquePtr<Base> obj = loader1.createUniqueInstance<Base>("Cat");
+      ASSERT_TRUE(class_loader::class_loader_private::isLibraryLoadedByAnybody(LIBRARY_1));
+      ASSERT_TRUE(loader1.isLibraryLoaded());
+    }
+
+    //The library will unload automatically when the only plugin object left is destroyed
+    ASSERT_FALSE(class_loader::class_loader_private::isLibraryLoadedByAnybody(LIBRARY_1));
+    return;
+  }
+  catch(class_loader::ClassLoaderException& e)
+  {
+    FAIL() << "ClassLoaderException: " << e.what() << "\n";
+  }
+  catch(...)
+  {
+    FAIL() << "Unhandled exception";
+  }
+}
+
+/*****************************************************************************/
+
+TEST(ClassLoaderUniquePtrTest, nonExistentPlugin)
+{
+  ClassLoader loader1(LIBRARY_1, false);
+
+  try
+  {
+    ClassLoader::UniquePtr<Base> obj = loader1.createUniqueInstance<Base>("Bear");
+    if(obj == NULL)
+      FAIL() << "Null object being returned instead of exception thrown.";
+
+    obj->saySomething();
+  }
+  catch(const class_loader::CreateClassException& e)
+  {
+    SUCCEED();
+    return;
+  }
+  catch(...)
+  {
+    FAIL() << "Unknown exception caught.\n";
+  }
+
+  FAIL() << "Did not throw exception as expected.\n";
+}
+
+/*****************************************************************************/
+
+void wait(int seconds)
+{
+  boost::this_thread::sleep(boost::posix_time::seconds(seconds));
+}
+
+void run(ClassLoader* loader)
+{
+  std::vector<std::string> classes = loader->getAvailableClasses<Base>();
+  for(unsigned int c = 0; c < classes.size(); c++)
+  {
+    loader->createUniqueInstance<Base>(classes.at(c))->saySomething();
+  }
+}
+
+TEST(ClassLoaderUniquePtrTest, threadSafety)
+{
+  ClassLoader loader1(LIBRARY_1);
+  ASSERT_TRUE(loader1.isLibraryLoaded());
+
+  //Note: Hard to test thread safety to make sure memory isn't corrupted.
+  //The hope is this test is hard enough that once in a while it'll segfault
+  //or something if there's some implementation error.
+  try
+  {
+    std::vector<boost::thread> client_threads;
+
+    for(unsigned int c = 0; c < 1000; c++)
+      client_threads.emplace_back(std::bind(&run, &loader1));
+
+    for(unsigned int c = 0; c < client_threads.size(); c++)
+      client_threads.at(c).join();
+
+    loader1.unloadLibrary();
+    ASSERT_FALSE(loader1.isLibraryLoaded());
+
+  }
+  catch(const class_loader::ClassLoaderException& ex)
+  {
+    FAIL() << "Unexpected ClassLoaderException.";
+  }
+  catch(...)
+  {
+    FAIL() << "Unknown exception.";
+  }
+}
+
+
+/*****************************************************************************/
+
+TEST(ClassLoaderUniquePtrTest, loadRefCountingLazy)
+{
+  try
+  {
+    ClassLoader loader1(LIBRARY_1, true);
+    ASSERT_FALSE(loader1.isLibraryLoaded());
+
+    {
+      ClassLoader::UniquePtr<Base> obj = loader1.createUniqueInstance<Base>("Dog");
+      ASSERT_TRUE(loader1.isLibraryLoaded());
+    }
+
+    ASSERT_FALSE(loader1.isLibraryLoaded());
+
+    loader1.loadLibrary();
+    ASSERT_TRUE(loader1.isLibraryLoaded());
+
+    loader1.loadLibrary();
+    ASSERT_TRUE(loader1.isLibraryLoaded());
+
+    loader1.unloadLibrary();
+    ASSERT_TRUE(loader1.isLibraryLoaded());
+
+    loader1.unloadLibrary();
+    ASSERT_FALSE(loader1.isLibraryLoaded());
+
+    loader1.unloadLibrary();
+    ASSERT_FALSE(loader1.isLibraryLoaded());
+
+    loader1.loadLibrary();
+    ASSERT_TRUE(loader1.isLibraryLoaded());
+
+    return;
+  }
+  catch(const class_loader::ClassLoaderException& e)
+  {
+    FAIL() << "Unexpected exception.\n";
+  }
+  catch(...)
+  {
+    FAIL() << "Unknown exception caught.\n";
+  }
+
+  FAIL() << "Did not throw exception as expected.\n";
+}
+
+
+/*****************************************************************************/
+
+void testMultiClassLoader(bool lazy)
+{
+  try
+  {
+    class_loader::MultiLibraryClassLoader loader(lazy);
+    loader.loadLibrary(LIBRARY_1);
+    loader.loadLibrary(LIBRARY_2);
+    for (int i=0; i < 2; ++i) {
+      loader.createUniqueInstance<Base>("Cat")->saySomething();
+      loader.createUniqueInstance<Base>("Dog")->saySomething();
+      loader.createUniqueInstance<Base>("Robot")->saySomething();
+    }
+  }
+  catch(class_loader::ClassLoaderException& e)
+  {
+    FAIL() << "ClassLoaderException: " << e.what() << "\n";
+  }
+
+  SUCCEED();
+}
+
+TEST(MultiClassLoaderUniquePtrTest, lazyLoad)
+{
+  testMultiClassLoader(true);
+}
+TEST(MultiClassLoaderUniquePtrTest, lazyLoadSecondTime)
+{
+  testMultiClassLoader(true);
+}
+TEST(MultiClassLoaderUniquePtrTest, nonLazyLoad)
+{
+  testMultiClassLoader(false);
+}
+TEST(MultiClassLoaderUniquePtrTest, noWarningOnLazyLoad)
+{
+  try
+  {
+    ClassLoader::UniquePtr<Base> cat = nullptr, dog = nullptr, rob = nullptr;
+    {
+      class_loader::MultiLibraryClassLoader loader(true);
+      loader.loadLibrary(LIBRARY_1);
+      loader.loadLibrary(LIBRARY_2);
+
+      cat = loader.createUniqueInstance<Base>("Cat");
+      dog = loader.createUniqueInstance<Base>("Dog");
+      rob = loader.createUniqueInstance<Base>("Robot");
+    }
+    cat->saySomething();
+    dog->saySomething();
+    rob->saySomething();
+  }
+  catch(class_loader::ClassLoaderException& e)
+  {
+    FAIL() << "ClassLoaderException: " << e.what() << "\n";
+  }
+
+  SUCCEED();
+}
+
+/*****************************************************************************/
+
+// Run all the tests that were declared with TEST()
+int main(int argc, char **argv){
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
+
+

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/ros/ros-class-loader.git



More information about the debian-science-commits mailing list