#include <dirent.h>
#include <cstring>
#include <vector>
+#include <exception>
#include "support/PluginProxy.h"
#include "support/PluginManager.h"
} // PluginManager
-PluginManager::~PluginManager()
+PluginManager::~PluginManager() noexcept(false)
{
- unloadPlugin();
+ // if exception is already being thrown then we can't throw yet
+ // another exception from destructor because std::terminate will
+ // be called and terminates program so that we don't unload plugin
+ // because this function can throw exception
+ if ( !std::uncaught_exception() )
+ {
+ unloadPlugin();
+ }
} // ~PluginManager
+#include <dlfcn.h>
+
#include "support/CommandLine.h"
#include "support/PluginManager.h"
std::string plugin(STRING(CMAKE_SAMPLE_PLUGIN_ABS_PATH) "\n");
EXPECT_TRUE(os.str() == plugin );
}
+
+// Unload shared library
+static void unloadShared(std::string plugin_path)
+{
+ void *handle = dlopen(plugin_path.c_str(), RTLD_LAZY);
+ assert(handle);
+
+ // try to close library until it is closed
+ for ( int i = 0; !dlclose(handle) && i < 10; i++ ) ;
+
+} // unloadShared
+
+// Test PluginManager that destructor throws exception correctly
+TEST(SUPPORT_NNC, verifyPluginManager4UnloadPlugin)
+{
+ std::string plugin_path{STRING(CMAKE_SAMPLE_PLUGIN_ABS_PATH)};
+ bool is_thrown = false;
+
+ // test that destructor throws exception
+ try
+ {
+ // load the library
+ PluginManager pluginManager(plugin_path);
+
+ // unload the library directly
+ unloadShared(plugin_path);
+ }
+ catch ( const PluginException &e )
+ {
+ // the exception must be thrown from destructor because the library is already unloaded
+ is_thrown = true;
+ }
+
+ ASSERT_EQ(is_thrown, true);
+
+ // test that destructor doesn't throw exception while stack is unwinding
+ try
+ {
+ // load the library
+ PluginManager pluginManager(plugin_path);
+
+ // unload the library directly
+ unloadShared(plugin_path);
+
+ throw PluginException("test exception");
+ }
+ catch (const PluginException &e)
+ {
+ ASSERT_EQ(e.what(), "test exception");
+ }
+}