1 //  (C) Copyright Gennadiy Rozental 2005-2014.
2 //  Distributed under the Boost Software License, Version 1.0.
3 //  (See accompanying file LICENSE_1_0.txt or copy at
4 //  http://www.boost.org/LICENSE_1_0.txt)
5 
6 //  See http://www.boost.org/libs/test for the library home page.
7 
8 // Boost.Test
9 #ifndef BOOST_TEST_DYN_LINK
10 #define BOOST_TEST_DYN_LINK
11 #endif
12 #include <boost/test/unit_test.hpp>
13 
14 // Boost.Runtime.Param
15 #include <boost/test/utils/runtime/cla/named_parameter.hpp>
16 #include <boost/test/utils/runtime/cla/parser.hpp>
17 
18 namespace rt  = boost::runtime;
19 namespace cla = boost::runtime::cla;
20 
21 // STL
22 #include <iostream>
23 
24 //_________________________________________________________________//
25 
26 // System API
27 
28 namespace dyn_lib {
29 
30 #if defined(BOOST_WINDOWS) && !defined(BOOST_DISABLE_WIN32) // WIN32 API
31 
32 #include <windows.h>
33 
34 typedef HINSTANCE handle;
35 
36 inline handle
open(std::string const & file_name)37 open( std::string const& file_name )
38 {
39     return LoadLibrary( file_name.c_str() );
40 }
41 
42 //_________________________________________________________________//
43 
44 template<typename TargType>
45 inline TargType
locate_symbol(handle h,std::string const & symbol)46 locate_symbol( handle h, std::string const& symbol )
47 {
48     return reinterpret_cast<TargType>( GetProcAddress( h, symbol.c_str() ) );
49 }
50 
51 //_________________________________________________________________//
52 
53 inline void
close(handle h)54 close( handle h )
55 {
56     if( h )
57         FreeLibrary( h );
58 }
59 
60 //_________________________________________________________________//
61 
62 inline std::string
error()63 error()
64 {
65     LPTSTR msg = NULL;
66 
67     FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
68                    NULL,
69                    GetLastError(),
70                    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
71                    (LPTSTR)&msg,
72                    0, NULL );
73 
74     std::string res( msg );
75 
76     if( msg )
77         LocalFree( msg );
78 
79     return res;
80 }
81 
82 //_________________________________________________________________//
83 
84 #elif defined(BOOST_HAS_UNISTD_H) // POSIX API
85 
86 #include <dlfcn.h>
87 
88 #include <sys/types.h>
89 #include <sys/stat.h>
90 #include <fcntl.h>
91 
92 
93 typedef void* handle;
94 
95 inline handle
96 open( std::string const& file_name )
97 {
98     return dlopen( file_name.c_str(), RTLD_LOCAL | RTLD_LAZY );
99 }
100 
101 //_________________________________________________________________//
102 
103 template<typename TargType>
104 inline TargType
105 locate_symbol( handle h, std::string const& symbol )
106 {
107     return reinterpret_cast<TargType>( dlsym( h, symbol.c_str() ) );
108 }
109 
110 //_________________________________________________________________//
111 
112 inline void
113 close( handle h )
114 {
115     if( h )
116         dlclose( h );
117 }
118 
119 //_________________________________________________________________//
120 
121 inline std::string
122 error()
123 {
124     return dlerror();
125 }
126 
127 //_________________________________________________________________//
128 
129 #else
130 
131 #error "Dynamic library API is unknown"
132 
133 #endif
134 
135 } // namespace dyn_lib
136 
137 //____________________________________________________________________________//
138 
139 static std::string test_lib_name;
140 static std::string init_func_name( "init_unit_test" );
141 
142 dyn_lib::handle test_lib_handle;
143 
load_test_lib()144 bool load_test_lib()
145 {
146     typedef bool (*init_func_ptr)();
147     init_func_ptr init_func;
148 
149     test_lib_handle = dyn_lib::open( test_lib_name );
150     if( !test_lib_handle )
151         throw std::logic_error( std::string("Fail to load test library: ")
152                                     .append( dyn_lib::error() ) );
153 
154     init_func =  dyn_lib::locate_symbol<init_func_ptr>( test_lib_handle, init_func_name );
155 
156     if( !init_func )
157         throw std::logic_error( std::string("Can't locate test initilization function ")
158                                     .append( init_func_name )
159                                     .append( ": " )
160                                     .append( dyn_lib::error() ) );
161 
162     return (*init_func)();
163 }
164 
165 //____________________________________________________________________________//
166 
main(int argc,char * argv[])167 int main( int argc, char* argv[] )
168 {
169     try {
170         cla::parser P;
171 
172         P - cla::ignore_mismatch
173             << cla::named_parameter<rt::cstring>( "test" ) - (cla::prefix = "--")
174             << cla::named_parameter<rt::cstring>( "init" ) - (cla::prefix = "--",cla::optional);
175 
176         P.parse( argc, argv );
177 
178         assign_op( test_lib_name, P.get( "test" ), 0 );
179         if( P["init"] )
180             assign_op( init_func_name, P.get( "init" ), 0 );
181 
182         int res = ::boost::unit_test::unit_test_main( &load_test_lib, argc, argv );
183 
184         ::boost::unit_test::framework::clear();
185         dyn_lib::close( test_lib_handle );
186 
187         return res;
188     }
189     catch( rt::logic_error const& ex ) {
190         std::cout << "Fail to parse command line arguments: " << ex.msg() << std::endl;
191         return -1;
192     }
193 }
194 
195 //____________________________________________________________________________//
196 
197 // EOF
198