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