utest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012, Willow Garage, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Willow Garage, Inc. nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <chrono>
31 #include <cstddef>
32 #include <functional>
33 #include <iostream>
34 #include <string>
35 #include <thread>
36 #include <vector>
37 
40 
41 #include "gtest/gtest.h"
42 
43 #include "./base.hpp"
44 
45 const std::string LIBRARY_1 = class_loader::systemLibraryFormat("class_loader_TestPlugins1"); // NOLINT
46 const std::string LIBRARY_2 = class_loader::systemLibraryFormat("class_loader_TestPlugins2"); // NOLINT
47 
48 TEST(ClassLoaderTest, basicLoad) {
49  try {
50  class_loader::ClassLoader loader1(LIBRARY_1, false);
51  loader1.createInstance<Base>("Cat")->saySomething(); // See if lazy load works
53  FAIL() << "ClassLoaderException: " << e.what() << "\n";
54  }
55 
56  SUCCEED();
57 }
58 
59 TEST(ClassLoaderTest, correctNonLazyLoadUnload) {
60  try {
62  class_loader::ClassLoader loader1(LIBRARY_1, false);
64  ASSERT_TRUE(loader1.isLibraryLoaded());
65  loader1.unloadLibrary();
67  ASSERT_FALSE(loader1.isLibraryLoaded());
68  return;
70  FAIL() << "ClassLoaderException: " << e.what() << "\n";
71  } catch (...) {
72  FAIL() << "Unhandled exception";
73  }
74 }
75 
76 TEST(ClassLoaderTest, correctLazyLoadUnload) {
77  try {
79  class_loader::ClassLoader loader1(LIBRARY_1, true);
81  ASSERT_FALSE(loader1.isLibraryLoaded());
82 
83  {
84  boost::shared_ptr<Base> obj = loader1.createInstance<Base>("Cat");
86  ASSERT_TRUE(loader1.isLibraryLoaded());
87  }
88 
89  // The library will unload automatically when the only plugin object left is destroyed
91  return;
93  FAIL() << "ClassLoaderException: " << e.what() << "\n";
94  } catch (...) {
95  FAIL() << "Unhandled exception";
96  }
97 }
98 
99 TEST(ClassLoaderTest, nonExistentPlugin) {
100  class_loader::ClassLoader loader1(LIBRARY_1, false);
101 
102  try {
103  boost::shared_ptr<Base> obj = loader1.createInstance<Base>("Bear");
104  if (nullptr == obj) {
105  FAIL() << "Null object being returned instead of exception thrown.";
106  }
107 
108  obj->saySomething();
109  } catch (const class_loader::CreateClassException &) {
110  SUCCEED();
111  return;
112  } catch (...) {
113  FAIL() << "Unknown exception caught.\n";
114  }
115 
116  FAIL() << "Did not throw exception as expected.\n";
117 }
118 
119 TEST(ClassLoaderTest, nonExistentLibrary) {
120  try {
121  class_loader::ClassLoader loader1("libDoesNotExist.so", false);
122  } catch (const class_loader::LibraryLoadException &) {
123  SUCCEED();
124  return;
125  } catch (...) {
126  FAIL() << "Unknown exception caught.\n";
127  }
128 
129  FAIL() << "Did not throw exception as expected.\n";
130 }
131 
132 class InvalidBase
133 {
134 };
135 
136 TEST(ClassLoaderTest, invalidBase) {
137  try {
138  class_loader::ClassLoader loader1(LIBRARY_1, false);
139  if (loader1.isClassAvailable<InvalidBase>("Cat")) {
140  FAIL() << "Cat should not be available for InvalidBase";
141  } else if (loader1.isClassAvailable<Base>("Cat")) {
142  SUCCEED();
143  return;
144  } else {
145  FAIL() << "Class not available for correct base class.";
146  }
147  } catch (const class_loader::LibraryLoadException &) {
148  FAIL() << "Unexpected exception";
149  } catch (...) {
150  FAIL() << "Unexpected and unknown exception caught.\n";
151  }
152 }
153 
154 void wait(int seconds)
155 {
156  std::this_thread::sleep_for(std::chrono::seconds(seconds));
157 }
158 
160 {
161  std::vector<std::string> classes = loader->getAvailableClasses<Base>();
162  for (auto & class_ : classes) {
163  loader->createInstance<Base>(class_)->saySomething();
164  }
165 }
166 
167 TEST(ClassLoaderTest, threadSafety) {
169  ASSERT_TRUE(loader1.isLibraryLoaded());
170 
171  // Note: Hard to test thread safety to make sure memory isn't corrupted.
172  // The hope is this test is hard enough that once in a while it'll segfault
173  // or something if there's some implementation error.
174  try {
175  std::vector<std::thread *> client_threads;
176 
177  for (size_t c = 0; c < 1000; c++) {
178  client_threads.push_back(new std::thread(std::bind(&run, &loader1)));
179  }
180 
181  for (auto & client_thread : client_threads) {
182  client_thread->join();
183  }
184 
185  for (auto & client_thread : client_threads) {
186  delete (client_thread);
187  }
188 
189  loader1.unloadLibrary();
190  ASSERT_FALSE(loader1.isLibraryLoaded());
191  } catch (const class_loader::ClassLoaderException &) {
192  FAIL() << "Unexpected ClassLoaderException.";
193  } catch (...) {
194  FAIL() << "Unknown exception.";
195  }
196 }
197 
198 TEST(ClassLoaderTest, loadRefCountingNonLazy) {
199  try {
200  class_loader::ClassLoader loader1(LIBRARY_1, false);
201  ASSERT_TRUE(loader1.isLibraryLoaded());
202 
203  loader1.loadLibrary();
204  loader1.loadLibrary();
205  ASSERT_TRUE(loader1.isLibraryLoaded());
206 
207  loader1.unloadLibrary();
208  ASSERT_TRUE(loader1.isLibraryLoaded());
209 
210  loader1.unloadLibrary();
211  ASSERT_TRUE(loader1.isLibraryLoaded());
212 
213  loader1.unloadLibrary();
214  ASSERT_FALSE(loader1.isLibraryLoaded());
215 
216  loader1.unloadLibrary();
217  ASSERT_FALSE(loader1.isLibraryLoaded());
218 
219  loader1.loadLibrary();
220  ASSERT_TRUE(loader1.isLibraryLoaded());
221 
222  return;
223  } catch (const class_loader::ClassLoaderException &) {
224  FAIL() << "Unexpected exception.\n";
225  } catch (...) {
226  FAIL() << "Unknown exception caught.\n";
227  }
228 
229  FAIL() << "Did not throw exception as expected.\n";
230 }
231 
232 TEST(ClassLoaderTest, loadRefCountingLazy) {
233  try {
234  class_loader::ClassLoader loader1(LIBRARY_1, true);
235  ASSERT_FALSE(loader1.isLibraryLoaded());
236 
237  {
238  boost::shared_ptr<Base> obj = loader1.createInstance<Base>("Dog");
239  ASSERT_TRUE(loader1.isLibraryLoaded());
240  }
241 
242  ASSERT_FALSE(loader1.isLibraryLoaded());
243 
244  loader1.loadLibrary();
245  ASSERT_TRUE(loader1.isLibraryLoaded());
246 
247  loader1.loadLibrary();
248  ASSERT_TRUE(loader1.isLibraryLoaded());
249 
250  loader1.unloadLibrary();
251  ASSERT_TRUE(loader1.isLibraryLoaded());
252 
253  loader1.unloadLibrary();
254  ASSERT_FALSE(loader1.isLibraryLoaded());
255 
256  loader1.unloadLibrary();
257  ASSERT_FALSE(loader1.isLibraryLoaded());
258 
259  loader1.loadLibrary();
260  ASSERT_TRUE(loader1.isLibraryLoaded());
261 
262  return;
263  } catch (const class_loader::ClassLoaderException &) {
264  FAIL() << "Unexpected exception.\n";
265  } catch (...) {
266  FAIL() << "Unknown exception caught.\n";
267  }
268 
269  FAIL() << "Did not throw exception as expected.\n";
270 }
271 
272 void testMultiClassLoader(bool lazy)
273 {
274  try {
276  loader.loadLibrary(LIBRARY_1);
277  loader.loadLibrary(LIBRARY_2);
278  for (int i = 0; i < 2; ++i) {
279  loader.createInstance<Base>("Cat")->saySomething();
280  loader.createInstance<Base>("Dog")->saySomething();
281  loader.createInstance<Base>("Robot")->saySomething();
282  }
283  } catch (class_loader::ClassLoaderException & e) {
284  FAIL() << "ClassLoaderException: " << e.what() << "\n";
285  }
286 
287  SUCCEED();
288 }
289 
290 TEST(MultiClassLoaderTest, lazyLoad) {
291  testMultiClassLoader(true);
292 }
293 TEST(MultiClassLoaderTest, lazyLoadSecondTime) {
294  testMultiClassLoader(true);
295 }
296 TEST(MultiClassLoaderTest, nonLazyLoad) {
297  testMultiClassLoader(false);
298 }
299 TEST(MultiClassLoaderTest, noWarningOnLazyLoad) {
300  try {
301  boost::shared_ptr<Base> cat, dog, rob;
302  {
304  loader.loadLibrary(LIBRARY_1);
305  loader.loadLibrary(LIBRARY_2);
306 
307  cat = loader.createInstance<Base>("Cat");
308  dog = loader.createInstance<Base>("Dog");
309  rob = loader.createInstance<Base>("Robot");
310  }
311  cat->saySomething();
312  dog->saySomething();
313  rob->saySomething();
314  } catch (class_loader::ClassLoaderException & e) {
315  FAIL() << "ClassLoaderException: " << e.what() << "\n";
316  }
317 
318  SUCCEED();
319 }
320 
321 // Run all the tests that were declared with TEST()
322 int main(int argc, char ** argv)
323 {
324  testing::InitGoogleTest(&argc, argv);
325  return RUN_ALL_TESTS();
326 }
Definition: base.hpp:33
std::vector< std::string > getAvailableClasses()
Indicates which classes (i.e. class_loader) that can be loaded by this object.
An exception class thrown when class_loader is unable to load a runtime library.
Definition: exceptions.hpp:57
A ClassLoader that can bind more than one runtime library.
CLASS_LOADER_PUBLIC bool isLibraryLoaded()
Indicates if a library is loaded within the scope of this ClassLoader. Note that the library may alre...
const std::string LIBRARY_2
Definition: utest.cpp:46
CLASS_LOADER_PUBLIC std::string systemLibraryFormat(const std::string &library_name)
Returns a platform specific version of a basic library name.
void testMultiClassLoader(bool lazy)
Definition: utest.cpp:272
An exception class thrown when class_loader is unable to create a plugin.
Definition: exceptions.hpp:81
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.
int main(int argc, char **argv)
Definition: utest.cpp:322
bool isClassAvailable(const std::string &class_name)
Indicates if a plugin class is available.
void wait(int seconds)
Definition: utest.cpp:154
CLASS_LOADER_PUBLIC int unloadLibrary()
Attempts to unload a library loaded within scope of the ClassLoader. If the library is not opened...
void run(class_loader::ClassLoader *loader)
Definition: utest.cpp:159
boost::shared_ptr< Base > createInstance(const std::string &derived_class_name)
Generates an instance of loadable classes (i.e. class_loader).
const std::string LIBRARY_1
Definition: utest.cpp:45
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.
boost::shared_ptr< Base > createInstance(const std::string &class_name)
Creates an instance of an object of given class name with ancestor class Base Same as createSharedIns...
TEST(ClassLoaderTest, basicLoad)
Definition: utest.cpp:48


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