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 #include <boost/thread.hpp>
36 
37 #include <functional>
38 #include <iostream>
39 #include <string>
40 #include <vector>
41 
42 #include "./base.hpp"
43 
44 const char LIBRARY_1[] = "libclass_loader_TestPlugins1.so";
45 const char LIBRARY_2[] = "libclass_loader_TestPlugins2.so";
46 
48 
49 /*****************************************************************************/
50 TEST(ClassLoaderUniquePtrTest, basicLoad) {
51  try {
52  ClassLoader loader1(LIBRARY_1, false);
53  loader1.createUniqueInstance<Base>("Cat")->saySomething(); // See if lazy load works
54  SUCCEED();
56  FAIL() << "ClassLoaderException: " << e.what() << "\n";
57  }
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 /*****************************************************************************/
85 
86 TEST(ClassLoaderUniquePtrTest, nonExistentPlugin) {
87  ClassLoader loader1(LIBRARY_1, false);
88 
89  try {
90  ClassLoader::UniquePtr<Base> obj = loader1.createUniqueInstance<Base>("Bear");
91  if (nullptr == obj) {
92  FAIL() << "Null object being returned instead of exception thrown.";
93  }
94 
95  obj->saySomething();
96  } catch (const class_loader::CreateClassException &) {
97  SUCCEED();
98  return;
99  } catch (...) {
100  FAIL() << "Unknown exception caught.\n";
101  }
102 
103  FAIL() << "Did not throw exception as expected.\n";
104 }
105 
106 /*****************************************************************************/
107 
108 void wait(int seconds)
109 {
110  boost::this_thread::sleep(boost::posix_time::seconds(seconds));
111 }
112 
113 void run(ClassLoader * loader)
114 {
115  std::vector<std::string> classes = loader->getAvailableClasses<Base>();
116  for (unsigned int c = 0; c < classes.size(); c++) {
117  loader->createUniqueInstance<Base>(classes.at(c))->saySomething();
118  }
119 }
120 
121 TEST(ClassLoaderUniquePtrTest, threadSafety) {
122  ClassLoader loader1(LIBRARY_1);
123  ASSERT_TRUE(loader1.isLibraryLoaded());
124 
125  // Note: Hard to test thread safety to make sure memory isn't corrupted.
126  // The hope is this test is hard enough that once in a while it'll segfault
127  // or something if there's some implementation error.
128  try {
129  std::vector<boost::thread> client_threads;
130 
131  for (unsigned int c = 0; c < 1000; c++) {
132  client_threads.emplace_back(std::bind(&run, &loader1));
133  }
134 
135  for (unsigned int c = 0; c < client_threads.size(); c++) {
136  client_threads.at(c).join();
137  }
138 
139  loader1.unloadLibrary();
140  ASSERT_FALSE(loader1.isLibraryLoaded());
141  } catch (const class_loader::ClassLoaderException &) {
142  FAIL() << "Unexpected ClassLoaderException.";
143  } catch (...) {
144  FAIL() << "Unknown exception.";
145  }
146 }
147 
148 
149 /*****************************************************************************/
150 
151 TEST(ClassLoaderUniquePtrTest, loadRefCountingLazy) {
152  try {
153  ClassLoader loader1(LIBRARY_1, true);
154  ASSERT_FALSE(loader1.isLibraryLoaded());
155 
156  {
157  ClassLoader::UniquePtr<Base> obj = loader1.createUniqueInstance<Base>("Dog");
158  ASSERT_TRUE(loader1.isLibraryLoaded());
159  }
160 
161  ASSERT_FALSE(loader1.isLibraryLoaded());
162 
163  loader1.loadLibrary();
164  ASSERT_TRUE(loader1.isLibraryLoaded());
165 
166  loader1.loadLibrary();
167  ASSERT_TRUE(loader1.isLibraryLoaded());
168 
169  loader1.unloadLibrary();
170  ASSERT_TRUE(loader1.isLibraryLoaded());
171 
172  loader1.unloadLibrary();
173  ASSERT_FALSE(loader1.isLibraryLoaded());
174 
175  loader1.unloadLibrary();
176  ASSERT_FALSE(loader1.isLibraryLoaded());
177 
178  loader1.loadLibrary();
179  ASSERT_TRUE(loader1.isLibraryLoaded());
180 
181  return;
182  } catch (const class_loader::ClassLoaderException &) {
183  FAIL() << "Unexpected exception.\n";
184  } catch (...) {
185  FAIL() << "Unknown exception caught.\n";
186  }
187 
188  FAIL() << "Did not throw exception as expected.\n";
189 }
190 
191 
192 /*****************************************************************************/
193 
194 void testMultiClassLoader(bool lazy)
195 {
196  try {
198  loader.loadLibrary(LIBRARY_1);
199  loader.loadLibrary(LIBRARY_2);
200  for (int i = 0; i < 2; ++i) {
201  loader.createUniqueInstance<Base>("Cat")->saySomething();
202  loader.createUniqueInstance<Base>("Dog")->saySomething();
203  loader.createUniqueInstance<Base>("Robot")->saySomething();
204  }
205  } catch (class_loader::ClassLoaderException & e) {
206  FAIL() << "ClassLoaderException: " << e.what() << "\n";
207  }
208 
209  SUCCEED();
210 }
211 
212 TEST(MultiClassLoaderUniquePtrTest, lazyLoad) {
213  testMultiClassLoader(true);
214 }
215 TEST(MultiClassLoaderUniquePtrTest, lazyLoadSecondTime) {
216  testMultiClassLoader(true);
217 }
218 TEST(MultiClassLoaderUniquePtrTest, nonLazyLoad) {
219  testMultiClassLoader(false);
220 }
221 TEST(MultiClassLoaderUniquePtrTest, noWarningOnLazyLoad) {
222  try {
223  ClassLoader::UniquePtr<Base> cat = nullptr, dog = nullptr, rob = nullptr;
224  {
226  loader.loadLibrary(LIBRARY_1);
227  loader.loadLibrary(LIBRARY_2);
228 
229  cat = loader.createUniqueInstance<Base>("Cat");
230  dog = loader.createUniqueInstance<Base>("Dog");
231  rob = loader.createUniqueInstance<Base>("Robot");
232  }
233  cat->saySomething();
234  dog->saySomething();
235  rob->saySomething();
236  } catch (class_loader::ClassLoaderException & e) {
237  FAIL() << "ClassLoaderException: " << e.what() << "\n";
238  }
239 
240  SUCCEED();
241 }
242 
243 /*****************************************************************************/
244 
245 // Run all the tests that were declared with TEST()
246 int main(int argc, char ** argv)
247 {
248  testing::InitGoogleTest(&argc, argv);
249  return RUN_ALL_TESTS();
250 }
Definition: base.hpp:33
std::vector< std::string > getAvailableClasses()
Indicates which classes (i.e. class_loader) that can be loaded by this object.
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...
const char LIBRARY_1[]
An exception class thrown when class_loader is unable to create a plugin.
Definition: exceptions.hpp:80
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.
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 char LIBRARY_2[]
void testMultiClassLoader(bool lazy)
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...
void run(ClassLoader *loader)


class_loader
Author(s): Mirza Shah
autogenerated on Mon Oct 22 2018 03:57:45