Fix java examples and related docs on how to run them
[xapian.git] / xapian-core / tests / unittest.cc
blobee074ddf86e592b87fe4b453a5ff8f9c9a447a01
1 /** @file unittest.cc
2 * @brief Unit tests of non-Xapian-specific internal code.
3 */
4 /* Copyright (C) 2006,2007,2009,2010,2012,2015,2016 Olly Betts
5 * Copyright (C) 2007 Richard Boulton
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
20 * USA
23 #include <config.h>
25 #include <cfloat>
26 #include <climits>
27 #include <cmath>
28 #include <cstring>
29 #include <iostream>
31 #include "safeunistd.h"
33 #define XAPIAN_UNITTEST
34 static const char * unittest_assertion_failed = NULL;
35 #define UNITTEST_CHECK_EXCEPTION \
36 if (unittest_assertion_failed) { \
37 const char * unittest_assertion_failed_ = unittest_assertion_failed;\
38 unittest_assertion_failed = NULL;\
39 throw unittest_assertion_failed_;\
42 #include "testsuite.h"
44 using namespace std;
46 #define UNITTEST_ASSERT_LOCATION__(LINE,MSG) __FILE__":"#LINE": "#MSG
47 #define UNITTEST_ASSERT_LOCATION_(LINE,MSG) UNITTEST_ASSERT_LOCATION__(LINE,MSG)
48 #define UNITTEST_ASSERT_LOCATION(MSG) UNITTEST_ASSERT_LOCATION_(__LINE__,MSG)
49 #define UNITTEST_ASSERT_NOTHROW(COND, RET) \
50 do {\
51 if (rare(!(COND))) {\
52 unittest_assertion_failed = UNITTEST_ASSERT_LOCATION(COND);\
53 return RET;\
55 } while (false)
57 // Utility code we use:
58 #include "../common/stringutils.h"
59 #include "../common/log2.h"
61 // Simpler version of TEST_EXCEPTION macro.
62 #define TEST_EXCEPTION(TYPE, CODE) \
63 do { \
64 try { \
65 CODE; \
66 UNITTEST_CHECK_EXCEPTION \
67 FAIL_TEST("Expected exception "#TYPE" not thrown"); \
68 } catch (const TYPE &) { \
69 } \
70 } while (0)
72 // Code we're unit testing:
73 #include "../common/closefrom.cc"
74 #include "../common/errno_to_string.cc"
75 #include "../common/fileutils.cc"
76 #include "../common/serialise-double.cc"
77 #include "../common/str.cc"
78 #include "../net/length.cc"
79 #include "../net/serialise-error.cc"
80 #include "../api/error.cc"
81 #include "../api/sortable-serialise.cc"
83 // Stub replacement, which doesn't deal with escaping or producing valid UTF-8.
84 // The full implementation needs Xapian::Utf8Iterator and
85 // Xapian::Unicode::append_utf8().
86 void
87 description_append(std::string & desc, const std::string &s)
89 desc += s;
92 DEFINE_TESTCASE_(simple_exceptions_work1) {
93 try {
94 throw 42;
95 } catch (int val) {
96 TEST_EQUAL(val, 42);
97 return true;
99 return false;
102 class TestException { };
104 DEFINE_TESTCASE_(class_exceptions_work1) {
105 try {
106 throw TestException();
107 } catch (const TestException &) {
108 return true;
110 return false;
113 inline string
114 r_r_p(string a, const string & b)
116 resolve_relative_path(a, b);
117 return a;
120 DEFINE_TESTCASE_(resolverelativepath1) {
121 TEST_EQUAL(r_r_p("/abs/o/lute", ""), "/abs/o/lute");
122 TEST_EQUAL(r_r_p("/abs/o/lute", "/"), "/abs/o/lute");
123 TEST_EQUAL(r_r_p("/abs/o/lute", "//"), "/abs/o/lute");
124 TEST_EQUAL(r_r_p("/abs/o/lute", "foo"), "/abs/o/lute");
125 TEST_EQUAL(r_r_p("/abs/o/lute", "foo/"), "/abs/o/lute");
126 TEST_EQUAL(r_r_p("/abs/o/lute", "/foo"), "/abs/o/lute");
127 TEST_EQUAL(r_r_p("/abs/o/lute", "/foo/"), "/abs/o/lute");
128 TEST_EQUAL(r_r_p("/abs/o/lute", "foo/bar"), "/abs/o/lute");
129 TEST_EQUAL(r_r_p("/abs/o/lute", "foo/bar/"), "/abs/o/lute");
130 TEST_EQUAL(r_r_p("/abs/o/lute", "/foo/bar"), "/abs/o/lute");
131 TEST_EQUAL(r_r_p("/abs/o/lute", "/foo/bar/"), "/abs/o/lute");
132 TEST_EQUAL(r_r_p("rel/a/tive", ""), "rel/a/tive");
133 TEST_EQUAL(r_r_p("rel/a/tive", "/"), "/rel/a/tive");
134 TEST_EQUAL(r_r_p("rel/a/tive", "//"), "//rel/a/tive");
135 TEST_EQUAL(r_r_p("rel/a/tive", "foo"), "rel/a/tive");
136 TEST_EQUAL(r_r_p("rel/a/tive", "foo/"), "foo/rel/a/tive");
137 TEST_EQUAL(r_r_p("rel/a/tive", "/foo"), "/rel/a/tive");
138 TEST_EQUAL(r_r_p("rel/a/tive", "/foo/"), "/foo/rel/a/tive");
139 TEST_EQUAL(r_r_p("rel/a/tive", "foo/bar"), "foo/rel/a/tive");
140 TEST_EQUAL(r_r_p("rel/a/tive", "foo/bar/"), "foo/bar/rel/a/tive");
141 TEST_EQUAL(r_r_p("rel/a/tive", "/foo/bar"), "/foo/rel/a/tive");
142 TEST_EQUAL(r_r_p("rel/a/tive", "/foo/bar/"), "/foo/bar/rel/a/tive");
143 #ifndef __WIN32__
144 TEST_EQUAL(r_r_p("/abs/o/lute", "/foo\\bar"), "/abs/o/lute");
145 TEST_EQUAL(r_r_p("rel/a/tive", "/foo\\bar"), "/rel/a/tive");
146 #else
147 TEST_EQUAL(r_r_p("\\dos\\path", ""), "\\dos\\path");
148 TEST_EQUAL(r_r_p("\\dos\\path", "/"), "\\dos\\path");
149 TEST_EQUAL(r_r_p("\\dos\\path", "\\"), "\\dos\\path");
150 TEST_EQUAL(r_r_p("\\dos\\path", "c:"), "c:\\dos\\path");
151 TEST_EQUAL(r_r_p("\\dos\\path", "c:\\"), "c:\\dos\\path");
152 TEST_EQUAL(r_r_p("\\dos\\path", "c:\\temp"), "c:\\dos\\path");
153 TEST_EQUAL(r_r_p("\\dos\\path", "c:\\temp\\"), "c:\\dos\\path");
154 TEST_EQUAL(r_r_p("rel/a/tive", "\\"), "\\rel/a/tive");
155 TEST_EQUAL(r_r_p("rel/a/tive", "foo\\"), "foo\\rel/a/tive");
156 TEST_EQUAL(r_r_p("rel\\a\\tive", "/foo/"), "/foo/rel\\a\\tive");
157 TEST_EQUAL(r_r_p("rel/a/tive", "c:/foo/bar"), "c:/foo/rel/a/tive");
158 TEST_EQUAL(r_r_p("rel/a/tive", "c:foo/bar/"), "c:foo/bar/rel/a/tive");
159 TEST_EQUAL(r_r_p("rel/a/tive", "c:"), "c:rel/a/tive");
160 TEST_EQUAL(r_r_p("rel/a/tive", "c:\\"), "c:\\rel/a/tive");
161 TEST_EQUAL(r_r_p("C:rel/a/tive", "c:\\foo\\bar"), "C:\\foo\\rel/a/tive");
162 TEST_EQUAL(r_r_p("C:rel/a/tive", "c:"), "C:rel/a/tive");
163 // This one is impossible to reliably resolve without knowing the current
164 // drive - if it is C:, then the answer is: "C:/abs/o/rel/a/tive"
165 TEST_EQUAL(r_r_p("C:rel/a/tive", "/abs/o/lute"), "C:rel/a/tive");
166 // UNC paths tests:
167 TEST_EQUAL(r_r_p("\\\\SRV\\VOL\\FILE", "/a/b"), "\\\\SRV\\VOL\\FILE");
168 TEST_EQUAL(r_r_p("rel/a/tive", "\\\\SRV\\VOL\\DIR\\FILE"), "\\\\SRV\\VOL\\DIR\\rel/a/tive");
169 TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\SRV\\VOL\\FILE"), "\\\\SRV\\VOL/abs/o/lute");
170 TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\S\\V\\FILE"), "\\\\S\\V/abs/o/lute");
171 TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\S\\V\\"), "\\\\S\\V/abs/o/lute");
172 TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\S\\V"), "\\\\S\\V/abs/o/lute");
173 TEST_EQUAL(r_r_p("//SRV/VOL/FILE", "/a/b"), "//SRV/VOL/FILE");
174 TEST_EQUAL(r_r_p("rel/a/tive", "//SRV/VOL/DIR/FILE"), "//SRV/VOL/DIR/rel/a/tive");
175 TEST_EQUAL(r_r_p("/abs/o/lute", "//SRV/VOL/FILE"), "//SRV/VOL/abs/o/lute");
176 TEST_EQUAL(r_r_p("/abs/o/lute", "//S/V/FILE"), "//S/V/abs/o/lute");
177 TEST_EQUAL(r_r_p("/abs/o/lute", "//S/V/"), "//S/V/abs/o/lute");
178 TEST_EQUAL(r_r_p("/abs/o/lute", "//S/V"), "//S/V/abs/o/lute");
179 TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\?\\C:\\wibble"), "\\\\?\\C:\\abs\\o\\lute");
180 TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\?\\UNC\\S\\V"), "\\\\?\\UNC\\S\\V\\abs\\o\\lute");
181 TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\?\\UNC\\S\\V\\"), "\\\\?\\UNC\\S\\V\\abs\\o\\lute");
182 TEST_EQUAL(r_r_p("/abs/o/lute", "\\\\?\\UNC\\S\\V\\TMP\\README.TXT"), "\\\\?\\UNC\\S\\V\\abs\\o\\lute");
183 TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\C:\\wibble"), "\\\\?\\C:\\r\\elativ\\e");
184 TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\C:\\wibble\\wobble"), "\\\\?\\C:\\wibble\\r\\elativ\\e");
185 #if 0 // Is this a valid testcase? It fails, but isn't relevant to Xapian.
186 TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\UNC\\S\\V"), "\\\\?\\UNC\\S\\V\\r\\elativ\\e");
187 #endif
188 TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\UNC\\S\\V\\"), "\\\\?\\UNC\\S\\V\\r\\elativ\\e");
189 TEST_EQUAL(r_r_p("r/elativ/e", "\\\\?\\UNC\\S\\V\\TMP\\README.TXT"), "\\\\?\\UNC\\S\\V\\TMP\\r\\elativ\\e");
190 #endif
191 return true;
194 static void
195 check_double_serialisation(double u)
197 // Commonly C++ string implementations keep the string nul-terminated, and
198 // encoded.data() returns a pointer to a buffer including the nul (the same
199 // as encoded.c_str()). This means that valgrind won't catch a read one
200 // past the end of the serialised value, so we copy just the serialised
201 // value into a temporary buffer.
202 char buf[16];
203 string encoded = serialise_double(u);
204 TEST(encoded.size() < sizeof(buf));
205 memcpy(buf, encoded.data(), encoded.size());
206 // Put a NULL pointer either side, to catch incrementing/decrementing at
207 // the wrong level of indirection (regression test for a bug in an
208 // unreleased version).
209 const char * ptr[3] = { NULL, buf, NULL };
210 const char * end = ptr[1] + encoded.size();
211 double v = unserialise_double(&(ptr[1]), end);
212 if (ptr[1] != end || u != v) {
213 cout << u << " -> " << v << ", difference = " << v - u << endl;
214 cout << "FLT_RADIX = " << FLT_RADIX << endl;
215 cout << "DBL_MAX_EXP = " << DBL_MAX_EXP << endl;
217 TEST_EQUAL(static_cast<const void*>(ptr[1]), static_cast<const void*>(end));
220 // Check serialisation of doubles.
221 DEFINE_TESTCASE_(serialisedouble1) {
222 static const double test_values[] = {
223 3.14159265,
224 1e57,
225 123.1,
226 257.12,
227 1234.567e123,
228 255.5,
229 256.125,
230 257.03125,
233 check_double_serialisation(0.0);
234 check_double_serialisation(1.0);
235 check_double_serialisation(-1.0);
236 check_double_serialisation(DBL_MAX);
237 check_double_serialisation(-DBL_MAX);
238 check_double_serialisation(DBL_MIN);
239 check_double_serialisation(-DBL_MIN);
241 const double *p;
242 for (p = test_values; p < test_values + sizeof(test_values) / sizeof(double); ++p) {
243 double val = *p;
244 check_double_serialisation(val);
245 check_double_serialisation(-val);
246 check_double_serialisation(1.0 / val);
247 check_double_serialisation(-1.0 / val);
250 return true;
253 #ifdef XAPIAN_HAS_REMOTE_BACKEND
254 // Check serialisation of lengths.
255 static bool test_serialiselength1()
257 size_t n = 0;
258 while (n < 0xff000000) {
259 string s = encode_length(n);
260 const char *p = s.data();
261 const char *p_end = p + s.size();
262 size_t decoded_n;
263 decode_length(&p, p_end, decoded_n);
264 if (n != decoded_n || p != p_end) tout << "[" << s << "]" << endl;
265 TEST_EQUAL(n, decoded_n);
266 TEST_EQUAL(p_end - p, 0);
267 if (n < 5000) {
268 ++n;
269 } else {
270 n += 53643;
274 return true;
277 // Regression test: vetting the remaining buffer length
278 static bool test_serialiselength2()
280 // Special case tests for 0
282 string s = encode_length(0);
284 const char *p = s.data();
285 const char *p_end = p + s.size();
286 size_t r;
287 decode_length_and_check(&p, p_end, r);
288 TEST(r == 0);
289 TEST(p == p_end);
291 s += 'x';
293 const char *p = s.data();
294 const char *p_end = p + s.size();
295 size_t r;
296 decode_length_and_check(&p, p_end, r);
297 TEST(r == 0);
298 TEST_EQUAL(p_end - p, 1);
301 // Special case tests for 1
303 string s = encode_length(1);
304 TEST_EXCEPTION(Xapian_NetworkError,
305 const char *p = s.data();
306 const char *p_end = p + s.size();
307 size_t r;
308 decode_length_and_check(&p, p_end, r);
309 (void)r;
311 s += 'x';
313 const char *p = s.data();
314 const char *p_end = p + s.size();
315 size_t r;
316 decode_length_and_check(&p, p_end, r);
317 TEST(r == 1);
318 TEST_EQUAL(p_end - p, 1);
320 s += 'x';
322 const char *p = s.data();
323 const char *p_end = p + s.size();
324 size_t r;
325 decode_length_and_check(&p, p_end, r);
326 TEST(r == 1);
327 TEST_EQUAL(p_end - p, 2);
330 // Nothing magic here, just test a range of odd and even values.
331 for (size_t n = 2; n < 1000; n = (n + 1) * 2 + (n >> 1)) {
332 string s = encode_length(n);
333 TEST_EXCEPTION(Xapian_NetworkError,
334 const char *p = s.data();
335 const char *p_end = p + s.size();
336 size_t r;
337 decode_length_and_check(&p, p_end, r);
338 (void)r;
340 s.append(n - 1, 'x');
341 TEST_EXCEPTION(Xapian_NetworkError,
342 const char *p = s.data();
343 const char *p_end = p + s.size();
344 size_t r;
345 decode_length_and_check(&p, p_end, r);
346 (void)r;
348 s += 'x';
350 const char *p = s.data();
351 const char *p_end = p + s.size();
352 size_t r;
353 decode_length_and_check(&p, p_end, r);
354 TEST(r == n);
355 TEST_EQUAL(size_t(p_end - p), n);
357 s += 'x';
359 const char *p = s.data();
360 const char *p_end = p + s.size();
361 size_t r;
362 decode_length_and_check(&p, p_end, r);
363 TEST(r == n);
364 TEST_EQUAL(size_t(p_end - p), n + 1);
368 return true;
371 // Check serialisation of Xapian::Error.
372 static bool test_serialiseerror1()
374 string enoent_msg(strerror(ENOENT));
375 Xapian::DatabaseOpeningError e("Failed to open database", ENOENT);
376 // Regression test for bug in 1.0.0 - it didn't convert errno values for
377 // get_description() if they hadn't already been converted.
378 TEST_STRINGS_EQUAL(e.get_description(), "DatabaseOpeningError: Failed to open database (" + enoent_msg + ")");
380 TEST_STRINGS_EQUAL(e.get_error_string(), enoent_msg);
382 string serialisation = serialise_error(e);
384 // Test if unserialise_error() throws with a flag to avoid the possibility
385 // of an "unreachable code" warning when we get around to marking
386 // unserialise_error() as "noreturn".
387 bool threw = false;
388 try {
389 // unserialise_error throws an exception.
390 unserialise_error(serialisation, "", "");
391 } catch (const Xapian::Error & ecaught) {
392 TEST_STRINGS_EQUAL(ecaught.get_error_string(), enoent_msg);
393 threw = true;
395 TEST(threw);
397 // Check that the original is still OK.
398 TEST_STRINGS_EQUAL(e.get_error_string(), enoent_msg);
400 // Regression test - in 1.0.0, copying used to duplicate the error_string
401 // pointer, resulting in double calls to free().
402 Xapian::DatabaseOpeningError ecopy(e);
403 TEST_STRINGS_EQUAL(ecopy.get_error_string(), enoent_msg);
405 return true;
407 #endif
409 // Test log2() (which might be our replacement version).
410 static bool test_log2()
412 TEST_EQUAL(log2(1.0), 0.0);
413 TEST_EQUAL(log2(2.0), 1.0);
414 TEST_EQUAL(log2(1024.0), 10.0);
415 TEST_EQUAL(log2(0.5), -1.0);
416 return true;
419 static const double test_sortableserialise_numbers[] = {
420 #ifdef INFINITY
421 -INFINITY,
422 #endif
423 -HUGE_VAL,
424 -DBL_MAX,
425 -exp2(1022),
426 -1024.5,
427 -3.14159265358979323846,
430 -1.8,
431 -1.1,
433 -0.5,
434 -0.2,
435 -0.1,
436 -0.000005,
437 -0.000002,
438 -0.000001,
439 -exp2(-1023),
440 -exp2(-1024),
441 -exp2(-1074),
442 -DBL_MIN,
444 DBL_MIN,
445 exp2(-1074),
446 exp2(-1024),
447 exp2(-1023),
448 0.000001,
449 0.000002,
450 0.000005,
451 0.1,
452 0.2,
453 0.5,
455 1.1,
456 1.8,
459 3.14159265358979323846,
460 1024.5,
461 exp2(1022),
462 DBL_MAX,
463 HUGE_VAL,
464 #ifdef INFINITY
465 INFINITY,
466 #endif
468 64 // Magic number which we stop at.
471 // Test serialisation and unserialisation of various numbers.
472 // This is actually a public API, but we want extra assertions in the code
473 // while we test it.
474 static bool test_sortableserialise1()
476 double prevnum = 0;
477 string prevstr;
478 bool started = false;
479 for (const double *p = test_sortableserialise_numbers; *p != 64; ++p) {
480 double num = *p;
481 tout << "Number: " << num << '\n';
482 string str = Xapian::sortable_serialise(num);
483 tout << "String: " << str << '\n';
484 TEST_EQUAL(Xapian::sortable_unserialise(str), num);
486 if (started) {
487 int num_cmp = 0;
488 if (prevnum < num) {
489 num_cmp = -1;
490 } else if (prevnum > num) {
491 num_cmp = 1;
493 int str_cmp = 0;
494 if (prevstr < str) {
495 str_cmp = -1;
496 } else if (prevstr > str) {
497 str_cmp = 1;
500 TEST_AND_EXPLAIN(num_cmp == str_cmp,
501 "Numbers " << prevnum << " and " << num <<
502 " don't sort the same way as their string "
503 "counterparts");
506 prevnum = num;
507 prevstr = str;
508 started = true;
510 return true;
513 static bool test_tostring1()
515 TEST_EQUAL(str(0), "0");
516 TEST_EQUAL(str(0u), "0");
517 TEST_EQUAL(str(1), "1");
518 TEST_EQUAL(str(1u), "1");
519 TEST_EQUAL(str(9), "9");
520 TEST_EQUAL(str(9u), "9");
521 TEST_EQUAL(str(10), "10");
522 TEST_EQUAL(str(10u), "10");
523 TEST_EQUAL(str(-1), "-1");
524 TEST_EQUAL(str(-9), "-9");
525 TEST_EQUAL(str(-10), "-10");
526 TEST_EQUAL(str(0xffffffff), "4294967295");
527 TEST_EQUAL(str(0x7fffffff), "2147483647");
528 TEST_EQUAL(str(0x7fffffffu), "2147483647");
529 TEST_EQUAL(str(-0x7fffffff), "-2147483647");
531 #ifdef __WIN32__
532 /* Test the 64 bit integer conversion to string.
533 * (Currently only exists for windows.)
535 TEST_EQUAL(str(10ll), "10");
536 TEST_EQUAL(str(-10ll), "-10");
537 TEST_EQUAL(str(0x200000000ll), "8589934592");
538 // We don't currently have an "unsigned long long" version since it's not required
539 // anywhere in the library.
540 // TEST_EQUAL(str(0x200000000ull), "8589934592");
541 #endif
543 return true;
546 /// Regression test for bug fixed in 1.1.1.
547 static bool test_strbool1()
549 TEST_EQUAL(str(true), "1");
550 TEST_EQUAL(str(false), "0");
551 return true;
554 static bool test_closefrom1()
556 #ifndef __WIN32__
557 // Simple test.
558 closefrom(8);
560 // Simple test when there are definitely no fds to close.
561 closefrom(42);
563 // Test passing a really high threshold.
564 closefrom(INT_MAX);
566 // Open some fds and check the expected ones are closed.
567 TEST_EQUAL(dup2(1, 14), 14);
568 TEST_EQUAL(dup2(1, 15), 15);
569 TEST_EQUAL(dup2(1, 18), 18);
570 closefrom(15);
571 TEST_EQUAL(close(14), 0);
572 TEST(close(15) == -1 && errno == EBADF);
573 TEST(close(18) == -1 && errno == EBADF);
574 #endif
575 return true;
578 static const test_desc tests[] = {
579 TESTCASE(simple_exceptions_work1),
580 TESTCASE(class_exceptions_work1),
581 TESTCASE(resolverelativepath1),
582 TESTCASE(serialisedouble1),
583 #ifdef XAPIAN_HAS_REMOTE_BACKEND
584 TESTCASE(serialiselength1),
585 TESTCASE(serialiselength2),
586 TESTCASE(serialiseerror1),
587 #endif
588 TESTCASE(log2),
589 TESTCASE(sortableserialise1),
590 TESTCASE(tostring1),
591 TESTCASE(strbool1),
592 TESTCASE(closefrom1),
593 END_OF_TESTCASES
596 int main(int argc, char **argv)
597 try {
598 test_driver::parse_command_line(argc, argv);
599 return test_driver::run(tests);
600 } catch (const char * e) {
601 cout << e << endl;
602 return 1;