TestSuite.C

Go to the documentation of this file.
00001 /*!@file TestSuite/TestSuite.C Class to manage a suite of tests */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00005 // University of Southern California (USC) and the iLab at USC.         //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Rob Peters <rjpeters@klab.caltech.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/TestSuite/TestSuite.C $
00035 // $Id: TestSuite.C 10854 2009-02-14 05:09:44Z mundhenk $
00036 //
00037 
00038 #ifndef TESTSUITE_C_DEFINED
00039 #define TESTSUITE_C_DEFINED
00040 
00041 #include "TestSuite/TestSuite.H"
00042 
00043 #include "Image/IO.H"
00044 #include "Image/Image.H"
00045 #include "Image/MathOps.H"
00046 #include "Image/Pixels.H"
00047 #include "rutz/prof.h"
00048 
00049 #include <iomanip>
00050 #include <iostream>
00051 #include <sstream>
00052 #include <string>
00053 #include <vector>
00054 
00055 ///////////////////////////////////////////////////////////////////////
00056 /*
00057  *
00058  * TestData helper struct just pairs a TestFunc with its name.
00059  *
00060  */
00061 ///////////////////////////////////////////////////////////////////////
00062 
00063 struct TestData
00064 {
00065   TestData(const std::string& n, TestFunc f) : name(n), func(f) {}
00066 
00067   std::string name;
00068   TestFunc func;
00069 };
00070 
00071 ///////////////////////////////////////////////////////////////////////
00072 /*
00073  *
00074  * TestSuite::Impl holds all the member variables that TestSuite
00075  * needs. However, by putting them in a private struct and having TestSuite
00076  * just store a pointer to that struct, the header file just needs to see a
00077  * forward declaration of the struct, and does NOT have to #include <vector>,
00078  * <sstream>, etc.
00079  *
00080  */
00081 ///////////////////////////////////////////////////////////////////////
00082 
00083 struct TestSuite::Impl
00084 {
00085   Impl() : itsTests(), itsSuccess(true), itsOutput() {}
00086 
00087   std::vector<TestData> itsTests;
00088   bool                  itsSuccess;
00089   std::ostringstream    itsOutput;
00090 
00091   void printResult()
00092   {
00093     std::cout << itsSuccess << "\n"
00094               << itsOutput.str() << "\n";
00095   }
00096 
00097   template <class T>
00098   bool requireScalarEq(const T& expr, const T& expected,
00099                        const char* srcfile, int line, const char* expr_str)
00100   {
00101     const bool ok = (expr == expected);
00102     if ( !ok )
00103       {
00104         itsSuccess = false;
00105         itsOutput << "\tFAILED @ " << srcfile << ":" << line << ": "
00106                   << expr_str << ", "
00107                   << "expected '"
00108                   << std::setprecision(30) << std::showpoint << expected
00109                   << "', got '"
00110                   << std::setprecision(30) << std::showpoint << expr
00111                   << "'\n";
00112       }
00113     return ok;
00114   }
00115 
00116   template <class T>
00117   bool requireImgEq(const Image<T>& expr, const Image<T>& expected,
00118                     const char* srcfile, int line, const char* expr_str)
00119   {
00120     const bool ok = (expr == expected);
00121     if ( !ok )
00122       {
00123         itsSuccess = false;
00124         itsOutput << "\tFAILED @ " << srcfile << ":" << line << ": "
00125                   << expr_str << ", "
00126                   << "expected (" << convertToString(expected.getDims()) << ") "
00127                   << expected << ", "
00128                   << "got (" << convertToString(expr.getDims()) << ") "
00129                   << expr << "\n";
00130       }
00131     return ok;
00132   }
00133 
00134   bool requireImgEqFp(const Image<float>& expr, const Image<float>& expected,
00135                       const float prec, const char* srcfile, int line,
00136                       const char* expr_str)
00137   {
00138     bool ok = false;
00139     std::ostringstream extrainfo;
00140 
00141     if (expr.getDims() == expected.getDims())
00142       {
00143         Image<float> diff = abs(expr - expected);
00144         float ma; Point2D<int> loc;
00145         findMax(diff, loc, ma);
00146 
00147         ok = (ma <= prec);
00148 
00149         extrainfo << "(largest difference of " << ma << " at [x="
00150                   << loc.i << ",y=" << loc.j << "])\n";
00151       }
00152 
00153     if ( !ok )
00154       {
00155         itsSuccess = false;
00156         itsOutput << "\tFAILED @ " << srcfile << ":" << line << ": "
00157                   << expr_str << ", "
00158                   << "expected (" << convertToString(expected.getDims()) << ") "
00159                   << expected << ", "
00160                   << "got (" << convertToString(expr.getDims()) << ") "
00161                   << expr << "\n"
00162                   << extrainfo.str();
00163       }
00164     return ok;
00165   }
00166 
00167   bool requireEqUserTypeImpl(const bool ok,
00168                              const std::string& expr,
00169                              const std::string& expected,
00170                              const char* srcfile, int line,
00171                              const char* expr_str)
00172 
00173   {
00174     if ( !ok )
00175       {
00176         itsSuccess = false;
00177         itsOutput << "\tFAILED @ " << srcfile << ":" << line << ": "
00178                   << expr_str << ", "
00179                   << "expected '"
00180                   << expected
00181                   << "', got '"
00182                   << expr
00183                   << "'\n";
00184       }
00185     return ok;
00186   }
00187 
00188   template <class T>
00189   static bool compare(const T& lhs, Op op, const T& rhs)
00190   {
00191     switch (op)
00192       {
00193       case EQ:  return lhs == rhs;
00194       case NEQ: return lhs != rhs;
00195       case LT:  return lhs <  rhs;
00196       case LTE: return lhs <= rhs;
00197       case GT:  return lhs >  rhs;
00198       case GTE: return lhs >= rhs;
00199       }
00200     LFATAL("invalid Op '%d'", int(op));
00201     return false; // "can't happen"
00202   }
00203 
00204   static const char* opname(Op op)
00205   {
00206     switch (op)
00207       {
00208       case EQ:  return " == ";
00209       case NEQ: return " != ";
00210       case LT:  return " < ";
00211       case LTE: return " <= ";
00212       case GT:  return " > ";
00213       case GTE: return " >= ";
00214       }
00215     LFATAL("invalid Op '%d'", int(op));
00216     return ""; // "can't happen"
00217   }
00218 
00219   template <class T>
00220   bool require(const T& lhs, Op op, const T& rhs,
00221                const char* srcfile, int line,
00222                const char* lhs_str, const char* rhs_str)
00223   {
00224     const bool ok = compare(lhs, op, rhs);
00225     if ( !ok )
00226       {
00227         itsSuccess = false;
00228         itsOutput << "\tFAILED @ " << srcfile << ":" << line << ":\n"
00229                   << "\t expected " << lhs_str << opname(op) << rhs_str << ",\n "
00230                   << "\t got " << lhs_str << "==" << lhs
00231                   << " and " << rhs_str << "==" << rhs << '\n';
00232       }
00233     return ok;
00234   }
00235 };
00236 
00237 ///////////////////////////////////////////////////////////////////////
00238 //
00239 // TestSuite member function definitions
00240 //
00241 ///////////////////////////////////////////////////////////////////////
00242 
00243 
00244 // ######################################################################
00245 TestSuite::TestSuite() :
00246   rep(new Impl)
00247 {}
00248 
00249 // ######################################################################
00250 TestSuite::~TestSuite()
00251 {
00252   delete rep;
00253 }
00254 
00255 // ######################################################################
00256 void TestSuite::addTest(const char* name, TestFunc func)
00257 {
00258   rep->itsTests.push_back(TestData(name, func));
00259 }
00260 
00261 // ######################################################################
00262 void TestSuite::printAvailableTests() const
00263 {
00264   for (unsigned int i = 0; i < rep->itsTests.size(); ++i)
00265     std::cout << '{' << i << '\t' << rep->itsTests[i].name << "}\n";
00266 }
00267 
00268 // ######################################################################
00269 void TestSuite::printAvailableTestsForPerl() const
00270 {
00271   for (unsigned int i = 0; i < rep->itsTests.size(); ++i)
00272     std::cout << i << '\t' << rep->itsTests[i].name << "\n";
00273 }
00274 
00275 // ######################################################################
00276 void TestSuite::runTest(int test_n, int repeat_n)
00277 {
00278   if (test_n < 0 || (unsigned int) test_n >= rep->itsTests.size())
00279     return;
00280 
00281   for (int i = 0; i < repeat_n; ++i)
00282     rep->itsTests.at(test_n).func(*this);
00283 
00284   rep->printResult();
00285 }
00286 
00287 // ######################################################################
00288 namespace
00289 {
00290   void showUsageAndExit(const char* argv0)
00291   {
00292     std::cerr << "usage: " << argv0 << " <options>\n"
00293               << "available options:\n"
00294               << "\t--query        print test names and number (for tcl)\n"
00295               << "\t--perlquery    print test names and number (for perl)\n"
00296               << "\t--run <n>      run the test number <n>\n"
00297               << "\t--repeat <n>   repeat the test <n> times (for profiling, etc.)\n"
00298               << "\t--dump-prof    print a profiling summary before exit\n";
00299 
00300     exit(1);
00301   }
00302 }
00303 
00304 // ######################################################################
00305 void TestSuite::parseAndRun(int argc, const char** argv)
00306 {
00307   if (argc == 1)
00308     {
00309       showUsageAndExit(argv[0]);
00310     }
00311 
00312   int test_n = -1;
00313   int repeat_n = 1;
00314   bool dump_prof = false;
00315 
00316   for (int i = 1; i < argc; ++i)
00317     {
00318       if (strcmp(argv[i], "--run") == 0)
00319         {
00320           if (++i < argc) test_n = atoi(argv[i]);
00321         }
00322 
00323       else if (strcmp(argv[i], "--repeat") == 0)
00324         {
00325           if (++i < argc) repeat_n = atoi(argv[i]);
00326         }
00327 
00328       else if (strcmp(argv[i], "--query") == 0)
00329         {
00330           printAvailableTests();
00331           return;
00332         }
00333 
00334       else if (strcmp(argv[i], "--perlquery") == 0)
00335         {
00336           printAvailableTestsForPerl();
00337           return;
00338         }
00339 
00340       else if (strcmp(argv[i], "--dump-prof") == 0)
00341         {
00342           dump_prof = true;
00343         }
00344 
00345       else
00346         {
00347           showUsageAndExit(argv[0]);
00348         }
00349     }
00350 
00351   runTest(test_n, repeat_n);
00352 
00353   if (dump_prof)
00354     rutz::prof::print_all_prof_data(std::cerr);
00355 }
00356 
00357 // ######################################################################
00358 bool TestSuite::require(bool expr, const char* srcfile, int line, const char* expr_str)
00359 {
00360   if (!expr)
00361     {
00362       rep->itsSuccess = false;
00363       rep->itsOutput << "\tFAILED @ " << srcfile << ":" << line << ": "
00364                      << expr_str << "\n";
00365     }
00366   return expr;
00367 }
00368 
00369 // ######################################################################
00370 bool TestSuite::requireEq(int expr, int expected,
00371                           const char* srcfile, int line, const char* expr_str)
00372 { return rep->requireScalarEq(expr, expected, srcfile, line, expr_str); }
00373 
00374 // ######################################################################
00375 bool TestSuite::requireEq(uint expr, uint expected,
00376                           const char* srcfile, int line, const char* expr_str)
00377 { return rep->requireScalarEq(expr, expected, srcfile, line, expr_str); }
00378 
00379 // ######################################################################
00380 bool TestSuite::requireEq(long expr, long expected,
00381                           const char* srcfile, int line, const char* expr_str)
00382 { return rep->requireScalarEq(expr, expected, srcfile, line, expr_str); }
00383 
00384 // ######################################################################
00385 bool TestSuite::requireEq(unsigned long expr, unsigned long expected,
00386                           const char* srcfile, int line, const char* expr_str)
00387 { return rep->requireScalarEq(expr, expected, srcfile, line, expr_str); }
00388 
00389 // ######################################################################
00390 bool TestSuite::requireEq(double expr, double expected,
00391                           const char* srcfile, int line, const char* expr_str)
00392 { return rep->requireScalarEq(expr, expected, srcfile, line, expr_str); }
00393 
00394 // ######################################################################
00395 bool TestSuite::requireEq(const std::string& expr, const std::string& expected,
00396                           const char* srcfile, int line, const char* expr_str)
00397 { return rep->requireScalarEq(expr, expected, srcfile, line, expr_str); }
00398 
00399 // ######################################################################
00400 template <class T>
00401 bool TestSuite::requireEq(const Image<T>& expr, const Image<T>& expected,
00402                           const char* srcfile, int line, const char* expr_str)
00403 { return rep->requireImgEq(expr, expected, srcfile, line, expr_str); }
00404 
00405 // ######################################################################
00406 bool TestSuite::requireEq(const Image<float>& expr,
00407                           const Image<float>& expected,
00408                           const float prec, const char* srcfile, int line,
00409                           const char* expr_str)
00410 { return rep->requireImgEqFp(expr, expected, prec, srcfile, line, expr_str); }
00411 
00412 // ######################################################################
00413 bool TestSuite::require(int lhs, Op op, int rhs,
00414                         const char* srcfile, int line,
00415                         const char* lhs_str, const char* rhs_str)
00416 { return rep->require(lhs, op, rhs, srcfile, line, lhs_str, rhs_str); }
00417 
00418 // ######################################################################
00419 bool TestSuite::require(long lhs, Op op, long rhs,
00420                         const char* srcfile, int line,
00421                         const char* lhs_str, const char* rhs_str)
00422 { return rep->require(lhs, op, rhs, srcfile, line, lhs_str, rhs_str); }
00423 
00424 // ######################################################################
00425 bool TestSuite::require(double lhs, Op op, double rhs,
00426                         const char* srcfile, int line,
00427                         const char* lhs_str, const char* rhs_str)
00428 { return rep->require(lhs, op, rhs, srcfile, line, lhs_str, rhs_str); }
00429 
00430 // ######################################################################
00431 bool TestSuite::requireEqUserTypeImpl(const bool ok,
00432                                       const std::string& expr,
00433                                       const std::string& expected,
00434                                       const char* srcfile, int line,
00435                                       const char* expr_str)
00436 { return rep->requireEqUserTypeImpl(ok, expr, expected, srcfile, line, expr_str); }
00437 
00438 // Include the explicit instantiations, and make sure that they go in the
00439 // TestSuite:: namespace
00440 #define INST_CLASS TestSuite::
00441 #include "inst/TestSuite/TestSuite.I"
00442 
00443 template bool INST_CLASS requireEq(const Image<int>& expr, const Image<int>& expected, const char* srcfile, int line, const char* expr_str);
00444 
00445 /* So things look consistent in everyone's emacs... */
00446 /* Local Variables: */
00447 /* indent-tabs-mode: nil */
00448 /* End: */
00449 
00450 #endif // !TESTSUITE_C_DEFINED
Generated on Sun May 8 08:06:55 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3