LCOV - code coverage report
Current view: top level - home/olly/git/atia-xapian/xapian-core/tests - api_serialise.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core r Lines: 322 342 94.2 %
Date: 2011-08-21 Functions: 33 48 68.8 %
Branches: 133 446 29.8 %

           Branch data     Line data    Source code
       1                 :            : /** @file api_serialise.cc
       2                 :            :  * @brief Tests of serialisation functionality.
       3                 :            :  */
       4                 :            : /* Copyright 2009 Lemur Consulting Ltd
       5                 :            :  * Copyright 2009 Olly Betts
       6                 :            :  *
       7                 :            :  * This program is free software; you can redistribute it and/or modify
       8                 :            :  * it under the terms of the GNU General Public License as published by
       9                 :            :  * the Free Software Foundation; either version 2 of the License, or
      10                 :            :  * (at your option) any later version.
      11                 :            :  *
      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.
      16                 :            :  *
      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 USA
      20                 :            :  */
      21                 :            : 
      22                 :            : #include <config.h>
      23                 :            : 
      24                 :            : #include "api_serialise.h"
      25                 :            : 
      26                 :            : #include <xapian.h>
      27                 :            : 
      28                 :            : #include <exception>
      29                 :            : #include <stdexcept>
      30                 :            : 
      31                 :            : #include "apitest.h"
      32                 :            : #include "testutils.h"
      33                 :            : 
      34                 :            : using namespace std;
      35                 :            : 
      36                 :            : // Test for serialising a document
      37                 :          1 : DEFINE_TESTCASE(serialise_document1, !backend) {
      38                 :          1 :     Xapian::Document doc;
      39                 :          1 :     doc.add_term("foo", 2);
      40                 :          1 :     doc.add_posting("foo", 10);
      41                 :          1 :     doc.add_value(1, "bar");
      42                 :          1 :     doc.set_data("baz");
      43                 :            : 
      44                 :          1 :     Xapian::Document doc2 = Xapian::Document::unserialise(doc.serialise());
      45                 :            : 
      46   [ -  +  #  # ]:          1 :     TEST_EQUAL(doc.termlist_count(), doc2.termlist_count());
      47 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(doc.termlist_count(), 1);
      48                 :          1 :     Xapian::TermIterator i;
      49                 :          1 :     Xapian::PositionIterator j;
      50                 :          1 :     Xapian::ValueIterator k;
      51                 :            : 
      52                 :          1 :     i = doc.termlist_begin();
      53 [ -  + ][ #  # ]:          1 :     TEST_NOT_EQUAL(i, doc.termlist_end());
      54 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(i.get_wdf(), 3);
      55 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(*i, "foo");
      56 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(i.positionlist_count(), 1);
      57                 :          1 :     j = i.positionlist_begin();
      58 [ -  + ][ #  # ]:          1 :     TEST_NOT_EQUAL(j, i.positionlist_end());
      59 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(*j, 10);
      60                 :          1 :     ++j;
      61 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(j, i.positionlist_end());
      62                 :          1 :     ++i;
      63 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(i, doc.termlist_end());
      64                 :            : 
      65 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(doc.values_count(), 1);
      66                 :          1 :     k = doc.values_begin();
      67   [ -  +  #  # ]:          1 :     TEST_NOT_EQUAL(k, doc.values_end());
      68 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(k.get_valueno(), 1);
      69 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(*k, "bar");
      70                 :          1 :     ++k;
      71   [ -  +  #  # ]:          1 :     TEST_EQUAL(k, doc.values_end());
      72                 :            : 
      73 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(doc.get_data(), "baz");
      74                 :            : 
      75                 :          1 :     i = doc2.termlist_begin();
      76 [ -  + ][ #  # ]:          1 :     TEST_NOT_EQUAL(i, doc2.termlist_end());
      77 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(i.get_wdf(), 3);
      78 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(*i, "foo");
      79 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(i.positionlist_count(), 1);
      80                 :          1 :     j = i.positionlist_begin();
      81 [ -  + ][ #  # ]:          1 :     TEST_NOT_EQUAL(j, i.positionlist_end());
      82 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(*j, 10);
      83                 :          1 :     ++j;
      84 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(j, i.positionlist_end());
      85                 :          1 :     ++i;
      86 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(i, doc2.termlist_end());
      87                 :            : 
      88 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(doc2.values_count(), 1);
      89                 :          1 :     k = doc2.values_begin();
      90   [ -  +  #  # ]:          1 :     TEST_NOT_EQUAL(k, doc2.values_end());
      91 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(k.get_valueno(), 1);
      92 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(*k, "bar");
      93                 :          1 :     ++k;
      94   [ -  +  #  # ]:          1 :     TEST_EQUAL(k, doc2.values_end());
      95                 :            : 
      96 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(doc2.get_data(), "baz");
      97                 :            :  
      98                 :          1 :     return true;
      99                 :            : }
     100                 :            : 
     101                 :            : // Test for serialising a document obtained from a database.
     102                 :         10 : DEFINE_TESTCASE(serialise_document2, writable) {
     103                 :         10 :     Xapian::Document origdoc;
     104                 :         10 :     origdoc.add_term("foo", 2);
     105                 :         10 :     origdoc.add_posting("foo", 10);
     106                 :         10 :     origdoc.add_value(1, "bar");
     107                 :         10 :     origdoc.set_data("baz");
     108                 :         10 :     Xapian::WritableDatabase db = get_writable_database();
     109                 :         10 :     db.add_document(origdoc);
     110                 :            : 
     111                 :         10 :     Xapian::Document doc = db.get_document(1);
     112                 :            : 
     113                 :         10 :     Xapian::Document doc2 = Xapian::Document::unserialise(doc.serialise());
     114                 :            : 
     115   [ -  +  #  # ]:         10 :     TEST_EQUAL(doc.termlist_count(), doc2.termlist_count());
     116 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(doc.termlist_count(), 1);
     117                 :         10 :     Xapian::TermIterator i;
     118                 :         10 :     Xapian::PositionIterator j;
     119                 :         10 :     Xapian::ValueIterator k;
     120                 :            : 
     121                 :         10 :     i = doc.termlist_begin();
     122 [ -  + ][ #  # ]:         10 :     TEST_NOT_EQUAL(i, doc.termlist_end());
     123 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(i.get_wdf(), 3);
     124 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(*i, "foo");
     125 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(i.positionlist_count(), 1);
     126                 :         10 :     j = i.positionlist_begin();
     127 [ -  + ][ #  # ]:         10 :     TEST_NOT_EQUAL(j, i.positionlist_end());
     128 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(*j, 10);
     129                 :         10 :     ++j;
     130 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(j, i.positionlist_end());
     131                 :         10 :     ++i;
     132 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(i, doc.termlist_end());
     133                 :            : 
     134 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(doc.values_count(), 1);
     135                 :         10 :     k = doc.values_begin();
     136   [ -  +  #  # ]:         10 :     TEST_NOT_EQUAL(k, doc.values_end());
     137 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(k.get_valueno(), 1);
     138 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(*k, "bar");
     139                 :         10 :     ++k;
     140   [ -  +  #  # ]:         10 :     TEST_EQUAL(k, doc.values_end());
     141                 :            : 
     142 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(doc.get_data(), "baz");
     143                 :            : 
     144                 :         10 :     i = doc2.termlist_begin();
     145 [ -  + ][ #  # ]:         10 :     TEST_NOT_EQUAL(i, doc2.termlist_end());
     146 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(i.get_wdf(), 3);
     147 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(*i, "foo");
     148 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(i.positionlist_count(), 1);
     149                 :         10 :     j = i.positionlist_begin();
     150 [ -  + ][ #  # ]:         10 :     TEST_NOT_EQUAL(j, i.positionlist_end());
     151 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(*j, 10);
     152                 :         10 :     ++j;
     153 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(j, i.positionlist_end());
     154                 :         10 :     ++i;
     155 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(i, doc2.termlist_end());
     156                 :            : 
     157 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(doc2.values_count(), 1);
     158                 :         10 :     k = doc2.values_begin();
     159   [ -  +  #  # ]:         10 :     TEST_NOT_EQUAL(k, doc2.values_end());
     160 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(k.get_valueno(), 1);
     161 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(*k, "bar");
     162                 :         10 :     ++k;
     163   [ -  +  #  # ]:         10 :     TEST_EQUAL(k, doc2.values_end());
     164                 :            : 
     165 [ -  + ][ #  # ]:         10 :     TEST_EQUAL(doc2.get_data(), "baz");
     166                 :            :  
     167                 :         10 :     return true;
     168                 :            : }
     169                 :            : 
     170                 :            : // Test for serialising a query
     171                 :          1 : DEFINE_TESTCASE(serialise_query1, !backend) {
     172                 :          1 :     Xapian::Query q;
     173                 :          1 :     Xapian::Query q2 = Xapian::Query::unserialise(q.serialise());
     174 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), q2.get_description());
     175 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), "Xapian::Query()");
     176                 :            : 
     177                 :          1 :     q = Xapian::Query("hello");
     178                 :          1 :     q2 = Xapian::Query::unserialise(q.serialise());
     179 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), q2.get_description());
     180 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), "Xapian::Query(hello)");
     181                 :            : 
     182                 :          1 :     q = Xapian::Query(Xapian::Query::OP_OR, Xapian::Query("hello"), Xapian::Query("world"));
     183                 :          1 :     q2 = Xapian::Query::unserialise(q.serialise());
     184 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), q2.get_description());
     185 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), "Xapian::Query((hello OR world))");
     186                 :            : 
     187                 :          1 :     return true;
     188                 :            : }
     189                 :            : 
     190                 :            : // Test for serialising a query which contains a PostingSource.
     191                 :          1 : DEFINE_TESTCASE(serialise_query2, !backend) {
     192                 :          1 :     Xapian::ValueWeightPostingSource s1(10);
     193                 :          1 :     Xapian::Query q(&s1);
     194                 :          1 :     Xapian::Query q2 = Xapian::Query::unserialise(q.serialise());
     195 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), q2.get_description());
     196 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), "Xapian::Query(PostingSource(Xapian::ValueWeightPostingSource(slot=10)))");
     197                 :            : 
     198                 :          1 :     Xapian::ValueMapPostingSource s2(11);
     199                 :          1 :     s2.set_default_weight(5.0);
     200                 :          1 :     q = Xapian::Query(&s2);
     201                 :          1 :     q2 = Xapian::Query::unserialise(q.serialise());
     202 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), q2.get_description());
     203 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), "Xapian::Query(PostingSource(Xapian::ValueMapPostingSource(slot=11)))");
     204                 :            : 
     205                 :          1 :     Xapian::FixedWeightPostingSource s3(5.5);
     206                 :          1 :     q = Xapian::Query(&s3);
     207                 :          1 :     q2 = Xapian::Query::unserialise(q.serialise());
     208 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), q2.get_description());
     209 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), "Xapian::Query(PostingSource(Xapian::FixedWeightPostingSource(wt=5.5)))");
     210                 :            : 
     211                 :          1 :     return true;
     212                 :            : }
     213                 :            : 
     214                 :            : // Test for unserialising a query using the default registry.
     215                 :          1 : DEFINE_TESTCASE(serialise_query3, !backend) {
     216                 :          1 :     Xapian::ValueWeightPostingSource s1(10);
     217                 :          1 :     Xapian::Query q(&s1);
     218                 :          1 :     Xapian::Registry reg;
     219                 :          1 :     Xapian::Query q2 = Xapian::Query::unserialise(q.serialise(), reg);
     220 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), q2.get_description());
     221 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), "Xapian::Query(PostingSource(Xapian::ValueWeightPostingSource(slot=10)))");
     222                 :            : 
     223                 :          1 :     Xapian::ValueMapPostingSource s2(11);
     224                 :          1 :     s2.set_default_weight(5.0);
     225                 :          1 :     q = Xapian::Query(&s2);
     226                 :          1 :     q2 = Xapian::Query::unserialise(q.serialise(), reg);
     227 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), q2.get_description());
     228 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), "Xapian::Query(PostingSource(Xapian::ValueMapPostingSource(slot=11)))");
     229                 :            : 
     230                 :          1 :     Xapian::FixedWeightPostingSource s3(5.5);
     231                 :          1 :     q = Xapian::Query(&s3);
     232                 :          1 :     q2 = Xapian::Query::unserialise(q.serialise(), reg);
     233 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), q2.get_description());
     234 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), "Xapian::Query(PostingSource(Xapian::FixedWeightPostingSource(wt=5.5)))");
     235                 :            : 
     236                 :          1 :     return true;
     237                 :            : }
     238                 :            : 
     239 [ +  - ][ -  + ]:          8 : class MyPostingSource2 : public Xapian::ValuePostingSource {
     240                 :            :     std::string desc;
     241                 :            :   public:
     242                 :          8 :     MyPostingSource2(const std::string & desc_)
     243                 :          8 :             : Xapian::ValuePostingSource(0), desc(desc_)
     244                 :            :     {
     245                 :          8 :     }
     246                 :            : 
     247                 :          5 :     MyPostingSource2 * clone() const
     248                 :            :     {
     249                 :          5 :         return new MyPostingSource2(desc);
     250                 :            :     }
     251                 :            : 
     252                 :          5 :     std::string name() const {
     253                 :          5 :         return "MyPostingSource2";
     254                 :            :     }
     255                 :            : 
     256                 :          1 :     std::string serialise() const {
     257                 :          1 :         return desc;
     258                 :            :     }
     259                 :            : 
     260                 :          1 :     MyPostingSource2 * unserialise(const std::string & s) const {
     261                 :          1 :         return new MyPostingSource2(s);
     262                 :            :     }
     263                 :            : 
     264                 :          0 :     Xapian::weight get_weight() const { return 1.0; }
     265                 :            : 
     266                 :          3 :     std::string get_description() const {
     267                 :          3 :         return "MyPostingSource2(" + desc + ")";
     268                 :            :     }
     269                 :            : };
     270                 :            : 
     271                 :            : // Test for unserialising a query which contains a custom PostingSource.
     272                 :          1 : DEFINE_TESTCASE(serialise_query4, !backend) {
     273                 :          1 :     MyPostingSource2 s1("foo");
     274                 :          1 :     Xapian::Query q(&s1);
     275 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), "Xapian::Query(PostingSource(MyPostingSource2(foo)))");
     276                 :          1 :     std::string serialised = q.serialise();
     277                 :            : 
     278 [ +  - ][ -  + ]:          2 :     TEST_EXCEPTION(Xapian::InvalidArgumentError, Xapian::Query::unserialise(serialised));
         [ #  # ][ -  + ]
     279                 :          1 :     Xapian::Registry reg;
     280 [ +  - ][ -  + ]:          2 :     TEST_EXCEPTION(Xapian::InvalidArgumentError, Xapian::Query::unserialise(serialised, reg));
         [ #  # ][ -  + ]
     281                 :            : 
     282                 :          1 :     reg.register_posting_source(s1);
     283                 :          1 :     Xapian::Query q2 = Xapian::Query::unserialise(serialised, reg);
     284 [ -  + ][ #  # ]:          1 :     TEST_EQUAL(q.get_description(), q2.get_description());
     285                 :            : 
     286                 :          1 :     return true;
     287                 :            : }
     288                 :            : 
     289                 :            : /// Test for memory leaks when registering posting sources or weights twice.
     290                 :          1 : DEFINE_TESTCASE(double_register_leak, !backend) {
     291                 :          1 :     MyPostingSource2 s1("foo");
     292                 :          1 :     Xapian::BM25Weight w1;
     293                 :            : 
     294                 :          1 :     Xapian::Registry reg;
     295                 :          1 :     reg.register_posting_source(s1);
     296                 :          1 :     reg.register_posting_source(s1);
     297                 :          1 :     reg.register_posting_source(s1);
     298                 :            : 
     299                 :          1 :     reg.register_weighting_scheme(w1);
     300                 :          1 :     reg.register_weighting_scheme(w1);
     301                 :          1 :     reg.register_weighting_scheme(w1);
     302                 :            : 
     303                 :          1 :     return true;
     304                 :            : }
     305                 :            : 
     306                 :            : class ExceptionalPostingSource : public Xapian::PostingSource {
     307                 :            :   public:
     308                 :            :     typedef enum { NONE, CLONE, DTOR } failmode;
     309                 :            : 
     310                 :            :     failmode fail;
     311                 :            : 
     312                 :            :     PostingSource * & allocated;
     313                 :            : 
     314                 :          6 :     ExceptionalPostingSource(failmode fail_, PostingSource * & allocated_)
     315                 :          6 :         : fail(fail_), allocated(allocated_) { }
     316                 :            : 
     317                 :          6 :     ~ExceptionalPostingSource() {
     318 [ +  + ][ -  + ]:          6 :         if (fail == DTOR) {
     319                 :          1 :             throw runtime_error(string("arfle barfle gloop?"));
     320                 :            :         }
     321 [ +  - ][ -  + ]:          6 :     }
     322                 :            : 
     323                 :          4 :     string name() const {
     324                 :          4 :         return "ExceptionalPostingSource";
     325                 :            :     }
     326                 :            : 
     327                 :          3 :     PostingSource * clone() const {
     328         [ +  + ]:          3 :         if (fail == CLONE)
     329                 :          1 :             throw bad_alloc();
     330                 :          2 :         allocated = new ExceptionalPostingSource(fail, allocated);
     331                 :          2 :         return allocated;
     332                 :            :     }
     333                 :            : 
     334                 :          0 :     void init(const Xapian::Database &) { }
     335                 :            : 
     336                 :          0 :     Xapian::doccount get_termfreq_min() const { return 0; }
     337                 :          0 :     Xapian::doccount get_termfreq_est() const { return 1; }
     338                 :          0 :     Xapian::doccount get_termfreq_max() const { return 2; }
     339                 :            : 
     340                 :          0 :     void next(Xapian::weight) { }
     341                 :            : 
     342                 :          0 :     void skip_to(Xapian::docid, Xapian::weight) { }
     343                 :            : 
     344                 :          0 :     bool at_end() const { return true; }
     345                 :          0 :     Xapian::docid get_docid() const { return 0; }
     346                 :            : };
     347                 :            : 
     348                 :            : /// Check that exceptions when registering a postingsource are handled well.
     349                 :          1 : DEFINE_TESTCASE(registry1, !backend) {
     350                 :            :     // Test that a replacement object throwing bad_alloc is handled.
     351                 :            :     {
     352                 :          1 :         Xapian::Registry reg;
     353                 :            : 
     354                 :          1 :         Xapian::PostingSource * ptr = NULL;
     355                 :          1 :         ExceptionalPostingSource eps(ExceptionalPostingSource::NONE, ptr);
     356 [ +  - ][ -  + ]:          2 :         TEST_EXCEPTION(Xapian::UnimplementedError, eps.serialise());
         [ #  # ][ -  + ]
     357 [ +  - ][ -  + ]:          3 :         TEST_EXCEPTION(Xapian::UnimplementedError, eps.unserialise(string()));
         [ #  # ][ -  + ]
     358                 :          1 :         reg.register_posting_source(eps);
     359                 :            :         try {
     360                 :          1 :             Xapian::PostingSource * ptr_clone = NULL;
     361                 :            :             ExceptionalPostingSource eps_clone(ExceptionalPostingSource::CLONE,
     362                 :          1 :                                                ptr_clone);
     363                 :          1 :             reg.register_posting_source(eps_clone);
     364                 :          1 :             return false;
     365                 :          1 :         } catch (const bad_alloc &) {
     366                 :            :         }
     367                 :            : 
     368                 :            :         // Either the old entry should be removed, or it should work.
     369                 :            :         const Xapian::PostingSource * p;
     370                 :          1 :         p = reg.get_posting_source("ExceptionalPostingSource");
     371         [ -  + ]:          1 :         if (p) {
     372 [ #  # ][ #  # ]:          1 :             TEST_EQUAL(p->name(), "ExceptionalPostingSource");
     373 [ -  + ][ +  - ]:          1 :         }
     374                 :            :     }
     375                 :            : 
     376                 :            :     // Test that the replaced object throwing runtime_error is handled.
     377                 :            :     {
     378                 :          1 :         Xapian::Registry reg;
     379                 :            : 
     380                 :          1 :         Xapian::PostingSource * ptr_dtor = NULL;
     381                 :            :         ExceptionalPostingSource eps_dtor(ExceptionalPostingSource::DTOR,
     382                 :          1 :                                           ptr_dtor);
     383                 :          1 :         reg.register_posting_source(eps_dtor);
     384                 :            :         // Prevent eps_dtor's dtor from throwing an exception.
     385                 :          1 :         eps_dtor.fail = ExceptionalPostingSource::NONE;
     386                 :            : 
     387                 :            :         try {
     388                 :          1 :             Xapian::PostingSource * ptr = NULL;
     389                 :          1 :             ExceptionalPostingSource eps(ExceptionalPostingSource::NONE, ptr);
     390                 :          1 :             reg.register_posting_source(eps);
     391                 :          1 :             return false;
     392                 :          1 :         } catch (const runtime_error &) {
     393                 :            :         }
     394                 :            : 
     395                 :            :         // Either the old entry should be removed, or it should work.
     396                 :            :         const Xapian::PostingSource * p;
     397                 :          1 :         p = reg.get_posting_source("ExceptionalPostingSource");
     398         [ -  + ]:          1 :         if (p) {
     399 [ #  # ][ #  # ]:          0 :             TEST_EQUAL(p->name(), "ExceptionalPostingSource");
     400                 :            :         }
     401                 :            : 
     402                 :            :         // Because the destructor threw an exception, the memory allocated for
     403                 :            :         // the object didn't get released.
     404 [ -  + ][ +  - ]:          1 :         operator delete(ptr_dtor);
     405                 :            :     }
     406                 :            : 
     407                 :          1 :     return true;
     408                 :            : }
     409                 :            : 
     410                 :            : class ExceptionalWeight : public Xapian::Weight {
     411                 :            :   public:
     412                 :            :     typedef enum { NONE, CLONE, DTOR } failmode;
     413                 :            : 
     414                 :            :     failmode fail;
     415                 :            : 
     416                 :            :     Weight * & allocated;
     417                 :            : 
     418                 :          6 :     ExceptionalWeight(failmode fail_, Weight * & allocated_)
     419                 :          6 :         : fail(fail_), allocated(allocated_) { }
     420                 :            : 
     421                 :          6 :     ~ExceptionalWeight() {
     422 [ +  + ][ -  + ]:          6 :         if (fail == DTOR) {
     423                 :          1 :             throw runtime_error(string("arfle barfle gloop?"));
     424                 :            :         }
     425 [ +  - ][ -  + ]:          6 :     }
     426                 :            : 
     427                 :          4 :     string name() const {
     428                 :          4 :         return "ExceptionalWeight";
     429                 :            :     }
     430                 :            : 
     431                 :          3 :     Weight * clone() const {
     432         [ +  + ]:          3 :         if (fail == CLONE)
     433                 :          1 :             throw bad_alloc();
     434                 :          2 :         allocated = new ExceptionalWeight(fail, allocated);
     435                 :          2 :         return allocated;
     436                 :            :     }
     437                 :            : 
     438                 :          0 :     void init(double) { }
     439                 :            : 
     440                 :          0 :     Xapian::weight get_sumpart(Xapian::termcount, Xapian::termcount) const {
     441                 :          0 :         return 0;
     442                 :            :     }
     443                 :          0 :     Xapian::weight get_maxpart() const { return 0; }
     444                 :            : 
     445                 :          0 :     Xapian::weight get_sumextra(Xapian::termcount) const { return 0; }
     446                 :          0 :     Xapian::weight get_maxextra() const { return 0; }
     447                 :            : };
     448                 :            : 
     449                 :            : /// Check that exceptions when registering are handled well.
     450                 :          1 : DEFINE_TESTCASE(registry2, !backend) {
     451                 :            :     // Test that a replacement object throwing bad_alloc is handled.
     452                 :            :     {
     453                 :          1 :         Xapian::Registry reg;
     454                 :            : 
     455                 :          1 :         Xapian::Weight * ptr = NULL;
     456                 :          1 :         ExceptionalWeight ewt(ExceptionalWeight::NONE, ptr);
     457                 :          1 :         reg.register_weighting_scheme(ewt);
     458                 :            :         try {
     459                 :          1 :             Xapian::Weight * ptr_clone = NULL;
     460                 :            :             ExceptionalWeight ewt_clone(ExceptionalWeight::CLONE,
     461                 :          1 :                                                ptr_clone);
     462                 :          1 :             reg.register_weighting_scheme(ewt_clone);
     463                 :          1 :             return false;
     464                 :          1 :         } catch (const bad_alloc &) {
     465                 :            :         }
     466                 :            : 
     467                 :            :         // Either the old entry should be removed, or it should work.
     468                 :            :         const Xapian::Weight * p;
     469                 :          1 :         p = reg.get_weighting_scheme("ExceptionalWeight");
     470         [ -  + ]:          1 :         if (p) {
     471 [ #  # ][ #  # ]:          1 :             TEST_EQUAL(p->name(), "ExceptionalWeight");
     472 [ -  + ][ +  - ]:          1 :         }
     473                 :            :     }
     474                 :            : 
     475                 :            :     // Test that the replaced object throwing runtime_error is handled.
     476                 :            :     {
     477                 :          1 :         Xapian::Registry reg;
     478                 :            : 
     479                 :          1 :         Xapian::Weight * ptr_dtor = NULL;
     480                 :            :         ExceptionalWeight ewt_dtor(ExceptionalWeight::DTOR,
     481                 :          1 :                                           ptr_dtor);
     482                 :          1 :         reg.register_weighting_scheme(ewt_dtor);
     483                 :            :         // Prevent ewt_dtor's dtor from throwing an exception.
     484                 :          1 :         ewt_dtor.fail = ExceptionalWeight::NONE;
     485                 :            : 
     486                 :            :         try {
     487                 :          1 :             Xapian::Weight * ptr = NULL;
     488                 :          1 :             ExceptionalWeight ewt(ExceptionalWeight::NONE, ptr);
     489                 :          1 :             reg.register_weighting_scheme(ewt);
     490                 :          1 :             return false;
     491                 :          1 :         } catch (const runtime_error &) {
     492                 :            :         }
     493                 :            : 
     494                 :            :         // Either the old entry should be removed, or it should work.
     495                 :            :         const Xapian::Weight * p;
     496                 :          1 :         p = reg.get_weighting_scheme("ExceptionalWeight");
     497         [ -  + ]:          1 :         if (p) {
     498 [ #  # ][ #  # ]:          0 :             TEST_EQUAL(p->name(), "ExceptionalWeight");
     499                 :            :         }
     500                 :            : 
     501                 :            :         // Because the destructor threw an exception, the memory allocated for
     502                 :            :         // the object didn't get released.
     503 [ -  + ][ +  - ]:          1 :         operator delete(ptr_dtor);
     504                 :            :     }
     505                 :            : 
     506                 :          1 :     return true;
     507                 :            : }
     508                 :            : 
     509                 :            : class ExceptionalMatchSpy : public Xapian::MatchSpy {
     510                 :            :   public:
     511                 :            :     typedef enum { NONE, CLONE, DTOR } failmode;
     512                 :            : 
     513                 :            :     failmode fail;
     514                 :            : 
     515                 :            :     MatchSpy * & allocated;
     516                 :            : 
     517                 :          6 :     ExceptionalMatchSpy(failmode fail_, MatchSpy * & allocated_)
     518                 :          6 :         : fail(fail_), allocated(allocated_) { }
     519                 :            : 
     520                 :          6 :     ~ExceptionalMatchSpy() {
     521 [ +  + ][ -  + ]:          6 :         if (fail == DTOR) {
     522                 :          1 :             throw runtime_error(string("arfle barfle gloop?"));
     523                 :            :         }
     524 [ +  - ][ -  + ]:          6 :     }
     525                 :            : 
     526                 :          4 :     string name() const {
     527                 :          4 :         return "ExceptionalMatchSpy";
     528                 :            :     }
     529                 :            : 
     530                 :          3 :     MatchSpy * clone() const {
     531         [ +  + ]:          3 :         if (fail == CLONE)
     532                 :          1 :             throw bad_alloc();
     533                 :          2 :         allocated = new ExceptionalMatchSpy(fail, allocated);
     534                 :          2 :         return allocated;
     535                 :            :     }
     536                 :            : 
     537                 :          0 :     void operator()(const Xapian::Document &, Xapian::weight) {
     538                 :          0 :     }
     539                 :            : };
     540                 :            : 
     541                 :            : /// Check that exceptions when registering are handled well.
     542                 :          1 : DEFINE_TESTCASE(registry3, !backend) {
     543                 :            :     // Test that a replacement object throwing bad_alloc is handled.
     544                 :            :     {
     545                 :          1 :         Xapian::Registry reg;
     546                 :            : 
     547                 :          1 :         Xapian::MatchSpy * ptr = NULL;
     548                 :          1 :         ExceptionalMatchSpy ems(ExceptionalMatchSpy::NONE, ptr);
     549                 :          1 :         reg.register_match_spy(ems);
     550                 :            :         try {
     551                 :          1 :             Xapian::MatchSpy * ptr_clone = NULL;
     552                 :            :             ExceptionalMatchSpy ems_clone(ExceptionalMatchSpy::CLONE,
     553                 :          1 :                                           ptr_clone);
     554                 :          1 :             reg.register_match_spy(ems_clone);
     555                 :          1 :             return false;
     556                 :          1 :         } catch (const bad_alloc &) {
     557                 :            :         }
     558                 :            : 
     559                 :            :         // Either the old entry should be removed, or it should work.
     560                 :            :         const Xapian::MatchSpy * p;
     561                 :          1 :         p = reg.get_match_spy("ExceptionalMatchSpy");
     562         [ -  + ]:          1 :         if (p) {
     563 [ #  # ][ #  # ]:          1 :             TEST_EQUAL(p->name(), "ExceptionalMatchSpy");
     564 [ -  + ][ +  - ]:          1 :         }
     565                 :            :     }
     566                 :            : 
     567                 :            :     // Test that the replaced object throwing runtime_error is handled.
     568                 :            :     {
     569                 :          1 :         Xapian::Registry reg;
     570                 :            : 
     571                 :          1 :         Xapian::MatchSpy * ptr_dtor = NULL;
     572                 :          1 :         ExceptionalMatchSpy ems_dtor(ExceptionalMatchSpy::DTOR, ptr_dtor);
     573                 :          1 :         reg.register_match_spy(ems_dtor);
     574                 :            :         // Prevent ems_dtor's dtor from throwing an exception.
     575                 :          1 :         ems_dtor.fail = ExceptionalMatchSpy::NONE;
     576                 :            : 
     577                 :            :         try {
     578                 :          1 :             Xapian::MatchSpy * ptr = NULL;
     579                 :          1 :             ExceptionalMatchSpy ems(ExceptionalMatchSpy::NONE, ptr);
     580                 :          1 :             reg.register_match_spy(ems);
     581                 :          1 :             return false;
     582                 :          1 :         } catch (const runtime_error &) {
     583                 :            :         }
     584                 :            : 
     585                 :            :         // Either the old entry should be removed, or it should work.
     586                 :            :         const Xapian::MatchSpy * p;
     587                 :          1 :         p = reg.get_match_spy("ExceptionalMatchSpy");
     588         [ -  + ]:          1 :         if (p) {
     589 [ #  # ][ #  # ]:          0 :             TEST_EQUAL(p->name(), "ExceptionalMatchSpy");
     590                 :            :         }
     591                 :            : 
     592                 :            :         // Because the destructor threw an exception, the memory allocated for
     593                 :            :         // the object didn't get released.
     594 [ -  + ][ +  - ]:          1 :         operator delete(ptr_dtor);
     595                 :            :     }
     596                 :            : 
     597                 :          1 :     return true;
     598                 :            : }

Generated by: LCOV version 1.8