00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <config.h>
00025
00026
00027 #define XAPIAN_DEPRECATED(D) D
00028 #include <xapian.h>
00029
00030 #include <float.h>
00031 #include "safeerrno.h"
00032
00033 #include <string>
00034
00035 using namespace std;
00036
00037 #include "autoptr.h"
00038 #include "testsuite.h"
00039 #include "testutils.h"
00040
00041 #include "serialise.h"
00042 #include "serialise-double.h"
00043 #include "omqueryinternal.h"
00044 #include "utils.h"
00045
00046 static bool test_except1()
00047 {
00048 try {
00049 throw 1;
00050 } catch (int) {
00051 }
00052 return true;
00053 }
00054
00055 class Test_Exception {
00056 public:
00057 int value;
00058 Test_Exception(int value_) : value(value_) {}
00059 };
00060
00061
00062 static bool test_exception1()
00063 {
00064 try {
00065 try {
00066 throw Test_Exception(1);
00067 } catch (...) {
00068 try {
00069 throw Test_Exception(2);
00070 } catch (...) {
00071 }
00072 throw;
00073 }
00074 } catch (Test_Exception & e) {
00075 TEST_EQUAL(e.value, 1);
00076 return true;
00077 }
00078 return false;
00079 }
00080
00081
00082
00083
00084
00085 class test_refcnt : public Xapian::Internal::RefCntBase {
00086 private:
00087 bool &deleted;
00088 public:
00089 test_refcnt(bool &deleted_) : deleted(deleted_) {
00090 tout << "constructor\n";
00091 }
00092 Xapian::Internal::RefCntPtr<const test_refcnt> test() {
00093 return Xapian::Internal::RefCntPtr<const test_refcnt>(this);
00094 }
00095 ~test_refcnt() {
00096 deleted = true;
00097 tout << "destructor\n";
00098 }
00099 };
00100
00101 static bool test_refcnt1()
00102 {
00103 bool deleted = false;
00104
00105 test_refcnt *p = new test_refcnt(deleted);
00106
00107 TEST_EQUAL(p->ref_count, 0);
00108
00109 {
00110 Xapian::Internal::RefCntPtr<test_refcnt> rcp(p);
00111
00112 TEST_EQUAL(rcp->ref_count, 1);
00113
00114 {
00115 Xapian::Internal::RefCntPtr<test_refcnt> rcp2;
00116 rcp2 = rcp;
00117 TEST_EQUAL(rcp->ref_count, 2);
00118
00119 }
00120
00121 TEST_AND_EXPLAIN(!deleted, "Object prematurely deleted!");
00122 TEST_EQUAL(rcp->ref_count, 1);
00123
00124 }
00125
00126 TEST_AND_EXPLAIN(deleted, "Object not properly deleted");
00127
00128 return true;
00129 }
00130
00131
00132
00133 static bool test_refcnt2()
00134 {
00135 bool deleted = false;
00136
00137 test_refcnt *p = new test_refcnt(deleted);
00138
00139 Xapian::Internal::RefCntPtr<test_refcnt> rcp(p);
00140
00141 rcp = rcp;
00142
00143 TEST_AND_EXPLAIN(!deleted, "Object deleted by self-assignment");
00144
00145 return true;
00146 }
00147
00148
00149 class test_autoptr {
00150 bool &deleted;
00151 public:
00152 test_autoptr(bool &deleted_) : deleted(deleted_) {
00153 tout << "test_autoptr constructor\n";
00154 }
00155 ~test_autoptr() {
00156 deleted = true;
00157 tout << "test_autoptr destructor\n";
00158 }
00159 };
00160
00161
00162 static bool test_autoptr1()
00163 {
00164 bool deleted = false;
00165
00166 test_autoptr * raw_ptr = new test_autoptr(deleted);
00167 {
00168 AutoPtr<test_autoptr> ptr(raw_ptr);
00169
00170 TEST_EQUAL(ptr.get(), raw_ptr);
00171
00172 TEST(!deleted);
00173
00174 ptr = ptr;
00175
00176 TEST_EQUAL(ptr.get(), raw_ptr);
00177
00178 TEST(!deleted);
00179 }
00180
00181 TEST(deleted);
00182
00183 return true;
00184 }
00185
00186
00187 static bool test_stringcomp1()
00188 {
00189 bool success = true;
00190
00191 string s1;
00192 string s2;
00193
00194 s1 = "foo";
00195 s2 = "foo";
00196
00197 if ((s1 != s2) || (s1 > s2)) {
00198 success = false;
00199 tout << "String comparisons BADLY wrong" << endl;
00200 }
00201
00202 s1 += '\0';
00203
00204 if ((s1 == s2) || (s1 < s2)) {
00205 success = false;
00206 tout << "String comparisions don't cope with extra nulls" << endl;
00207 }
00208
00209 s2 += '\0';
00210
00211 s1 += 'a';
00212 s2 += 'z';
00213
00214 if ((s1.length() != 5) || (s2.length() != 5)) {
00215 success = false;
00216 tout << "Lengths with added nulls wrong" << endl;
00217 }
00218
00219 if ((s1 == s2) || !(s1 < s2)) {
00220 success = false;
00221 tout << "Characters after a null ignored in comparisons" << endl;
00222 }
00223
00224 return success;
00225 }
00226
00227 static bool test_tostring1()
00228 {
00229 TEST_EQUAL(om_tostring(0), "0");
00230 TEST_EQUAL(om_tostring(10), "10");
00231 TEST_EQUAL(om_tostring(10u), "10");
00232 TEST_EQUAL(om_tostring(-10), "-10");
00233 TEST_EQUAL(om_tostring(0xffffffff), "4294967295");
00234 TEST_EQUAL(om_tostring(0x7fffffff), "2147483647");
00235 TEST_EQUAL(om_tostring(0x7fffffffu), "2147483647");
00236 TEST_EQUAL(om_tostring(-0x7fffffff), "-2147483647");
00237
00238 #ifdef __WIN32__
00239
00240
00241
00242 TEST_EQUAL(om_tostring(10ll), "10");
00243 TEST_EQUAL(om_tostring(-10ll), "-10");
00244 TEST_EQUAL(om_tostring(0x200000000ll), "8589934592");
00245
00246
00247
00248 #endif
00249
00250 return true;
00251 }
00252
00253 #ifdef XAPIAN_HAS_REMOTE_BACKEND
00254
00255 static bool test_serialiselength1()
00256 {
00257 size_t n = 0;
00258 while (n < 0xff000000) {
00259 string s = encode_length(n);
00260 const char *p = s.data();
00261 const char *p_end = p + s.size();
00262 size_t decoded_n = decode_length(&p, p_end, false);
00263 if (n != decoded_n || p != p_end) tout << "[" << s << "]" << endl;
00264 TEST_EQUAL(n, decoded_n);
00265 TEST_EQUAL(p_end - p, 0);
00266 if (n < 5000) {
00267 ++n;
00268 } else {
00269 n += 53643;
00270 }
00271 }
00272
00273 return true;
00274 }
00275
00276
00277 static bool test_serialiselength2()
00278 {
00279
00280 {
00281 string s = encode_length(0);
00282 {
00283 const char *p = s.data();
00284 const char *p_end = p + s.size();
00285 TEST(decode_length(&p, p_end, true) == 0);
00286 TEST(p == p_end);
00287 }
00288 s += 'x';
00289 {
00290 const char *p = s.data();
00291 const char *p_end = p + s.size();
00292 TEST(decode_length(&p, p_end, true) == 0);
00293 TEST_EQUAL(p_end - p, 1);
00294 }
00295 }
00296
00297 {
00298 string s = encode_length(1);
00299 TEST_EXCEPTION(Xapian::NetworkError,
00300 const char *p = s.data();
00301 const char *p_end = p + s.size();
00302 TEST(decode_length(&p, p_end, true) == 1);
00303 );
00304 s += 'x';
00305 {
00306 const char *p = s.data();
00307 const char *p_end = p + s.size();
00308 TEST(decode_length(&p, p_end, true) == 1);
00309 TEST_EQUAL(p_end - p, 1);
00310 }
00311 s += 'x';
00312 {
00313 const char *p = s.data();
00314 const char *p_end = p + s.size();
00315 TEST(decode_length(&p, p_end, true) == 1);
00316 TEST_EQUAL(p_end - p, 2);
00317 }
00318 }
00319
00320 for (size_t n = 2; n < 1000; n = (n + 1) * 2 + (n >> 1)) {
00321 string s = encode_length(n);
00322 TEST_EXCEPTION(Xapian::NetworkError,
00323 const char *p = s.data();
00324 const char *p_end = p + s.size();
00325 TEST(decode_length(&p, p_end, true) == n);
00326 );
00327 s.append(n-1, 'x');
00328 TEST_EXCEPTION(Xapian::NetworkError,
00329 const char *p = s.data();
00330 const char *p_end = p + s.size();
00331 TEST(decode_length(&p, p_end, true) == n);
00332 );
00333 s += 'x';
00334 {
00335 const char *p = s.data();
00336 const char *p_end = p + s.size();
00337 TEST(decode_length(&p, p_end, true) == n);
00338 TEST_EQUAL(size_t(p_end - p), n);
00339 }
00340 s += 'x';
00341 {
00342 const char *p = s.data();
00343 const char *p_end = p + s.size();
00344 TEST(decode_length(&p, p_end, true) == n);
00345 TEST_EQUAL(size_t(p_end - p), n + 1);
00346 }
00347 }
00348
00349 return true;
00350 }
00351 #endif
00352
00353 static void check_double_serialisation(double u)
00354 {
00355 string encoded = serialise_double(u);
00356 const char * ptr = encoded.data();
00357 const char * end = ptr + encoded.size();
00358 double v = unserialise_double(&ptr, end);
00359 if (ptr != end || u != v) {
00360 tout << u << " -> " << v << ", difference = " << v - u << endl;
00361 tout << "FLT_RADIX = " << FLT_RADIX << endl;
00362 tout << "DBL_MAX_EXP = " << DBL_MAX_EXP << endl;
00363 }
00364 TEST(ptr == end);
00365 TEST_EQUAL(u, v);
00366 }
00367
00368
00369 static bool test_serialisedouble1()
00370 {
00371 static const double test_values[] = {
00372 3.14159265,
00373 1e57,
00374 123.1,
00375 257.12,
00376 1234.567e123,
00377 255.5,
00378 256.125,
00379 257.03125,
00380 };
00381
00382 check_double_serialisation(0.0);
00383 check_double_serialisation(1.0);
00384 check_double_serialisation(-1.0);
00385 check_double_serialisation(DBL_MAX);
00386 check_double_serialisation(-DBL_MAX);
00387 check_double_serialisation(DBL_MIN);
00388 check_double_serialisation(-DBL_MIN);
00389
00390 const double *p;
00391 for (p = test_values; p < test_values + sizeof(test_values) / sizeof(double); ++p) {
00392 double val = *p;
00393 check_double_serialisation(val);
00394 check_double_serialisation(-val);
00395 check_double_serialisation(1.0 / val);
00396 check_double_serialisation(-1.0 / val);
00397 }
00398
00399 return true;
00400 }
00401
00402 #ifdef XAPIAN_HAS_REMOTE_BACKEND
00403
00404 static bool test_serialisedoc1()
00405 {
00406 Xapian::Document doc;
00407
00408 string s;
00409
00410 s = serialise_document(doc);
00411 TEST(serialise_document(unserialise_document(s)) == s);
00412
00413 doc.set_data("helllooooo");
00414 doc.add_term("term");
00415 doc.add_value(1, "foo");
00416
00417 s = serialise_document(doc);
00418 TEST(serialise_document(unserialise_document(s)) == s);
00419
00420 return true;
00421 }
00422
00423 static void
00424 serialisequery1_helper(const Xapian::Query & query)
00425 {
00426 string before = query.internal->serialise();
00427 Xapian::Query::Internal * qint;
00428 qint = Xapian::Query::Internal::unserialise(before);
00429 string after = qint->serialise();
00430 delete qint;
00431 TEST(before == after);
00432 }
00433
00434
00435 static bool test_serialisequery1()
00436 {
00437 string s;
00438
00439 serialisequery1_helper(Xapian::Query("foo"));
00440
00441
00442 serialisequery1_helper(Xapian::Query("foo", 1, 1));
00443
00444 serialisequery1_helper(Xapian::Query(Xapian::Query::OP_OR,
00445 Xapian::Query("foo", 1, 1),
00446 Xapian::Query("bar", 1, 1)));
00447
00448 static const char * words[] = { "paragraph", "word" };
00449 serialisequery1_helper(Xapian::Query(Xapian::Query::OP_OR, words, words + 2));
00450
00451 static const char * words2[] = { "milk", "on", "fridge" };
00452 serialisequery1_helper(
00453 Xapian::Query(Xapian::Query::OP_SCALE_WEIGHT,
00454 Xapian::Query(Xapian::Query::OP_OR,
00455 Xapian::Query("leave"),
00456 Xapian::Query(Xapian::Query::OP_PHRASE, words2, words2 + 3)
00457 ),
00458 2.5)
00459 );
00460
00461 return true;
00462 }
00463
00464
00465 static bool test_serialiseerror1()
00466 {
00467 string enoent_msg(strerror(ENOENT));
00468 Xapian::DatabaseOpeningError e("Failed to open database", ENOENT);
00469
00470
00471 TEST_STRINGS_EQUAL(e.get_description(), "DatabaseOpeningError: Failed to open database (" + enoent_msg + ")");
00472
00473 TEST_EQUAL(e.get_errno(), ENOENT);
00474 TEST_STRINGS_EQUAL(e.get_error_string(), enoent_msg);
00475
00476 string serialisation = serialise_error(e);
00477
00478
00479
00480
00481 bool threw = false;
00482 try {
00483
00484 unserialise_error(serialisation, "", "");
00485 } catch (Xapian::Error & ecaught) {
00486 TEST_EQUAL(ecaught.get_errno(), 0);
00487 TEST_STRINGS_EQUAL(ecaught.get_error_string(), enoent_msg);
00488 threw = true;
00489 }
00490 TEST(threw);
00491
00492
00493 TEST_STRINGS_EQUAL(e.get_error_string(), enoent_msg);
00494
00495
00496
00497 Xapian::DatabaseOpeningError ecopy(e);
00498 TEST_STRINGS_EQUAL(ecopy.get_error_string(), enoent_msg);
00499
00500 return true;
00501 }
00502 #endif
00503
00504
00505
00506
00507
00508
00509
00510 struct TempDtorTest {
00511 static int count;
00512 static TempDtorTest factory() { return TempDtorTest(); }
00513 TempDtorTest() { ++count; }
00514 ~TempDtorTest() { --count; }
00515 };
00516
00517 int TempDtorTest::count = 0;
00518
00519 static bool test_temporarydtor1()
00520 {
00521 TEST_EQUAL(TempDtorTest::count, 0);
00522 TempDtorTest::factory();
00523 TEST_EQUAL(TempDtorTest::count, 0);
00524
00525 return true;
00526 }
00527
00528
00529
00530
00531
00533 test_desc tests[] = {
00534 {"except1", test_except1},
00535 {"exception1", test_exception1},
00536 {"refcnt1", test_refcnt1},
00537 {"refcnt2", test_refcnt2},
00538 {"autoptr1", test_autoptr1},
00539 {"stringcomp1", test_stringcomp1},
00540 {"temporarydtor1", test_temporarydtor1},
00541 {"tostring1", test_tostring1},
00542 {"serialisedouble1", test_serialisedouble1},
00543 #ifdef XAPIAN_HAS_REMOTE_BACKEND
00544 {"serialiselength1", test_serialiselength1},
00545 {"serialiselength2", test_serialiselength2},
00546 {"serialisedoc1", test_serialisedoc1},
00547 {"serialisequery1", test_serialisequery1},
00548 {"serialiseerror1", test_serialiseerror1},
00549 #endif
00550 {0, 0}
00551 };
00552
00553 int main(int argc, char **argv)
00554 {
00555 test_driver::parse_command_line(argc, argv);
00556 return test_driver::run(tests);
00557 }