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