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 <boost/thread.hpp>
31 #include <boost/bind.hpp>
32 #include <iostream>
33 #include <string>
34 #include <vector>
35 
38 
39 #include "gtest/gtest.h"
40 
41 #include "./base.hpp"
42 
43 const char LIBRARY_1[] = "libclass_loader_TestPlugins1.so";
44 const char LIBRARY_2[] = "libclass_loader_TestPlugins2.so";
45 
46 /*****************************************************************************/
47 TEST(ClassLoaderTest, basicLoad) {
48  try {
49  class_loader::ClassLoader loader1(LIBRARY_1, false);
50  loader1.createInstance<Base>("Cat")->saySomething(); // See if lazy load works
52  FAIL() << "ClassLoaderException: " << e.what() << "\n";
53  }
54 
55  SUCCEED();
56 }
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 /*****************************************************************************/
77 TEST(ClassLoaderTest, correctLazyLoadUnload) {
78  try {
80  class_loader::ClassLoader loader1(LIBRARY_1, true);
82  ASSERT_FALSE(loader1.isLibraryLoaded());
83 
84  {
85  boost::shared_ptr<Base> obj = loader1.createInstance<Base>("Cat");
87  ASSERT_TRUE(loader1.isLibraryLoaded());
88  }
89 
90  // The library will unload automatically when the only plugin object left is destroyed
92  return;
94  FAIL() << "ClassLoaderException: " << e.what() << "\n";
95  } catch (...) {
96  FAIL() << "Unhandled exception";
97  }
98 }
99 
100 /*****************************************************************************/
101 
102 TEST(ClassLoaderTest, nonExistentPlugin) {
103  class_loader::ClassLoader loader1(LIBRARY_1, false);
104 
105  try {
106  boost::shared_ptr<Base> obj = loader1.createInstance<Base>("Bear");
107  if (NULL == obj) {
108  FAIL() << "Null object being returned instead of exception thrown.";
109  }
110 
111  obj->saySomething();
112  } catch (const class_loader::CreateClassException &) {
113  SUCCEED();
114  return;
115  } catch (...) {
116  FAIL() << "Unknown exception caught.\n";
117  }
118 
119  FAIL() << "Did not throw exception as expected.\n";
120 }
121 
122 /*****************************************************************************/
123 TEST(ClassLoaderTest, nonExistentLibrary) {
124  try {
125  class_loader::ClassLoader loader1("libDoesNotExist.so", false);
126  } catch (const class_loader::LibraryLoadException &) {
127  SUCCEED();
128  return;
129  } catch (...) {
130  FAIL() << "Unknown exception caught.\n";
131  }
132 
133  FAIL() << "Did not throw exception as expected.\n";
134 }
135 
136 /*****************************************************************************/
137 
139 {
140 };
141 
142 TEST(ClassLoaderTest, invalidBase) {
143  try {
144  class_loader::ClassLoader loader1(LIBRARY_1, false);
145  if (loader1.isClassAvailable<InvalidBase>("Cat")) {
146  FAIL() << "Cat should not be available for InvalidBase";
147  } else if (loader1.isClassAvailable<Base>("Cat")) {
148  SUCCEED();
149  return;
150  } else {
151  FAIL() << "Class not available for correct base class.";
152  }
153  } catch (const class_loader::LibraryLoadException &) {
154  FAIL() << "Unexpected exception";
155  } catch (...) {
156  FAIL() << "Unexpected and unknown exception caught.\n";
157  }
158 }
159 
160 /*****************************************************************************/
161 
162 void wait(int seconds)
163 {
164  boost::this_thread::sleep(boost::posix_time::seconds(seconds));
165 }
166 
168 {
169  std::vector<std::string> classes = loader->getAvailableClasses<Base>();
170  for (unsigned int c = 0; c < classes.size(); c++) {
171  loader->createInstance<Base>(classes.at(c))->saySomething();
172  }
173 }
174 
175 TEST(ClassLoaderTest, threadSafety) {
177  ASSERT_TRUE(loader1.isLibraryLoaded());
178 
179  // Note: Hard to test thread safety to make sure memory isn't corrupted.
180  // The hope is this test is hard enough that once in a while it'll segfault
181  // or something if there's some implementation error.
182  try {
183  std::vector<boost::thread *> client_threads;
184 
185  for (unsigned int c = 0; c < 1000; c++) {
186  client_threads.push_back(new boost::thread(boost::bind(&run, &loader1)));
187  }
188 
189  for (unsigned int c = 0; c < client_threads.size(); c++) {
190  client_threads.at(c)->join();
191  }
192 
193  for (unsigned int c = 0; c < client_threads.size(); c++) {
194  delete (client_threads.at(c));
195  }
196 
197  loader1.unloadLibrary();
198  ASSERT_FALSE(loader1.isLibraryLoaded());
199  } catch (const class_loader::ClassLoaderException &) {
200  FAIL() << "Unexpected ClassLoaderException.";
201  } catch (...) {
202  FAIL() << "Unknown exception.";
203  }
204 }
205 
206 /*****************************************************************************/
207 
208 TEST(ClassLoaderTest, loadRefCountingNonLazy) {
209  try {
210  class_loader::ClassLoader loader1(LIBRARY_1, false);
211  ASSERT_TRUE(loader1.isLibraryLoaded());
212 
213  loader1.loadLibrary();
214  loader1.loadLibrary();
215  ASSERT_TRUE(loader1.isLibraryLoaded());
216 
217  loader1.unloadLibrary();
218  ASSERT_TRUE(loader1.isLibraryLoaded());
219 
220  loader1.unloadLibrary();
221  ASSERT_TRUE(loader1.isLibraryLoaded());
222 
223  loader1.unloadLibrary();
224  ASSERT_FALSE(loader1.isLibraryLoaded());
225 
226  loader1.unloadLibrary();
227  ASSERT_FALSE(loader1.isLibraryLoaded());
228 
229  loader1.loadLibrary();
230  ASSERT_TRUE(loader1.isLibraryLoaded());
231 
232  return;
233  } catch (const class_loader::ClassLoaderException &) {
234  FAIL() << "Unexpected exception.\n";
235  } catch (...) {
236  FAIL() << "Unknown exception caught.\n";
237  }
238 
239  FAIL() << "Did not throw exception as expected.\n";
240 }
241 
242 /*****************************************************************************/
243 
244 TEST(ClassLoaderTest, loadRefCountingLazy) {
245  try {
246  class_loader::ClassLoader loader1(LIBRARY_1, true);
247  ASSERT_FALSE(loader1.isLibraryLoaded());
248 
249  {
250  boost::shared_ptr<Base> obj = loader1.createInstance<Base>("Dog");
251  ASSERT_TRUE(loader1.isLibraryLoaded());
252  }
253 
254  ASSERT_FALSE(loader1.isLibraryLoaded());
255 
256  loader1.loadLibrary();
257  ASSERT_TRUE(loader1.isLibraryLoaded());
258 
259  loader1.loadLibrary();
260  ASSERT_TRUE(loader1.isLibraryLoaded());
261 
262  loader1.unloadLibrary();
263  ASSERT_TRUE(loader1.isLibraryLoaded());
264 
265  loader1.unloadLibrary();
266  ASSERT_FALSE(loader1.isLibraryLoaded());
267 
268  loader1.unloadLibrary();
269  ASSERT_FALSE(loader1.isLibraryLoaded());
270 
271  loader1.loadLibrary();
272  ASSERT_TRUE(loader1.isLibraryLoaded());
273 
274  return;
275  } catch (const class_loader::ClassLoaderException &) {
276  FAIL() << "Unexpected exception.\n";
277  } catch (...) {
278  FAIL() << "Unknown exception caught.\n";
279  }
280 
281  FAIL() << "Did not throw exception as expected.\n";
282 }
283 
284 
285 /*****************************************************************************/
286 
287 void testMultiClassLoader(bool lazy)
288 {
289  try {
291  loader.loadLibrary(LIBRARY_1);
292  loader.loadLibrary(LIBRARY_2);
293  for (int i = 0; i < 2; ++i) {
294  loader.createInstance<Base>("Cat")->saySomething();
295  loader.createInstance<Base>("Dog")->saySomething();
296  loader.createInstance<Base>("Robot")->saySomething();
297  }
298  } catch (class_loader::ClassLoaderException & e) {
299  FAIL() << "ClassLoaderException: " << e.what() << "\n";
300  }
301 
302  SUCCEED();
303 }
304 
305 TEST(MultiClassLoaderTest, lazyLoad) {
306  testMultiClassLoader(true);
307 }
308 TEST(MultiClassLoaderTest, lazyLoadSecondTime) {
309  testMultiClassLoader(true);
310 }
311 TEST(MultiClassLoaderTest, nonLazyLoad) {
312  testMultiClassLoader(false);
313 }
314 TEST(MultiClassLoaderTest, noWarningOnLazyLoad) {
315  try {
316  boost::shared_ptr<Base> cat, dog, rob;
317  {
319  loader.loadLibrary(LIBRARY_1);
320  loader.loadLibrary(LIBRARY_2);
321 
322  cat = loader.createInstance<Base>("Cat");
323  dog = loader.createInstance<Base>("Dog");
324  rob = loader.createInstance<Base>("Robot");
325  }
326  cat->saySomething();
327  dog->saySomething();
328  rob->saySomething();
329  } catch (class_loader::ClassLoaderException & e) {
330  FAIL() << "ClassLoaderException: " << e.what() << "\n";
331  }
332 
333  SUCCEED();
334 }
335 
336 /*****************************************************************************/
337 
338 // Run all the tests that were declared with TEST()
339 int main(int argc, char ** argv)
340 {
341  testing::InitGoogleTest(&argc, argv);
342  return RUN_ALL_TESTS();
343 }
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:58
A ClassLoader that can bind more than one runtime library.
bool isLibraryLoaded()
Indicates if a library is loaded within the scope of this ClassLoader. Note that the library may alre...
void testMultiClassLoader(bool lazy)
Definition: utest.cpp:287
An exception class thrown when class_loader is unable to create a plugin.
Definition: exceptions.hpp:80
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:339
bool isClassAvailable(const std::string &class_name)
Indicates if a plugin class is available.
void wait(int seconds)
Definition: utest.cpp:162
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:167
const char LIBRARY_2[]
Definition: utest.cpp:44
boost::shared_ptr< Base > createInstance(const std::string &derived_class_name)
Generates an instance of loadable classes (i.e. class_loader).
bool isLibraryLoadedByAnybody(const std::string &library_path)
Indicates if passed library has been loaded by ANY ClassLoader.
void loadLibrary()
Attempts to load a library on behalf of the ClassLoader. If the library is already opened...
const char LIBRARY_1[]
Definition: utest.cpp:43
boost::shared_ptr< Base > createInstance(const std::string &class_name)
Creates an instance of an object of given class name with ancestor class Base This version does not l...
TEST(ClassLoaderTest, basicLoad)
Definition: utest.cpp:47


class_loader
Author(s): Mirza Shah
autogenerated on Mon Jun 10 2019 12:51:50