Generated on Tue Apr 18 10:22:19 2017 for Gecode by doxygen 1.6.3

test.cpp

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Christian Schulte <schulte@gecode.org>
00005  *     Mikael Lagerkvist <lagerkvist@gecode.org>
00006  *
00007  *  Copyright:
00008  *     Christian Schulte, 2004
00009  *     Mikael Lagerkvist, 2005
00010  *
00011  *  Last modified:
00012  *     $Date: 2016-10-25 12:52:26 +0200 (Tue, 25 Oct 2016) $ by $Author: schulte $
00013  *     $Revision: 15233 $
00014  *
00015  *  This file is part of Gecode, the generic constraint
00016  *  development environment:
00017  *     http://www.gecode.org
00018  *
00019  *  Permission is hereby granted, free of charge, to any person obtaining
00020  *  a copy of this software and associated documentation files (the
00021  *  "Software"), to deal in the Software without restriction, including
00022  *  without limitation the rights to use, copy, modify, merge, publish,
00023  *  distribute, sublicense, and/or sell copies of the Software, and to
00024  *  permit persons to whom the Software is furnished to do so, subject to
00025  *  the following conditions:
00026  *
00027  *  The above copyright notice and this permission notice shall be
00028  *  included in all copies or substantial portions of the Software.
00029  *
00030  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00031  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00032  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00033  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00034  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00035  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00036  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00037  *
00038  */
00039 
00040 #include "test/test.hh"
00041 
00042 #ifdef GECODE_HAS_MTRACE
00043 #include <mcheck.h>
00044 #endif
00045 
00046 #include <iostream>
00047 
00048 #include <cstdlib>
00049 #include <cstring>
00050 #include <ctime>
00051 #include <vector>
00052 #include <utility>
00053 
00054 namespace Test {
00055 
00056   // Log stream
00057   std::ostringstream olog;
00058 
00059   /*
00060    * Base class for tests
00061    *
00062    */
00063   Base::Base(const std::string& s)
00064     : _name(s), _next(_tests) {
00065     _tests = this; _n_tests++;
00066   }
00067 
00068   Base* Base::_tests = NULL;
00069   unsigned int Base::_n_tests = 0;
00070 
00072   class SortByName {
00073   public:
00074     forceinline bool
00075     operator()(Base* x, Base* y) {
00076       return x->name() > y->name();
00077     }
00078   };
00079 
00080   void
00081   Base::sort(void) {
00082     Base** b = Gecode::heap.alloc<Base*>(_n_tests);
00083     unsigned int i=0;
00084     for (Base* t = _tests; t != NULL; t = t->next())
00085       b[i++] = t;
00086     SortByName sbn;
00087     Gecode::Support::quicksort(b,_n_tests,sbn);
00088     i=0;
00089     _tests = NULL;
00090     for ( ; i < _n_tests; i++) {
00091       b[i]->next(_tests); _tests = b[i];
00092     }
00093     Gecode::heap.free(b,_n_tests);
00094   }
00095 
00096   Base::~Base(void) {}
00097 
00098   Gecode::Support::RandomGenerator Base::rand
00099   = Gecode::Support::RandomGenerator();
00100 
00101   Options opt;
00102 
00103   void report_error(std::string name) {
00104     std::cout << "Options: -seed " << opt.seed;
00105     if (opt.fixprob != opt.deffixprob)
00106       std::cout << " -fixprob " << opt.fixprob;
00107     std::cout << " -test " << name << std::endl;
00108     if (opt.log)
00109       std::cout << olog.str();
00110   }
00111 
00113   enum MatchType {
00114     MT_ANY,  //< Positive match anywhere in string
00115     MT_NOT,  //< Negative match
00116     MT_FIRST //< Positive match at beginning
00117   };
00118 
00119   std::vector<std::pair<MatchType, const char*> > testpat;
00120   const char* startFrom = NULL;
00121   bool list = false;
00122 
00123   void
00124   Options::parse(int argc, char* argv[]) {
00125     int i = 1;
00126     while (i < argc) {
00127       if (!strcmp(argv[i],"-help") || !strcmp(argv[i],"--help")) {
00128         std::cerr << "Options for testing:" << std::endl
00129                   << "\t-seed (unsigned int or \"time\") default: "
00130                   << seed << std::endl
00131                   << "\t\tseed for random number generator (unsigned int),"
00132                   << std::endl
00133                   << "\t\tor \"time\" for a random seed based on "
00134                   << "current time" << std::endl
00135                   << "\t-fixprob (unsigned int) default: "
00136                   << fixprob << std::endl
00137                   << "\t\t1/fixprob is the probability of computing a fixpoint"
00138                   << std::endl
00139                   << "\t-iter (unsigned int) default: " <<iter<< std::endl
00140                   << "\t\tthe number of iterations" << std::endl
00141                   << "\t-test (string) default: (none)" << std::endl
00142                   << "\t\tsimple pattern for the tests to run" << std::endl
00143                   << "\t\tprefixing with \"-\" negates the pattern" << std::endl
00144                   << "\t\tprefixing with \"^\" requires a match at the beginning" << std::endl
00145                   << "\t\tmultiple pattern-options may be given"
00146                   << std::endl
00147                   << "\t-start (string) default: (none)" << std::endl
00148                   << "\t\tsimple pattern for the first test to run" << std::endl
00149                   << "\t-log"
00150                   << std::endl
00151                   << "\t\tlog execution of tests"
00152                   << std::endl
00153                   << "\t\tthe optional argument determines the style of the log"
00154                   << std::endl
00155                   << "\t\twith text as the default style"
00156                   << std::endl
00157                   << "\t-stop (boolean) default: "
00158                   << (stop ? "true" : "false") << std::endl
00159                   << "\t\tstop on first error or continue" << std::endl
00160                   << "\t-list" << std::endl
00161                   << "\t\toutput list of all test cases and exit" << std::endl
00162           ;
00163         exit(EXIT_SUCCESS);
00164       } else if (!strcmp(argv[i],"-seed")) {
00165         if (++i == argc) goto missing;
00166         if (!strcmp(argv[i],"time")) {
00167           seed = static_cast<unsigned int>(time(NULL));
00168         } else {
00169           seed = static_cast<unsigned int>(atoi(argv[i]));
00170         }
00171       } else if (!strcmp(argv[i],"-iter")) {
00172         if (++i == argc) goto missing;
00173         iter = static_cast<unsigned int>(atoi(argv[i]));
00174       } else if (!strcmp(argv[i],"-fixprob")) {
00175         if (++i == argc) goto missing;
00176         fixprob = static_cast<unsigned int>(atoi(argv[i]));
00177       } else if (!strcmp(argv[i],"-test")) {
00178         if (++i == argc) goto missing;
00179         if (argv[i][0] == '^')
00180           testpat.push_back(std::make_pair(MT_FIRST, argv[i] + 1));
00181         else if (argv[i][0] == '-')
00182           testpat.push_back(std::make_pair(MT_NOT, argv[i] + 1));
00183         else
00184           testpat.push_back(std::make_pair(MT_ANY, argv[i]));
00185       } else if (!strcmp(argv[i],"-start")) {
00186         if (++i == argc) goto missing;
00187         startFrom = argv[i];
00188       } else if (!strcmp(argv[i],"-log")) {
00189         log = true;
00190       } else if (!strcmp(argv[i],"-stop")) {
00191         if (++i == argc) goto missing;
00192         if(argv[i][0] == 't') {
00193           stop = true;
00194         } else if (argv[i][0] == 'f') {
00195           stop = false;
00196         }
00197       } else if (!strcmp(argv[i],"-list")) {
00198         list = true;
00199       }
00200       i++;
00201     }
00202     return;
00203   missing:
00204     std::cerr << "Erroneous argument (" << argv[i-1] << ")" << std::endl
00205               << "  missing parameter" << std::endl;
00206     exit(EXIT_FAILURE);
00207   }
00208 
00209 }
00210 
00211 int
00212 main(int argc, char* argv[]) {
00213   using namespace Test;
00214 #ifdef GECODE_HAS_MTRACE
00215   mtrace();
00216 #endif
00217 
00218   opt.parse(argc, argv);
00219 
00220   Base::sort();
00221 
00222   if (list) {
00223     for (Base* t = Base::tests() ; t != NULL; t = t->next() ) {
00224       std::cout << t->name() << std::endl;
00225     }
00226     exit(EXIT_SUCCESS);
00227   }
00228 
00229   Base::rand.seed(opt.seed);
00230 
00231   bool started = startFrom == NULL ? true : false;
00232 
00233   for (Base* t = Base::tests() ; t != NULL; t = t->next() ) {
00234     try {
00235       if (!started) {
00236         if (t->name().find(startFrom) != std::string::npos)
00237           started = true;
00238         else
00239           goto next;
00240       }
00241       if (testpat.size() != 0) {
00242         bool match_found   = false;
00243         bool some_positive = false;
00244         for (unsigned int i = 0; i < testpat.size(); ++i) {
00245           if (testpat[i].first == MT_NOT) { // Negative pattern
00246             if (t->name().find(testpat[i].second) != std::string::npos)
00247               goto next;
00248           } else {               // Positive pattern
00249             some_positive = true;
00250             if (((testpat[i].first == MT_ANY) &&
00251                  (t->name().find(testpat[i].second) != std::string::npos)) ||
00252                 ((testpat[i].first == MT_FIRST) &&
00253                  (t->name().find(testpat[i].second) == 0)))
00254               match_found = true;
00255           }
00256         }
00257         if (some_positive && !match_found) goto next;
00258       }
00259       std::cout << t->name() << " ";
00260       std::cout.flush();
00261       for (unsigned int i = opt.iter; i--; ) {
00262         opt.seed = Base::rand.seed();
00263         if (t->run()) {
00264           std::cout << '+';
00265           std::cout.flush();
00266         } else {
00267           std::cout << "-" << std::endl;
00268           report_error(t->name());
00269           if (opt.stop)
00270             return 1;
00271         }
00272       }
00273     std::cout << std::endl;
00274     } catch (Gecode::Exception e) {
00275       std::cout << "Exception in \"Gecode::" << e.what()
00276                 << "." << std::endl
00277                 << "Stopping..." << std::endl;
00278       report_error(t->name());
00279       if (opt.stop)
00280         return 1;
00281     }
00282   next:;
00283   }
00284   return 0;
00285 }
00286 
00287 std::ostream&
00288 operator<<(std::ostream& os, const Test::ind& i) {
00289   for (int j=i.l; j--; )
00290     os << "  ";
00291   return os;
00292 }
00293 
00294 // STATISTICS: test-core