this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2/* 3 * Main authors: 4 * Christian Schulte <schulte@gecode.org> 5 * Mikael Lagerkvist <lagerkvist@gecode.org> 6 * 7 * Copyright: 8 * Christian Schulte, 2004 9 * Mikael Lagerkvist, 2005 10 * 11 * This file is part of Gecode, the generic constraint 12 * development environment: 13 * http://www.gecode.org 14 * 15 * Permission is hereby granted, free of charge, to any person obtaining 16 * a copy of this software and associated documentation files (the 17 * "Software"), to deal in the Software without restriction, including 18 * without limitation the rights to use, copy, modify, merge, publish, 19 * distribute, sublicense, and/or sell copies of the Software, and to 20 * permit persons to whom the Software is furnished to do so, subject to 21 * the following conditions: 22 * 23 * The above copyright notice and this permission notice shall be 24 * included in all copies or substantial portions of the Software. 25 * 26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 30 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 31 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 32 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 33 * 34 */ 35 36#include "test/test.hh" 37 38#ifdef GECODE_HAS_MTRACE 39#include <mcheck.h> 40#endif 41 42#include <iostream> 43 44#include <cstdlib> 45#include <cstring> 46#include <ctime> 47#include <utility> 48#include <vector> 49#include <utility> 50 51namespace Test { 52 53 // Log stream 54 std::ostringstream olog; 55 56 /* 57 * Base class for tests 58 * 59 */ 60 Base::Base(std::string s) 61 : _name(std::move(s)), _next(_tests) { 62 _tests = this; _n_tests++; 63 } 64 65 Base* Base::_tests = nullptr; 66 unsigned int Base::_n_tests = 0; 67 68 /// Sort tests by name 69 class SortByName { 70 public: 71 forceinline bool 72 operator()(Base* x, Base* y) { 73 return x->name() > y->name(); 74 } 75 }; 76 77 void 78 Base::sort() { 79 Base** b = Gecode::heap.alloc<Base*>(_n_tests); 80 unsigned int i=0; 81 for (Base* t = _tests; t != nullptr; t = t->next()) 82 b[i++] = t; 83 SortByName sbn; 84 Gecode::Support::quicksort(b, _n_tests,sbn); 85 i=0; 86 _tests = nullptr; 87 for ( ; i < _n_tests; i++) { 88 b[i]->next(_tests); _tests = b[i]; 89 } 90 Gecode::heap.free(b,_n_tests); 91 } 92 93 Base::~Base() = default; 94 95 Gecode::Support::RandomGenerator Base::rand 96 = Gecode::Support::RandomGenerator(); 97 98 Options opt; 99 100 void report_error(const std::string& name) { 101 std::cout << "Options: -seed " << opt.seed; 102 if (opt.fixprob != Test::Options::deffixprob) 103 std::cout << " -fixprob " << opt.fixprob; 104 std::cout << " -test " << name << std::endl; 105 if (opt.log) 106 std::cout << olog.str(); 107 } 108 109 /// How to match 110 enum MatchType { 111 MT_ANY, //< Positive match anywhere in string 112 MT_NOT, //< Negative match 113 MT_FIRST //< Positive match at beginning 114 }; 115 116 std::vector<std::pair<MatchType, const char*> > testpat; 117 const char* startFrom = nullptr; 118 bool list = false; 119 120 void 121 Options::parse(int argc, char* argv[]) { 122 int i = 1; 123 while (i < argc) { 124 if (!strcmp(argv[i],"-help") || !strcmp(argv[i],"--help")) { 125 std::cerr << "Options for testing:" << std::endl 126 << "\t-seed (unsigned int or \"time\") default: " 127 << seed << std::endl 128 << "\t\tseed for random number generator (unsigned int)," 129 << std::endl 130 << "\t\tor \"time\" for a random seed based on " 131 << "current time" << std::endl 132 << "\t-fixprob (unsigned int) default: " 133 << fixprob << std::endl 134 << "\t\t1/fixprob is the probability of computing a fixpoint" 135 << std::endl 136 << "\t-iter (unsigned int) default: " <<iter<< std::endl 137 << "\t\tthe number of iterations" << std::endl 138 << "\t-test (string) default: (none)" << std::endl 139 << "\t\tsimple pattern for the tests to run" << std::endl 140 << "\t\tprefixing with \"-\" negates the pattern" << std::endl 141 << "\t\tprefixing with \"^\" requires a match at the beginning" << std::endl 142 << "\t\tmultiple pattern-options may be given" 143 << std::endl 144 << "\t-start (string) default: (none)" << std::endl 145 << "\t\tsimple pattern for the first test to run" << std::endl 146 << "\t-log" 147 << std::endl 148 << "\t\tlog execution of tests" 149 << std::endl 150 << "\t\tthe optional argument determines the style of the log" 151 << std::endl 152 << "\t\twith text as the default style" 153 << std::endl 154 << "\t-stop (boolean) default: " 155 << (stop ? "true" : "false") << std::endl 156 << "\t\tstop on first error or continue" << std::endl 157 << "\t-list" << std::endl 158 << "\t\toutput list of all test cases and exit" << std::endl 159 ; 160 exit(EXIT_SUCCESS); 161 } else if (!strcmp(argv[i],"-seed")) { 162 if (++i == argc) goto missing; 163 if (!strcmp(argv[i],"time")) { 164 seed = static_cast<unsigned int>(time(nullptr)); 165 } else { 166 seed = static_cast<unsigned int>(atoi(argv[i])); 167 } 168 } else if (!strcmp(argv[i],"-iter")) { 169 if (++i == argc) goto missing; 170 iter = static_cast<unsigned int>(atoi(argv[i])); 171 } else if (!strcmp(argv[i],"-fixprob")) { 172 if (++i == argc) goto missing; 173 fixprob = static_cast<unsigned int>(atoi(argv[i])); 174 } else if (!strcmp(argv[i],"-test")) { 175 if (++i == argc) goto missing; 176 if (argv[i][0] == '^') 177 testpat.emplace_back(MT_FIRST, argv[i] + 1); 178 else if (argv[i][0] == '-') 179 testpat.emplace_back(MT_NOT, argv[i] + 1); 180 else 181 testpat.emplace_back(MT_ANY, argv[i]); 182 } else if (!strcmp(argv[i],"-start")) { 183 if (++i == argc) goto missing; 184 startFrom = argv[i]; 185 } else if (!strcmp(argv[i],"-log")) { 186 log = true; 187 } else if (!strcmp(argv[i],"-stop")) { 188 if (++i == argc) goto missing; 189 if(argv[i][0] == 't') { 190 stop = true; 191 } else if (argv[i][0] == 'f') { 192 stop = false; 193 } 194 } else if (!strcmp(argv[i],"-list")) { 195 list = true; 196 } 197 i++; 198 } 199 return; 200 missing: 201 std::cerr << "Erroneous argument (" << argv[i-1] << ")" << std::endl 202 << " missing parameter" << std::endl; 203 exit(EXIT_FAILURE); 204 } 205 206} 207 208int 209main(int argc, char* argv[]) { 210 using namespace Test; 211#ifdef GECODE_HAS_MTRACE 212 mtrace(); 213#endif 214 215 opt.parse(argc, argv); 216 217 Base::sort(); 218 219 if (list) { 220 for (Base* t = Base::tests() ; t != nullptr; t = t->next() ) { 221 std::cout << t->name() << std::endl; 222 } 223 exit(EXIT_SUCCESS); 224 } 225 226 Base::rand.seed(opt.seed); 227 228 bool started = startFrom == nullptr ? true : false; 229 230 for (Base* t = Base::tests() ; t != nullptr; t = t->next() ) { 231 try { 232 if (!started) { 233 if (t->name().find(startFrom) != std::string::npos) 234 started = true; 235 else 236 goto next; 237 } 238 if (!testpat.empty()) { 239 bool match_found = false; 240 bool some_positive = false; 241 for (unsigned int i = 0; i < testpat.size(); ++i) { 242 if (testpat[i].first == MT_NOT) { // Negative pattern 243 if (t->name().find(testpat[i].second) != std::string::npos) 244 goto next; 245 } else { // Positive pattern 246 some_positive = true; 247 if (((testpat[i].first == MT_ANY) && 248 (t->name().find(testpat[i].second) != std::string::npos)) || 249 ((testpat[i].first == MT_FIRST) && 250 (t->name().find(testpat[i].second) == 0))) 251 match_found = true; 252 } 253 } 254 if (some_positive && !match_found) goto next; 255 } 256 std::cout << t->name() << " "; 257 std::cout.flush(); 258 for (unsigned int i = opt.iter; i--; ) { 259 opt.seed = Base::rand.seed(); 260 if (t->run()) { 261 std::cout << '+'; 262 std::cout.flush(); 263 } else { 264 std::cout << "-" << std::endl; 265 report_error(t->name()); 266 if (opt.stop) 267 return 1; 268 } 269 } 270 std::cout << std::endl; 271 } catch (Gecode::Exception& e) { 272 std::cout << "Exception in \"Gecode::" << e.what() 273 << "." << std::endl 274 << "Stopping..." << std::endl; 275 report_error(t->name()); 276 if (opt.stop) 277 return 1; 278 } 279 next:; 280 } 281 return 0; 282} 283 284std::ostream& 285operator<<(std::ostream& os, const Test::ind& i) { 286 for (int j=i.l; j--; ) 287 os << " "; 288 return os; 289} 290 291// STATISTICS: test-core