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: 2009-02-04 13:25:42 +0100 (Wed, 04 Feb 2009) $ by $Author: schulte $ 00013 * $Revision: 8138 $ 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 00112 std::vector<std::pair<bool, const char*> > testpat; 00113 const char* startFrom = NULL; 00114 bool list = false; 00115 00116 void 00117 Options::parse(int argc, char* argv[]) { 00118 int i = 1; 00119 while (i < argc) { 00120 if (!strcmp(argv[i],"-help") || !strcmp(argv[i],"--help")) { 00121 std::cerr << "Options for testing:" << std::endl 00122 << "\t-seed (unsigned int or \"time\") default: " 00123 << seed << std::endl 00124 << "\t\tseed for random number generator (unsigned int)," 00125 << std::endl 00126 << "\t\tor \"time\" for a random seed based on " 00127 << "current time" << std::endl 00128 << "\t-fixprob (unsigned int) default: " 00129 << fixprob << std::endl 00130 << "\t\t1/fixprob is the probability of computing a fixpoint" 00131 << std::endl 00132 << "\t-iter (unsigned int) default: " <<iter<< std::endl 00133 << "\t\tthe number of iterations" << std::endl 00134 << "\t-test (string) default: (none)" << std::endl 00135 << "\t\tsimple pattern for the tests to run" << std::endl 00136 << "\t\tprefixing the pattern with \"-\" negates the pattern" 00137 << std::endl 00138 << "\t\tmultiple pattern-options may be given" << std::endl 00139 << "\t-start (string) default: (none)" << std::endl 00140 << "\t\tsimple pattern for the first test to run" << std::endl 00141 << "\t-log" 00142 << std::endl 00143 << "\t\tlog execution of tests" 00144 << std::endl 00145 << "\t\tthe optional argument determines the style of the log" 00146 << std::endl 00147 << "\t\twith text as the default style" 00148 << std::endl 00149 << "\t-stop (boolean) default: " 00150 << (stop ? "true" : "false") << std::endl 00151 << "\t\tstop on first error or continue" << std::endl 00152 << "\t-list" << std::endl 00153 << "\t\toutput list of all test cases and exit" << std::endl 00154 ; 00155 exit(EXIT_SUCCESS); 00156 } else if (!strcmp(argv[i],"-seed")) { 00157 if (++i == argc) goto missing; 00158 if (!strcmp(argv[i],"time")) { 00159 seed = static_cast<unsigned int>(time(NULL)); 00160 } else { 00161 seed = static_cast<unsigned int>(atoi(argv[i])); 00162 } 00163 } else if (!strcmp(argv[i],"-iter")) { 00164 if (++i == argc) goto missing; 00165 iter = static_cast<unsigned int>(atoi(argv[i])); 00166 } else if (!strcmp(argv[i],"-fixprob")) { 00167 if (++i == argc) goto missing; 00168 fixprob = static_cast<unsigned int>(atoi(argv[i])); 00169 } else if (!strcmp(argv[i],"-test")) { 00170 if (++i == argc) goto missing; 00171 if (argv[i][0] == '-') 00172 testpat.push_back(std::make_pair(true, argv[i] + 1)); 00173 else 00174 testpat.push_back(std::make_pair(false, argv[i])); 00175 } else if (!strcmp(argv[i],"-start")) { 00176 if (++i == argc) goto missing; 00177 startFrom = argv[i]; 00178 } else if (!strcmp(argv[i],"-log")) { 00179 log = true; 00180 } else if (!strcmp(argv[i],"-stop")) { 00181 if (++i == argc) goto missing; 00182 if(argv[i][0] == 't') { 00183 stop = true; 00184 } else if (argv[i][0] == 'f') { 00185 stop = false; 00186 } 00187 } else if (!strcmp(argv[i],"-list")) { 00188 list = true; 00189 } 00190 i++; 00191 } 00192 return; 00193 missing: 00194 std::cerr << "Erroneous argument (" << argv[i-1] << ")" << std::endl 00195 << " missing parameter" << std::endl; 00196 exit(EXIT_FAILURE); 00197 } 00198 00199 } 00200 00201 int 00202 main(int argc, char* argv[]) { 00203 using namespace Test; 00204 #ifdef GECODE_HAS_MTRACE 00205 mtrace(); 00206 #endif 00207 00208 opt.parse(argc, argv); 00209 00210 Base::sort(); 00211 00212 if (list) { 00213 for (Base* t = Base::tests() ; t != NULL; t = t->next() ) { 00214 std::cout << t->name() << std::endl; 00215 } 00216 exit(EXIT_SUCCESS); 00217 } 00218 00219 Base::rand.seed(opt.seed); 00220 00221 bool started = startFrom == NULL ? true : false; 00222 00223 for (Base* t = Base::tests() ; t != NULL; t = t->next() ) { 00224 try { 00225 if (!started) { 00226 if (t->name().find(startFrom) != std::string::npos) 00227 started = true; 00228 else 00229 goto next; 00230 } 00231 if (testpat.size() != 0) { 00232 bool match_found = false; 00233 bool some_positive = false; 00234 for (unsigned int i = 0; i < testpat.size(); ++i) { 00235 if (testpat[i].first) { // Negative pattern 00236 if (t->name().find(testpat[i].second) != std::string::npos) 00237 goto next; 00238 } else { // Positive pattern 00239 some_positive = true; 00240 if (t->name().find(testpat[i].second) != std::string::npos) 00241 match_found = true; 00242 } 00243 } 00244 if (some_positive && !match_found) goto next; 00245 } 00246 std::cout << t->name() << " "; 00247 std::cout.flush(); 00248 for (unsigned int i = opt.iter; i--; ) { 00249 opt.seed = Base::rand.seed(); 00250 if (t->run()) { 00251 std::cout << '+'; 00252 std::cout.flush(); 00253 } else { 00254 std::cout << "-" << std::endl; 00255 report_error(t->name()); 00256 if (opt.stop) 00257 return 1; 00258 } 00259 } 00260 std::cout << std::endl; 00261 } catch (Gecode::Exception e) { 00262 std::cout << "Exception in \"Gecode::" << e.what() 00263 << "." << std::endl 00264 << "Stopping..." << std::endl; 00265 report_error(t->name()); 00266 if (opt.stop) 00267 return 1; 00268 } 00269 next:; 00270 } 00271 return 0; 00272 } 00273 00274 std::ostream& 00275 operator<<(std::ostream& os, const Test::ind& i) { 00276 for (int j=i.l; j--; ) 00277 os << " "; 00278 return os; 00279 } 00280 00281 // STATISTICS: test-core