PageRenderTime 36ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/test/test.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 486 lines | 374 code | 59 blank | 53 comment | 26 complexity | 13b1ecd3f0954571e84c64fff6dffda5 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file test.cpp
  3. * @author Phoenix
  4. * @date 2005-09-26
  5. * @brief Entry point for the test app.
  6. *
  7. * $LicenseInfo:firstyear=2005&license=viewerlgpl$
  8. * Second Life Viewer Source Code
  9. * Copyright (C) 2010, Linden Research, Inc.
  10. *
  11. * This library is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation;
  14. * version 2.1 of the License only.
  15. *
  16. * This library is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with this library; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *
  25. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  26. * $/LicenseInfo$
  27. */
  28. /**
  29. *
  30. * You can add tests by creating a new cpp file in this directory, and
  31. * rebuilding. There are at most 50 tests per testgroup without a
  32. * little bit of template parameter and makefile tweaking.
  33. *
  34. */
  35. #include "linden_common.h"
  36. #include "llerrorcontrol.h"
  37. #include "lltut.h"
  38. #include "apr_pools.h"
  39. #include "apr_getopt.h"
  40. // the CTYPE_WORKAROUND is needed for linux dev stations that don't
  41. // have the broken libc6 packages needed by our out-of-date static
  42. // libs (such as libcrypto and libcurl). -- Leviathan 20060113
  43. #ifdef CTYPE_WORKAROUND
  44. # include "ctype_workaround.h"
  45. #endif
  46. #ifndef LL_WINDOWS
  47. #include <gmock/gmock.h>
  48. #include <gtest/gtest.h>
  49. #endif
  50. namespace tut
  51. {
  52. std::string sSourceDir;
  53. test_runner_singleton runner;
  54. }
  55. class LLTestCallback : public tut::callback
  56. {
  57. public:
  58. LLTestCallback(bool verbose_mode, std::ostream *stream) :
  59. mVerboseMode(verbose_mode),
  60. mTotalTests(0),
  61. mPassedTests(0),
  62. mFailedTests(0),
  63. mSkippedTests(0),
  64. mStream(stream)
  65. {
  66. }
  67. ~LLTestCallback()
  68. {
  69. }
  70. virtual void run_started()
  71. {
  72. //std::cout << "run_started" << std::endl;
  73. }
  74. virtual void group_started(const std::string& name) {
  75. std::cout << "Unit test group_started name=" << name << std::endl;
  76. }
  77. virtual void group_completed(const std::string& name) {
  78. std::cout << "Unit test group_completed name=" << name << std::endl;
  79. }
  80. virtual void test_completed(const tut::test_result& tr)
  81. {
  82. ++mTotalTests;
  83. std::ostringstream out;
  84. out << "[" << tr.group << ", " << tr.test << "] ";
  85. switch(tr.result)
  86. {
  87. case tut::test_result::ok:
  88. ++mPassedTests;
  89. out << "ok";
  90. break;
  91. case tut::test_result::fail:
  92. ++mFailedTests;
  93. out << "fail";
  94. break;
  95. case tut::test_result::ex:
  96. ++mFailedTests;
  97. out << "exception";
  98. break;
  99. case tut::test_result::warn:
  100. ++mFailedTests;
  101. out << "test destructor throw";
  102. break;
  103. case tut::test_result::term:
  104. ++mFailedTests;
  105. out << "abnormal termination";
  106. break;
  107. case tut::test_result::skip:
  108. ++mSkippedTests;
  109. out << "skipped known failure";
  110. break;
  111. default:
  112. ++mFailedTests;
  113. out << "unknown";
  114. }
  115. if(mVerboseMode || (tr.result != tut::test_result::ok))
  116. {
  117. if(!tr.message.empty())
  118. {
  119. out << ": '" << tr.message << "'";
  120. }
  121. if (mStream)
  122. {
  123. *mStream << out.str() << std::endl;
  124. }
  125. std::cout << out.str() << std::endl;
  126. }
  127. }
  128. virtual void run_completed()
  129. {
  130. if (mStream)
  131. {
  132. run_completed_(*mStream);
  133. }
  134. run_completed_(std::cout);
  135. }
  136. virtual int getFailedTests() const { return mFailedTests; }
  137. virtual void run_completed_(std::ostream &stream)
  138. {
  139. stream << "\tTotal Tests:\t" << mTotalTests << std::endl;
  140. stream << "\tPassed Tests:\t" << mPassedTests;
  141. if (mPassedTests == mTotalTests)
  142. {
  143. stream << "\tYAY!! \\o/";
  144. }
  145. stream << std::endl;
  146. if (mSkippedTests > 0)
  147. {
  148. stream << "\tSkipped known failures:\t" << mSkippedTests
  149. << std::endl;
  150. }
  151. if(mFailedTests > 0)
  152. {
  153. stream << "*********************************" << std::endl;
  154. stream << "Failed Tests:\t" << mFailedTests << std::endl;
  155. stream << "Please report or fix the problem." << std::endl;
  156. stream << "*********************************" << std::endl;
  157. }
  158. }
  159. protected:
  160. bool mVerboseMode;
  161. int mTotalTests;
  162. int mPassedTests;
  163. int mFailedTests;
  164. int mSkippedTests;
  165. std::ostream *mStream;
  166. };
  167. // TeamCity specific class which emits service messages
  168. // http://confluence.jetbrains.net/display/TCD3/Build+Script+Interaction+with+TeamCity;#BuildScriptInteractionwithTeamCity-testReporting
  169. class LLTCTestCallback : public LLTestCallback
  170. {
  171. public:
  172. LLTCTestCallback(bool verbose_mode, std::ostream *stream) :
  173. LLTestCallback(verbose_mode, stream),
  174. mTCStream()
  175. {
  176. }
  177. ~LLTCTestCallback()
  178. {
  179. }
  180. virtual void group_started(const std::string& name) {
  181. LLTestCallback::group_started(name);
  182. mTCStream << "\n##teamcity[testSuiteStarted name='" << name << "']" << std::endl;
  183. }
  184. virtual void group_completed(const std::string& name) {
  185. LLTestCallback::group_completed(name);
  186. mTCStream << "##teamcity[testSuiteFinished name='" << name << "']" << std::endl;
  187. }
  188. virtual void test_completed(const tut::test_result& tr)
  189. {
  190. LLTestCallback::test_completed(tr);
  191. switch(tr.result)
  192. {
  193. case tut::test_result::ok:
  194. mTCStream << "##teamcity[testStarted name='" << tr.group << "." << tr.test << "']" << std::endl;
  195. mTCStream << "##teamcity[testFinished name='" << tr.group << "." << tr.test << "']" << std::endl;
  196. break;
  197. case tut::test_result::fail:
  198. mTCStream << "##teamcity[testStarted name='" << tr.group << "." << tr.test << "']" << std::endl;
  199. mTCStream << "##teamcity[testFailed name='" << tr.group << "." << tr.test << "' message='" << tr.message << "']" << std::endl;
  200. mTCStream << "##teamcity[testFinished name='" << tr.group << "." << tr.test << "']" << std::endl;
  201. break;
  202. case tut::test_result::ex:
  203. mTCStream << "##teamcity[testStarted name='" << tr.group << "." << tr.test << "']" << std::endl;
  204. mTCStream << "##teamcity[testFailed name='" << tr.group << "." << tr.test << "' message='" << tr.message << "']" << std::endl;
  205. mTCStream << "##teamcity[testFinished name='" << tr.group << "." << tr.test << "']" << std::endl;
  206. break;
  207. case tut::test_result::warn:
  208. mTCStream << "##teamcity[testStarted name='" << tr.group << "." << tr.test << "']" << std::endl;
  209. mTCStream << "##teamcity[testFailed name='" << tr.group << "." << tr.test << "' message='" << tr.message << "']" << std::endl;
  210. mTCStream << "##teamcity[testFinished name='" << tr.group << "." << tr.test << "']" << std::endl;
  211. break;
  212. case tut::test_result::term:
  213. mTCStream << "##teamcity[testStarted name='" << tr.group << "." << tr.test << "']" << std::endl;
  214. mTCStream << "##teamcity[testFailed name='" << tr.group << "." << tr.test << "' message='" << tr.message << "']" << std::endl;
  215. mTCStream << "##teamcity[testFinished name='" << tr.group << "." << tr.test << "']" << std::endl;
  216. break;
  217. case tut::test_result::skip:
  218. mTCStream << "##teamcity[testStarted name='" << tr.group << "." << tr.test << "']" << std::endl;
  219. mTCStream << "##teamcity[testIgnored name='" << tr.group << "." << tr.test << "']" << std::endl;
  220. mTCStream << "##teamcity[testFinished name='" << tr.group << "." << tr.test << "']" << std::endl;
  221. break;
  222. default:
  223. break;
  224. }
  225. }
  226. virtual void run_completed()
  227. {
  228. LLTestCallback::run_completed();
  229. // dump the TC reporting results to cout
  230. tc_run_completed_(std::cout);
  231. }
  232. virtual void tc_run_completed_(std::ostream &stream)
  233. {
  234. // dump the TC reporting results to cout
  235. stream << mTCStream.str() << std::endl;
  236. }
  237. protected:
  238. std::ostringstream mTCStream;
  239. };
  240. static const apr_getopt_option_t TEST_CL_OPTIONS[] =
  241. {
  242. {"help", 'h', 0, "Print the help message."},
  243. {"list", 'l', 0, "List available test groups."},
  244. {"verbose", 'v', 0, "Verbose output."},
  245. {"group", 'g', 1, "Run test group specified by option argument."},
  246. {"output", 'o', 1, "Write output to the named file."},
  247. {"sourcedir", 's', 1, "Project source file directory from CMake."},
  248. {"touch", 't', 1, "Touch the given file if all tests succeed"},
  249. {"wait", 'w', 0, "Wait for input before exit."},
  250. {"debug", 'd', 0, "Emit full debug logs."},
  251. {"suitename", 'x', 1, "Run tests using this suitename"},
  252. {0, 0, 0, 0}
  253. };
  254. void stream_usage(std::ostream& s, const char* app)
  255. {
  256. s << "Usage: " << app << " [OPTIONS]" << std::endl
  257. << std::endl;
  258. s << "This application runs the unit tests." << std::endl << std::endl;
  259. s << "Options: " << std::endl;
  260. const apr_getopt_option_t* option = &TEST_CL_OPTIONS[0];
  261. while(option->name)
  262. {
  263. s << " ";
  264. s << " -" << (char)option->optch << ", --" << option->name
  265. << std::endl;
  266. s << "\t" << option->description << std::endl << std::endl;
  267. ++option;
  268. }
  269. s << "Examples:" << std::endl;
  270. s << " " << app << " --verbose" << std::endl;
  271. s << "\tRun all the tests and report all results." << std::endl;
  272. s << " " << app << " --list" << std::endl;
  273. s << "\tList all available test groups." << std::endl;
  274. s << " " << app << " --group=uuid" << std::endl;
  275. s << "\tRun the test group 'uuid'." << std::endl;
  276. }
  277. void stream_groups(std::ostream& s, const char* app)
  278. {
  279. s << "Registered test groups:" << std::endl;
  280. tut::groupnames gl = tut::runner.get().list_groups();
  281. tut::groupnames::const_iterator it = gl.begin();
  282. tut::groupnames::const_iterator end = gl.end();
  283. for(; it != end; ++it)
  284. {
  285. s << " " << *(it) << std::endl;
  286. }
  287. }
  288. void wouldHaveCrashed(const std::string& message)
  289. {
  290. tut::fail("llerrs message: " + message);
  291. }
  292. int main(int argc, char **argv)
  293. {
  294. // The following line must be executed to initialize Google Mock
  295. // (and Google Test) before running the tests.
  296. #ifndef LL_WINDOWS
  297. ::testing::InitGoogleMock(&argc, argv);
  298. #endif
  299. LLError::initForApplication(".");
  300. LLError::setFatalFunction(wouldHaveCrashed);
  301. LLError::setDefaultLevel(LLError::LEVEL_ERROR);
  302. //< *TODO: should come from error config file. Note that we
  303. // have a command line option that sets this to debug.
  304. #ifdef CTYPE_WORKAROUND
  305. ctype_workaround();
  306. #endif
  307. apr_initialize();
  308. apr_pool_t* pool = NULL;
  309. if(APR_SUCCESS != apr_pool_create(&pool, NULL))
  310. {
  311. std::cerr << "Unable to initialize pool" << std::endl;
  312. return 1;
  313. }
  314. apr_getopt_t* os = NULL;
  315. if(APR_SUCCESS != apr_getopt_init(&os, pool, argc, argv))
  316. {
  317. std::cerr << "Unable to pool" << std::endl;
  318. return 1;
  319. }
  320. // values used for controlling application
  321. bool verbose_mode = false;
  322. bool wait_at_exit = false;
  323. std::string test_group;
  324. std::string suite_name;
  325. // values use for options parsing
  326. apr_status_t apr_err;
  327. const char* opt_arg = NULL;
  328. int opt_id = 0;
  329. std::ofstream *output = NULL;
  330. const char *touch = NULL;
  331. while(true)
  332. {
  333. apr_err = apr_getopt_long(os, TEST_CL_OPTIONS, &opt_id, &opt_arg);
  334. if(APR_STATUS_IS_EOF(apr_err)) break;
  335. if(apr_err)
  336. {
  337. char buf[255]; /* Flawfinder: ignore */
  338. std::cerr << "Error parsing options: "
  339. << apr_strerror(apr_err, buf, 255) << std::endl;
  340. return 1;
  341. }
  342. switch (opt_id)
  343. {
  344. case 'g':
  345. test_group.assign(opt_arg);
  346. break;
  347. case 'h':
  348. stream_usage(std::cout, argv[0]);
  349. return 0;
  350. break;
  351. case 'l':
  352. stream_groups(std::cout, argv[0]);
  353. return 0;
  354. case 'v':
  355. verbose_mode = true;
  356. break;
  357. case 'o':
  358. output = new std::ofstream;
  359. output->open(opt_arg);
  360. break;
  361. case 's': // --sourcedir
  362. tut::sSourceDir = opt_arg;
  363. // For convenience, so you can use tut::sSourceDir + "myfile"
  364. tut::sSourceDir += '/';
  365. break;
  366. case 't':
  367. touch = opt_arg;
  368. break;
  369. case 'w':
  370. wait_at_exit = true;
  371. break;
  372. case 'd':
  373. // *TODO: should come from error config file. We set it to
  374. // ERROR by default, so this allows full debug levels.
  375. LLError::setDefaultLevel(LLError::LEVEL_DEBUG);
  376. break;
  377. case 'x':
  378. suite_name.assign(opt_arg);
  379. break;
  380. default:
  381. stream_usage(std::cerr, argv[0]);
  382. return 1;
  383. break;
  384. }
  385. }
  386. // run the tests
  387. LLTestCallback* mycallback;
  388. if (getenv("TEAMCITY_PROJECT_NAME"))
  389. {
  390. mycallback = new LLTCTestCallback(verbose_mode, output);
  391. }
  392. else
  393. {
  394. mycallback = new LLTestCallback(verbose_mode, output);
  395. }
  396. tut::runner.get().set_callback(mycallback);
  397. if(test_group.empty())
  398. {
  399. tut::runner.get().run_tests();
  400. }
  401. else
  402. {
  403. tut::runner.get().run_tests(test_group);
  404. }
  405. bool success = (mycallback->getFailedTests() == 0);
  406. if (wait_at_exit)
  407. {
  408. std::cerr << "Press return to exit..." << std::endl;
  409. std::cin.get();
  410. }
  411. if (output)
  412. {
  413. output->close();
  414. delete output;
  415. }
  416. if (touch && success)
  417. {
  418. std::ofstream s;
  419. s.open(touch);
  420. s << "ok" << std::endl;
  421. s.close();
  422. }
  423. apr_terminate();
  424. int retval = (success ? 0 : 1);
  425. return retval;
  426. //delete mycallback;
  427. }