unique_ptr_test.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012, Willow Garage, Inc.
3  * Copyright (c) 2016, Delft Robotics B.V.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * * Neither the name of the Willow Garage, Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
33 
34 #include <gtest/gtest.h>
35 
36 #include <chrono>
37 #include <cstddef>
38 #include <functional>
39 #include <iostream>
40 #include <string>
41 #include <thread>
42 #include <vector>
43 
44 #include "./base.hpp"
45 
46 const std::string LIBRARY_1 = class_loader::systemLibraryFormat("class_loader_TestPlugins1"); // NOLINT
47 const std::string LIBRARY_2 = class_loader::systemLibraryFormat("class_loader_TestPlugins2"); // NOLINT
48 
50 
51 TEST(ClassLoaderUniquePtrTest, basicLoad) {
52  try {
53  ClassLoader loader1(LIBRARY_1, false);
54  loader1.createUniqueInstance<Base>("Cat")->saySomething(); // See if lazy load works
55  SUCCEED();
57  FAIL() << "ClassLoaderException: " << e.what() << "\n";
58  }
59 }
60 
61 TEST(ClassLoaderUniquePtrTest, correctLazyLoadUnload) {
62  try {
64  ClassLoader loader1(LIBRARY_1, true);
66  ASSERT_FALSE(loader1.isLibraryLoaded());
67 
68  {
69  ClassLoader::UniquePtr<Base> obj = loader1.createUniqueInstance<Base>("Cat");
71  ASSERT_TRUE(loader1.isLibraryLoaded());
72  }
73 
74  // The library will unload automatically when the only plugin object left is destroyed
76  return;
78  FAIL() << "ClassLoaderException: " << e.what() << "\n";
79  } catch (...) {
80  FAIL() << "Unhandled exception";
81  }
82 }
83 
84 TEST(ClassLoaderUniquePtrTest, nonExistentPlugin) {
85  ClassLoader loader1(LIBRARY_1, false);
86 
87  try {
88  ClassLoader::UniquePtr<Base> obj = loader1.createUniqueInstance<Base>("Bear");
89  if (nullptr == obj) {
90  FAIL() << "Null object being returned instead of exception thrown.";
91  }
92 
93  obj->saySomething();
94  } catch (const class_loader::CreateClassException &) {
95  SUCCEED();
96  return;
97  } catch (...) {
98  FAIL() << "Unknown exception caught.\n";
99  }
100 
101  FAIL() << "Did not throw exception as expected.\n";
102 }
103 
104 void wait(int seconds)
105 {
106  std::this_thread::sleep_for(std::chrono::seconds(seconds));
107 }
108 
109 void run(ClassLoader * loader)
110 {
111  std::vector<std::string> classes = loader->getAvailableClasses<Base>();
112  for (auto & class_ : classes) {
113  loader->createUniqueInstance<Base>(class_)->saySomething();
114  }
115 }
116 
117 TEST(ClassLoaderUniquePtrTest, threadSafety) {
118  ClassLoader loader1(LIBRARY_1);
119  ASSERT_TRUE(loader1.isLibraryLoaded());
120 
121  // Note: Hard to test thread safety to make sure memory isn't corrupted.
122  // The hope is this test is hard enough that once in a while it'll segfault
123  // or something if there's some implementation error.
124  try {
125  std::vector<std::thread> client_threads;
126 
127  for (size_t c = 0; c < 1000; c++) {
128  client_threads.emplace_back(std::bind(&run, &loader1));
129  }
130 
131  for (auto & client_thread : client_threads) {
132  client_thread.join();
133  }
134 
135  loader1.unloadLibrary();
136  ASSERT_FALSE(loader1.isLibraryLoaded());
137  } catch (const class_loader::ClassLoaderException &) {
138  FAIL() << "Unexpected ClassLoaderException.";
139  } catch (...) {
140  FAIL() << "Unknown exception.";
141  }
142 }
143 
144 TEST(ClassLoaderUniquePtrTest, loadRefCountingLazy) {
145  try {
146  ClassLoader loader1(LIBRARY_1, true);
147  ASSERT_FALSE(loader1.isLibraryLoaded());
148 
149  {
150  ClassLoader::UniquePtr<Base> obj = loader1.createUniqueInstance<Base>("Dog");
151  ASSERT_TRUE(loader1.isLibraryLoaded());
152  }
153 
154  ASSERT_FALSE(loader1.isLibraryLoaded());
155 
156  loader1.loadLibrary();
157  ASSERT_TRUE(loader1.isLibraryLoaded());
158 
159  loader1.loadLibrary();
160  ASSERT_TRUE(loader1.isLibraryLoaded());
161 
162  loader1.unloadLibrary();
163  ASSERT_TRUE(loader1.isLibraryLoaded());
164 
165  loader1.unloadLibrary();
166  ASSERT_FALSE(loader1.isLibraryLoaded());
167 
168  loader1.unloadLibrary();
169  ASSERT_FALSE(loader1.isLibraryLoaded());
170 
171  loader1.loadLibrary();
172  ASSERT_TRUE(loader1.isLibraryLoaded());
173 
174  return;
175  } catch (const class_loader::ClassLoaderException &) {
176  FAIL() << "Unexpected exception.\n";
177  } catch (...) {
178  FAIL() << "Unknown exception caught.\n";
179  }
180 
181  FAIL() << "Did not throw exception as expected.\n";
182 }
183 
184 void testMultiClassLoader(bool lazy)
185 {
186  try {
188  loader.loadLibrary(LIBRARY_1);
189  loader.loadLibrary(LIBRARY_2);
190  for (int i = 0; i < 2; ++i) {
191  loader.createUniqueInstance<Base>("Cat")->saySomething();
192  loader.createUniqueInstance<Base>("Dog")->saySomething();
193  loader.createUniqueInstance<Base>("Robot")->saySomething();
194  }
195  } catch (class_loader::ClassLoaderException & e) {
196  FAIL() << "ClassLoaderException: " << e.what() << "\n";
197  }
198 
199  SUCCEED();
200 }
201 
202 TEST(MultiClassLoaderUniquePtrTest, lazyLoad) {
203  testMultiClassLoader(true);
204 }
205 TEST(MultiClassLoaderUniquePtrTest, lazyLoadSecondTime) {
206  testMultiClassLoader(true);
207 }
208 TEST(MultiClassLoaderUniquePtrTest, nonLazyLoad) {
209  testMultiClassLoader(false);
210 }
211 TEST(MultiClassLoaderUniquePtrTest, noWarningOnLazyLoad) {
212  try {
213  ClassLoader::UniquePtr<Base> cat = nullptr, dog = nullptr, rob = nullptr;
214  {
216  loader.loadLibrary(LIBRARY_1);
217  loader.loadLibrary(LIBRARY_2);
218 
219  cat = loader.createUniqueInstance<Base>("Cat");
220  dog = loader.createUniqueInstance<Base>("Dog");
221  rob = loader.createUniqueInstance<Base>("Robot");
222  }
223  cat->saySomething();
224  dog->saySomething();
225  rob->saySomething();
226  } catch (class_loader::ClassLoaderException & e) {
227  FAIL() << "ClassLoaderException: " << e.what() << "\n";
228  }
229 
230  SUCCEED();
231 }
232 
233 // Run all the tests that were declared with TEST()
234 int main(int argc, char ** argv)
235 {
236  testing::InitGoogleTest(&argc, argv);
237  return RUN_ALL_TESTS();
238 }
Definition: base.hpp:33
std::vector< std::string > getAvailableClasses()
Indicates which classes (i.e. class_loader) that can be loaded by this object.
ClassLoader::UniquePtr< Base > createUniqueInstance(const std::string &class_name)
Creates an instance of an object of given class name with ancestor class Base Same as createSharedIns...
A ClassLoader that can bind more than one runtime library.
UniquePtr< Base > createUniqueInstance(const std::string &derived_class_name)
Generates an instance of loadable classes (i.e. class_loader).
CLASS_LOADER_PUBLIC bool isLibraryLoaded()
Indicates if a library is loaded within the scope of this ClassLoader. Note that the library may alre...
CLASS_LOADER_PUBLIC std::string systemLibraryFormat(const std::string &library_name)
Returns a platform specific version of a basic library name.
const std::string LIBRARY_1
An exception class thrown when class_loader is unable to create a plugin.
Definition: exceptions.hpp:81
int main(int argc, char **argv)
This class allows loading and unloading of dynamically linked libraries which contain class definitio...
virtual void saySomething()=0
void loadLibrary(const std::string &library_path)
Loads a library into memory for this class loader.
CLASS_LOADER_PUBLIC int unloadLibrary()
Attempts to unload a library loaded within scope of the ClassLoader. If the library is not opened...
void wait(int seconds)
TEST(ClassLoaderUniquePtrTest, basicLoad)
const std::string LIBRARY_2
void testMultiClassLoader(bool lazy)
CLASS_LOADER_PUBLIC void loadLibrary()
Attempts to load a library on behalf of the ClassLoader. If the library is already opened...
CLASS_LOADER_PUBLIC bool isLibraryLoadedByAnybody(const std::string &library_path)
Indicates if passed library has been loaded by ANY ClassLoader.
void run(ClassLoader *loader)


class_loader
Author(s): Mirza Shah, Steven! Ragnarök
autogenerated on Mon Feb 28 2022 22:02:03