diff --git a/src/class_loader.cpp b/src/class_loader.cpp index 76785bc..f90acd0 100644 --- a/src/class_loader.cpp +++ b/src/class_loader.cpp @@ -72,6 +72,16 @@ ClassLoader::~ClassLoader() "%s", "class_loader.ClassLoader: Destroying class loader, " "unloading associated library...\n"); + { + // The deferred on-demand unload in onPluginDeletion() can't happen once this loader is gone. + std::lock_guard lock(plugin_ref_count_mutex_); + if (plugin_ref_count_ > 0 && isOnDemandLoadUnloadEnabled()) { + CONSOLE_BRIDGE_logWarn( + "%s", + "class_loader.ClassLoader: SEVERE WARNING!!! " + "Destroying ClassLoader while objects created by it exist in the heap!"); + } + } unloadLibrary(); // TODO(mikaelarguedas): while(unloadLibrary() > 0){} ?? } @@ -123,7 +133,9 @@ int ClassLoader::unloadLibraryInternal(bool lock_plugin_ref_count) std::lock_guard load_ref_lock(load_ref_count_mutex_); try { - if (plugin_ref_count_ > 0) { + if (plugin_ref_count_ > 0 && isOnDemandLoadUnloadEnabled()) { + // Expected: onPluginDeletion() unloads the library once the last object is destroyed. + } else if (plugin_ref_count_ > 0) { CONSOLE_BRIDGE_logWarn( "%s", "class_loader.ClassLoader: SEVERE WARNING!!! " diff --git a/test/unique_ptr_test.cpp b/test/unique_ptr_test.cpp index 1aa4578..6910b2a 100644 --- a/test/unique_ptr_test.cpp +++ b/test/unique_ptr_test.cpp @@ -37,6 +37,7 @@ #include #include +#include "console_bridge/console.h" #include "gtest/gtest.h" #include "class_loader/class_loader.hpp" @@ -48,6 +49,18 @@ const std::string LIBRARY_1 = class_loader::systemLibraryFormat("class_loader_Te const std::string LIBRARY_2 = class_loader::systemLibraryFormat("class_loader_TestPlugins2"); // NOLINT const std::string LIBRARY_3 = class_loader::systemLibraryFormat("class_loader_TestPlugins3"); // NOLINT +// Collects console_bridge warnings and errors logged while in scope. +struct WarningCapture : console_bridge::OutputHandler +{ + WarningCapture() {console_bridge::useOutputHandler(this);} + ~WarningCapture() override {console_bridge::restorePreviousOutputHandler();} + void log(const std::string & text, console_bridge::LogLevel level, const char *, int) override + { + if (level >= console_bridge::CONSOLE_BRIDGE_LOG_WARN) {warnings += text;} + } + std::string warnings; +}; + using class_loader::ClassLoader; TEST(ClassLoaderUniquePtrTest, basicLoad) { @@ -297,6 +310,7 @@ TEST(MultiClassLoaderUniquePtrTest, nonLazyLoad) { } TEST(MultiClassLoaderUniquePtrTest, noWarningOnLazyLoad) { try { + WarningCapture capture; ClassLoader::UniquePtr cat, dog, rob; { class_loader::MultiLibraryClassLoader loader(true); @@ -310,6 +324,7 @@ TEST(MultiClassLoaderUniquePtrTest, noWarningOnLazyLoad) { cat->saySomething(); dog->saySomething(); rob->saySomething(); + EXPECT_EQ("", capture.warnings); } catch (class_loader::ClassLoaderException & e) { FAIL() << "ClassLoaderException: " << e.what() << "\n"; } diff --git a/test/utest.cpp b/test/utest.cpp index f4e13ee..1a9fd3b 100644 --- a/test/utest.cpp +++ b/test/utest.cpp @@ -44,6 +44,7 @@ #include "class_loader/class_loader.hpp" #include "class_loader/multi_library_class_loader.hpp" +#include "console_bridge/console.h" #include "gtest/gtest.h" #include "./base.hpp" @@ -57,6 +58,18 @@ const std::string LIBRARY_3 = class_loader::systemLibraryFormat("class_loader_Te const std::string GLOBAL_PLUGINS = // NOLINT class_loader::systemLibraryFormat("class_loader_TestGlobalPlugins"); +// Collects console_bridge warnings and errors logged while in scope. +struct WarningCapture : console_bridge::OutputHandler +{ + WarningCapture() {console_bridge::useOutputHandler(this);} + ~WarningCapture() override {console_bridge::restorePreviousOutputHandler();} + void log(const std::string & text, console_bridge::LogLevel level, const char *, int) override + { + if (level >= console_bridge::CONSOLE_BRIDGE_LOG_WARN) {warnings += text;} + } + std::string warnings; +}; + TEST(ClassLoaderTest, basicLoad) { try { class_loader::ClassLoader loader1(LIBRARY_1, false); @@ -419,6 +432,7 @@ TEST(MultiClassLoaderTest, nonLazyLoad) { } TEST(MultiClassLoaderTest, noWarningOnLazyLoad) { try { + WarningCapture capture; std::shared_ptr cat, dog, rob; { class_loader::MultiLibraryClassLoader loader(true); @@ -432,6 +446,7 @@ TEST(MultiClassLoaderTest, noWarningOnLazyLoad) { cat->saySomething(); dog->saySomething(); rob->saySomething(); + EXPECT_EQ("", capture.warnings); } catch (class_loader::ClassLoaderException & e) { FAIL() << "ClassLoaderException: " << e.what() << "\n"; }