Boost External Test Runner
console_test_runner.cpp
Go to the documentation of this file.
1 // (C) Copyright Gennadiy Rozental 2005-2007.
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 
13 //suppression of warnings related to 3rd party files
14 #pragma warning ( disable: 6031 )
15 #pragma warning ( disable: 6011 )
16 #pragma warning ( disable: 6001 )
17 
18 #include <boost/test/unit_test.hpp>
19 
20 // Boost.Runtime.Param
21 #include <boost/test/utils/runtime/cla/named_parameter.hpp>
22 #include <boost/test/utils/runtime/cla/parser.hpp>
23 
24 //end suppression of warnings related to 3rd party files
25 #pragma warning ( default: 6031 )
26 #pragma warning ( default: 6011 )
27 #pragma warning ( default: 6001 )
28 
29 namespace rt = boost::runtime;
30 namespace cla = boost::runtime::cla;
31 
32 // STL
33 #include <iostream>
34 
35 #include <boost/cstdlib.hpp> // for exit codes
36 
37 #include <fstream>
38 #include "CBoostTestTreeLister.h"
40 
41 //_________________________________________________________________//
42 
43 // System API
44 
45 namespace dyn_lib
46 {
47 #if defined(BOOST_WINDOWS) && !defined(BOOST_DISABLE_WIN32) // WIN32 API
48 
49 #include <windows.h>
50 
51 typedef HINSTANCE handle;
52 
56 inline handle
57 open(std::string const& file_name)
58 {
59  return LoadLibrary(file_name.c_str());
60 }
61 
62 //_________________________________________________________________//
63 
69 template<typename TargType>
70 inline TargType
71 locate_symbol(handle h, std::string const& symbol)
72 {
73  return reinterpret_cast<TargType>(GetProcAddress(h, symbol.c_str()));
74 }
75 
76 //_________________________________________________________________//
77 
81 inline void
82 close(handle h)
83 {
84  if (h)
85  {
86  FreeLibrary(h);
87  }
88 }
89 
90 //_________________________________________________________________//
91 
92 inline std::string
93 error()
94 {
95  LPTSTR msg = NULL;
96 
97  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
98  NULL,
99  GetLastError(),
100  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
101  (LPTSTR)&msg,
102  0, NULL);
103 
104  std::string res;
105 
106  if (msg)
107  {
108  res = msg;
109  LocalFree(msg);
110  }
111 
112  return res;
113 }
114 
115 //_________________________________________________________________//
116 
117 #elif defined(BOOST_HAS_UNISTD_H) // POSIX API
118 
119 #include <dlfcn.h>
120 
121 #include <sys/types.h>
122 #include <sys/stat.h>
123 #include <fcntl.h>
124 
125 typedef void* handle;
126 
130 inline handle
131 open(std::string const& file_name)
132 {
133  return dlopen(file_name.c_str(), RTLD_LOCAL | RTLD_LAZY);
134 }
135 
136 //_________________________________________________________________//
140 template<typename TargType>
141 inline TargType
142 locate_symbol(handle h, std::string const& symbol)
143 {
144  return reinterpret_cast<TargType>(dlsym(h, symbol.c_str()));
145 }
146 
147 //_________________________________________________________________//
148 /*
149 * @brief Unloads a dll library on a POSIX run-time environment
150 */
151 inline void
152 close(handle h)
153 {
154  if (h)
155  {
156  dlclose(h);
157  }
158 }
159 
160 //_________________________________________________________________//
161 
162 inline std::string
163 error()
164 {
165  return dlerror();
166 }
167 
168 //_________________________________________________________________//
169 
170 #else
171 
172 #error "Dynamic library API is unknown"
173 
174 #endif
175 } // namespace dyn_lib
176 
177 //____________________________________________________________________________//
178 
179 static std::string test_lib_name;
180 static std::string init_func_name("init_unit_test");
181 
182 dyn_lib::handle test_lib_handle;
183 
184 typedef bool (*init_func_ptr)();
185 
186 //____________________________________________________________________________//
197 {
198  init_func_ptr init_func;
199 
200  test_lib_handle = dyn_lib::open(test_lib_name); //load the library via the relevant OS API
201 
202  if (!test_lib_handle)
203  throw std::logic_error(std::string("Fail to load test library: ")
204  .append(dyn_lib::error()));
205 
206  init_func = dyn_lib::locate_symbol<init_func_ptr>(test_lib_handle, init_func_name); //locate the initialization method inside the library
207 
212  /*
213  if( !init_func )
214  throw std::logic_error( std::string("Can't locate test initialization function ")
215  .append( init_func_name )
216  .append( ": " )
217  .append( dyn_lib::error() ) );
218  */
219 
220  return (init_func == nullptr) || ((*init_func)());
221 }
222 
223 //____________________________________________________________________________//
230 std::unique_ptr<std::ofstream> GetListOutputStream(const cla::parser& P, const std::string& arg)
231 {
232  std::string listOut;
233  assign_op(listOut, P.get(arg), 0);
234 
235  if (!listOut.empty())
236  {
237  return std::unique_ptr<std::ofstream>(new std::ofstream(listOut, (std::ios_base::out | std::ios_base::trunc)));
238  }
239 
240  return std::unique_ptr<std::ofstream>();
241 }
242 
243 //____________________________________________________________________________//
244 
245 typedef std::unique_ptr<::etas::boost::unit_test::CBoostTestTreeLister> TBoostTestTreeListerPtr;
246 
247 /*
248 * @brief Factory method return the correct type of test enumerator(lister) depending on the verbosity required
249 *
250 * @param [in] arg string containing either either "list" or "list-debug" on which the factory method will use to determine the type of lister to return
251 * @param [in] dll library path containing the Boost UTF tests
252 * @param [in] out pointer to an output stream class which the test enumerator will use to output the report
253 * @return object of either type CBoostTestTreeLister or CBoostTestTreeDebugLister depending on the verbosity required as supplied by argument arg
254 */
255 TBoostTestTreeListerPtr GetTestTreeLister(const std::string& arg, const std::string dll, std::ostream* out = nullptr)
256 {
257  out = (out == nullptr) ? &std::cout : out;
258 
259  if (arg == "list")
260  {
261  return TBoostTestTreeListerPtr(new ::etas::boost::unit_test::CBoostTestTreeLister(dll, out)); //less detail
262  }
263  else
264  {
265  return TBoostTestTreeListerPtr(new ::etas::boost::unit_test::CBoostTestTreeDebugLister(dll, out)); //more detail
266  }
267 
268 }
269 
270 //____________________________________________________________________________//
278 std::ostream& WriteError(std::ostream& out, const std::string& dll, const std::string& error = std::string())
279 {
280  out << "<![CDATA[Error: Could not load " << dll << '.';
281 
282  if (!error.empty())
283  {
284  out << " Detail: " << error;
285  }
286 
287  out << "]]>";
288 
289  return out;
290 }
291 
292 //____________________________________________________________________________//
299 int ListTests(const cla::parser& P)
300 {
301  int res = ::boost::exit_success;
302 
303  std::string arg = (P["list"]) ? "list" : "list-debug";
304 
305  std::unique_ptr<std::ofstream> out = GetListOutputStream(P, arg);
306  TBoostTestTreeListerPtr lister = GetTestTreeLister(arg, test_lib_name, out.get());
307 
308  if (lister != nullptr)
309  {
310  std::ostream& listing = lister->WriteHeader();
311 
312  try
313  {
318  if (load_test_lib())
319  {
320  //if the loading the library was successfull, then we proceed in enumerating the tests.
321  ::boost::unit_test::traverse_test_tree(::boost::unit_test::framework::master_test_suite(), *lister);
322  }
323  }
324  catch (std::exception& ex)
325  {
326  WriteError(listing, test_lib_name, ((ex.what() == nullptr) ? std::string() : ex.what()));
327  res = ::boost::exit_failure;
328  }
329  catch (...)
330  {
331  WriteError(listing, test_lib_name);
332  res = ::boost::exit_failure;
333  }
334 
335  lister->WriteTrailer();
336  }
337 
338  return res;
339 }
340 
341 //____________________________________________________________________________//
342 
471 int main(int argc, char* argv[])
472 {
473  try
474  {
475  cla::parser P;
476 
477  P - cla::ignore_mismatch
478  << cla::named_parameter<rt::cstring>("test") - (cla::prefix = "--")
479  << cla::named_parameter<rt::cstring>("list") - (cla::prefix = "--", cla::optional)
480  << cla::named_parameter<rt::cstring>("list-debug") - (cla::prefix = "--", cla::optional)
481  << cla::named_parameter<rt::cstring>("init") - (cla::prefix = "--", cla::optional);
482 
483  P.parse(argc, argv);
484 
485  assign_op(test_lib_name, P.get("test"), 0);
486 
487  if (P["init"])
488  {
489  assign_op(init_func_name, P.get("init"), 0);
490  }
491 
492  int res = ::boost::exit_success;
493 
494  //if the list or the list-debug command line directives are present then just enumerate tests,
495  //otherwise execute the tests according to the additional Boost UTF specific command line options supplied
496  if (P["list"] || P["list-debug"])
497  {
498  res = ListTests(P);
499  }
500  else
501  {
502  //run tests
503  res = ::boost::unit_test::unit_test_main(&load_test_lib, argc, argv);
504  }
505 
506  ::boost::unit_test::framework::clear();
507  dyn_lib::close(test_lib_handle); //unload the library
508 
509  return res;
510  }
511  catch (rt::logic_error const& ex)
512  {
513  std::cout << "Fail to parse command line arguments: " << ex.msg() << std::endl;
514  return -1;
515  }
516 }
517 
518 //____________________________________________________________________________//
519 
520 // EOF
std::unique_ptr<::etas::boost::unit_test::CBoostTestTreeLister > TBoostTestTreeListerPtr
static std::string test_lib_name
int main(int argc, char *argv[])
Entry point of the program.
int ListTests(const cla::parser &P)
Method handling the enumeration of the tests.
bool(* init_func_ptr)()
std::unique_ptr< std::ofstream > GetListOutputStream(const cla::parser &P, const std::string &arg)
Generates an object of type ofstream so as to write to file.
TBoostTestTreeListerPtr GetTestTreeLister(const std::string &arg, const std::string dll, std::ostream *out=nullptr)
std::ostream & WriteError(std::ostream &out, const std::string &dll, const std::string &error=std::string())
Method utilized to format and write any exceptions to the output stream.
dyn_lib::handle test_lib_handle
bool load_test_lib()
Load the Boost UTF dll containing the tests, locate the initialization method (either the default "in...
static std::string init_func_name("init_unit_test")