00001
00042 #include "linden_common.h"
00043 #include "llerrorcontrol.h"
00044 #include "lltut.h"
00045
00046 #include <apr-1/apr_pools.h>
00047 #include <apr-1/apr_getopt.h>
00048
00049
00050
00051
00052 #ifdef CTYPE_WORKAROUND
00053 # include "ctype_workaround.h"
00054 #endif
00055
00056
00057 namespace tut
00058 {
00059 test_runner_singleton runner;
00060 }
00061
00062 class LLTestCallback : public tut::callback
00063 {
00064 public:
00065 LLTestCallback(bool verbose_mode) :
00066 mVerboseMode(verbose_mode),
00067 mTotalTests(0),
00068 mPassedTests(0),
00069 mFailedTests(0),
00070 mSkippedTests(0),
00071 mSkipedFailTests(0)
00072 {
00073 }
00074
00075 void run_started()
00076 {
00077
00078 }
00079
00080 void test_completed(const tut::test_result& tr)
00081 {
00082 ++mTotalTests;
00083 std::ostringstream out;
00084 out << "[" << tr.group << ", " << tr.test << "] ";
00085 switch(tr.result)
00086 {
00087 case tut::test_result::ok:
00088 ++mPassedTests;
00089 out << "ok";
00090 break;
00091 case tut::test_result::fail:
00092 ++mFailedTests;
00093 out << "fail";
00094 break;
00095 case tut::test_result::ex:
00096 ++mFailedTests;
00097 out << "exception";
00098 break;
00099 case tut::test_result::warn:
00100 ++mFailedTests;
00101 out << "test destructor throw";
00102 break;
00103 case tut::test_result::term:
00104 ++mFailedTests;
00105 out << "abnormal termination";
00106 break;
00107 case tut::test_result::skip:
00108 ++mSkippedTests;
00109 out << "skipped";
00110 break;
00111 case tut::test_result::skip_fail:
00112 ++mSkipedFailTests;
00113 out << "skipped known failure";
00114 break;
00115 default:
00116 ++mFailedTests;
00117 out << "unknown";
00118 }
00119 if(mVerboseMode || (tr.result != tut::test_result::ok))
00120 {
00121 if(!tr.message.empty())
00122 {
00123 out << ": '" << tr.message << "'";
00124 }
00125 std::cout << out.str() << std::endl;
00126 }
00127 }
00128
00129 void run_completed()
00130 {
00131 std::cout << std::endl;
00132 std::cout << "Total Tests: " << mTotalTests << std::endl;
00133 std::cout << "Passed Tests: " << mPassedTests << std::endl;
00134
00135 if (mSkippedTests > 0)
00136 {
00137 std::cout << "Skipped Tests: " << mSkippedTests << std::endl;
00138 }
00139
00140 if (mSkipedFailTests > 0)
00141 {
00142 std::cout << "Skipped known failures: " << mSkipedFailTests
00143 << std::endl;
00144 }
00145
00146 if(mFailedTests > 0)
00147 {
00148 std::cout << "*********************************" << std::endl;
00149 std::cout << "Failed Tests: " << mFailedTests << std::endl;
00150 std::cout << "Please report or fix the problem." << std::endl;
00151 std::cout << "*********************************" << std::endl;
00152 exit(1);
00153 }
00154 }
00155
00156 protected:
00157 bool mVerboseMode;
00158 int mTotalTests;
00159 int mPassedTests;
00160 int mFailedTests;
00161 int mSkippedTests;
00162 int mSkipedFailTests;
00163 };
00164
00165 static const apr_getopt_option_t TEST_CL_OPTIONS[] =
00166 {
00167 {"help", 'h', 0, "Print the help message."},
00168 {"list", 'l', 0, "List available test groups."},
00169 {"verbose", 'v', 0, "Verbose output."},
00170 {"group", 'g', 1, "Run test group specified by option argument."},
00171 {"skip", 's', 1, "Skip test number specified by option argument. Only works when a specific group is being tested"},
00172 {"wait", 'w', 0, "Wait for input before exit."},
00173 {0, 0, 0, 0}
00174 };
00175
00176 void stream_usage(std::ostream& s, const char* app)
00177 {
00178 s << "Usage: " << app << " [OPTIONS]" << std::endl
00179 << std::endl;
00180
00181 s << "This application runs the unit tests." << std::endl << std::endl;
00182
00183 s << "Options: " << std::endl;
00184 const apr_getopt_option_t* option = &TEST_CL_OPTIONS[0];
00185 while(option->name)
00186 {
00187 s << " ";
00188 s << " -" << (char)option->optch << ", --" << option->name
00189 << std::endl;
00190 s << "\t" << option->description << std::endl << std::endl;
00191 ++option;
00192 }
00193
00194 s << "Examples:" << std::endl;
00195 s << " " << app << " --verbose" << std::endl;
00196 s << "\tRun all the tests and report all results." << std::endl;
00197 s << " " << app << " --list" << std::endl;
00198 s << "\tList all available test groups." << std::endl;
00199 s << " " << app << " --group=uuid" << std::endl;
00200 s << "\tRun the test group 'uuid'." << std::endl;
00201 s << " " << app << " --skip=2" << std::endl;
00202 s << "\tSkip test case 2." << std::endl;
00203 }
00204
00205 void stream_groups(std::ostream& s, const char* app)
00206 {
00207 s << "Registered test groups:" << std::endl;
00208 tut::groupnames gl = tut::runner.get().list_groups();
00209 tut::groupnames::const_iterator it = gl.begin();
00210 tut::groupnames::const_iterator end = gl.end();
00211 for(; it != end; ++it)
00212 {
00213 s << " " << *(it) << std::endl;
00214 }
00215 }
00216
00217 void wouldHaveCrashed(const std::string& message)
00218 {
00219 tut::fail("llerrs message: " + message);
00220 }
00221
00222 int main(int argc, char **argv)
00223 {
00224 LLError::initForApplication(".");
00225 LLError::setFatalFunction(wouldHaveCrashed);
00226 LLError::setDefaultLevel(LLError::LEVEL_ERROR);
00227
00228
00229 #ifdef CTYPE_WORKAROUND
00230 ctype_workaround();
00231 #endif
00232
00233 apr_initialize();
00234 apr_pool_t* pool = NULL;
00235 if(APR_SUCCESS != apr_pool_create(&pool, NULL))
00236 {
00237 std::cerr << "Unable to initialize pool" << std::endl;
00238 return 1;
00239 }
00240 apr_getopt_t* os = NULL;
00241 if(APR_SUCCESS != apr_getopt_init(&os, pool, argc, argv))
00242 {
00243 std::cerr << "Unable to pool" << std::endl;
00244 return 1;
00245 }
00246
00247
00248 bool verbose_mode = false;
00249 bool wait_at_exit = false;
00250 int skip_test_id = 0;
00251 std::string test_group;
00252
00253
00254 apr_status_t apr_err;
00255 const char* opt_arg = NULL;
00256 int opt_id = 0;
00257 while(true)
00258 {
00259 apr_err = apr_getopt_long(os, TEST_CL_OPTIONS, &opt_id, &opt_arg);
00260 if(APR_STATUS_IS_EOF(apr_err)) break;
00261 if(apr_err)
00262 {
00263 char buf[255];
00264 std::cerr << "Error parsing options: "
00265 << apr_strerror(apr_err, buf, 255) << std::endl;
00266 return 1;
00267 }
00268 switch (opt_id)
00269 {
00270 case 'g':
00271 test_group.assign(opt_arg);
00272 break;
00273 case 's':
00274 skip_test_id = atoi(opt_arg);
00275 break;
00276 case 'h':
00277 stream_usage(std::cout, argv[0]);
00278 return 0;
00279 break;
00280 case 'l':
00281 stream_groups(std::cout, argv[0]);
00282 return 0;
00283 case 'v':
00284 verbose_mode = true;
00285 break;
00286 case 'w':
00287 wait_at_exit = true;
00288 break;
00289 default:
00290 stream_usage(std::cerr, argv[0]);
00291 return 1;
00292 break;
00293 }
00294 }
00295
00296
00297 LLTestCallback callback(verbose_mode);
00298 tut::runner.get().set_callback(&callback);
00299
00300 if(test_group.empty())
00301 {
00302 tut::runner.get().run_tests();
00303 }
00304 else
00305 {
00306 tut::runner.get().run_tests(test_group, skip_test_id);
00307 }
00308
00309 if (wait_at_exit)
00310 {
00311 std::cerr << "Waiting for input before exiting..." << std::endl;
00312 std::cin.get();
00313 }
00314
00315 apr_terminate();
00316 return 0;
00317 }