LCOV - code coverage report
Current view: top level - tests - api_none.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core 7028d852e609 Lines: 523 531 98.5 %
Date: 2019-02-17 14:59:59 Functions: 38 43 88.4 %
Branches: 749 5954 12.6 %

           Branch data     Line data    Source code
       1                 :            : /** @file api_none.cc
       2                 :            :  * @brief tests which don't need a backend
       3                 :            :  */
       4                 :            : /* Copyright (C) 2009 Richard Boulton
       5                 :            :  * Copyright (C) 2009,2010,2011,2013,2014,2015,2016,2017,2018 Olly Betts
       6                 :            :  *
       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.
      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
      20                 :            :  * USA
      21                 :            :  */
      22                 :            : 
      23                 :            : #include <config.h>
      24                 :            : 
      25                 :            : #include "api_none.h"
      26                 :            : 
      27                 :            : #define XAPIAN_DEPRECATED(D) D
      28                 :            : #include <xapian.h>
      29                 :            : 
      30                 :            : #include "apitest.h"
      31                 :            : #include "str.h"
      32                 :            : #include "testsuite.h"
      33                 :            : #include "testutils.h"
      34                 :            : 
      35                 :            : using namespace std;
      36                 :            : 
      37                 :            : // Check the version functions give consistent results.
      38                 :          1 : DEFINE_TESTCASE(version1, !backend) {
      39         [ +  - ]:          1 :     string version = str(Xapian::major_version());
      40         [ +  - ]:          1 :     version += '.';
      41 [ +  - ][ +  - ]:          1 :     version += str(Xapian::minor_version());
      42         [ +  - ]:          1 :     version += '.';
      43 [ +  - ][ +  - ]:          1 :     version += str(Xapian::revision());
      44 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(Xapian::version_string(), version);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      45                 :          1 :     return true;
      46                 :            : }
      47                 :            : 
      48                 :            : // Regression test: various methods on Database() used to segfault or cause
      49                 :            : // division by 0.  Fixed in 1.1.4 and 1.0.18.  Ticket#415.
      50                 :          1 : DEFINE_TESTCASE(nosubdatabases1, !backend) {
      51         [ +  - ]:          1 :     Xapian::Database db;
      52 [ +  - ][ +  - ]:          1 :     TEST(db.get_metadata("foo").empty());
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      53 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(db.metadata_keys_begin(), db.metadata_keys_end());
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      54 [ +  - ][ -  + ]:          1 :     TEST_EXCEPTION(Xapian::InvalidOperationError, db.termlist_begin(1));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ -  + ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
                 [ +  - ]
      55 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(db.allterms_begin(), db.allterms_end());
         [ +  - ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
      56 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(db.allterms_begin("foo"), db.allterms_end("foo"));
         [ +  - ][ -  +  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                      # ]
      57 [ +  - ][ +  - ]:          1 :     TEST_EXCEPTION(Xapian::InvalidOperationError, db.positionlist_begin(1, "foo"));
           [ -  +  #  #  
          #  #  #  #  #  
             #  #  #  #  
              # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
      58 [ +  - ][ -  +  :          1 :     TEST_EQUAL(db.get_lastdocid(), 0);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
      59 [ +  - ][ -  +  :          1 :     TEST_EQUAL(db.valuestream_begin(7), db.valuestream_end(7));
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
      60 [ +  - ][ -  +  :          1 :     TEST_EXCEPTION(Xapian::InvalidOperationError, db.get_doclength(1));
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
      61 [ +  - ][ -  +  :          1 :     TEST_EXCEPTION(Xapian::InvalidOperationError, db.get_unique_terms(1));
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
      62 [ +  - ][ -  +  :          1 :     TEST_EXCEPTION(Xapian::InvalidOperationError, db.get_document(1));
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
      63                 :          1 :     return true;
      64                 :            : }
      65                 :            : 
      66                 :            : /// Feature test for Document::add_boolean_term(), new in 1.0.18/1.1.4.
      67                 :          1 : DEFINE_TESTCASE(document1, !backend) {
      68         [ +  - ]:          1 :     Xapian::Document doc;
      69 [ +  - ][ +  - ]:          1 :     doc.add_boolean_term("Hxapian.org");
      70 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(doc.termlist_count(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      71         [ +  - ]:          2 :     Xapian::TermIterator t = doc.termlist_begin();
      72 [ -  + ][ #  # ]:          1 :     TEST(t != doc.termlist_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      73 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(*t, "Hxapian.org");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
      74 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(t.get_wdf(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      75 [ +  - ][ -  + ]:          1 :     TEST(++t == doc.termlist_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      76 [ +  - ][ +  - ]:          1 :     doc.remove_term("Hxapian.org");
      77 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(doc.termlist_count(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      78 [ +  - ][ -  + ]:          1 :     TEST(doc.termlist_begin() == doc.termlist_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      79                 :          1 :     return true;
      80                 :            : }
      81                 :            : 
      82                 :            : /// Regression test - the docid wasn't initialised prior to 1.0.22/1.2.4.
      83                 :          1 : DEFINE_TESTCASE(document2, !backend) {
      84         [ +  - ]:          1 :     Xapian::Document doc;
      85                 :            :     // The return value is uninitialised, so running under valgrind this
      86                 :            :     // will fail reliably prior to the fix.
      87 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(doc.get_docid(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
      88                 :          1 :     return true;
      89                 :            : }
      90                 :            : 
      91                 :            : /// Feature tests for Document::clear_terms().
      92                 :          1 : DEFINE_TESTCASE(documentclearterms1, !backend) {
      93                 :            :     {
      94         [ +  - ]:          1 :         Xapian::Document doc;
      95 [ +  - ][ +  - ]:          1 :         doc.add_boolean_term("Hlocalhost");
      96 [ +  - ][ +  - ]:          1 :         doc.add_term("hello");
      97 [ +  - ][ +  - ]:          1 :         doc.add_term("there", 2);
      98 [ +  - ][ +  - ]:          1 :         doc.add_posting("positional", 1);
      99 [ +  - ][ +  - ]:          1 :         doc.add_posting("information", 2, 3);
     100 [ +  - ][ -  + ]:          1 :         TEST_EQUAL(doc.termlist_count(), 5);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     101 [ +  - ][ -  + ]:          1 :         TEST(doc.termlist_begin() != doc.termlist_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     102         [ +  - ]:          1 :         doc.clear_terms();
     103 [ +  - ][ -  + ]:          1 :         TEST_EQUAL(doc.termlist_count(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     104 [ +  - ][ -  + ]:          1 :         TEST(doc.termlist_begin() == doc.termlist_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     105                 :            :         // Test clear_terms() when there are no terms.
     106         [ +  - ]:          1 :         doc.clear_terms();
     107 [ +  - ][ -  + ]:          1 :         TEST_EQUAL(doc.termlist_count(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     108 [ +  - ][ -  + ]:          1 :         TEST(doc.termlist_begin() == doc.termlist_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     109                 :            :     }
     110                 :            : 
     111                 :            :     {
     112                 :            :         // Test clear_terms() when there have never been any terms.
     113         [ +  - ]:          1 :         Xapian::Document doc;
     114         [ +  - ]:          1 :         doc.clear_terms();
     115 [ +  - ][ -  + ]:          1 :         TEST_EQUAL(doc.termlist_count(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     116 [ +  - ][ -  + ]:          1 :         TEST(doc.termlist_begin() == doc.termlist_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     117                 :            :     }
     118                 :            : 
     119                 :          1 :     return true;
     120                 :            : }
     121                 :            : 
     122                 :            : /// Feature tests for Document::clear_values().
     123                 :          1 : DEFINE_TESTCASE(documentclearvalues1, !backend) {
     124                 :            :     {
     125         [ +  - ]:          1 :         Xapian::Document doc;
     126 [ +  - ][ +  - ]:          1 :         doc.add_value(37, "hello");
     127 [ +  - ][ +  - ]:          1 :         doc.add_value(42, "world");
     128 [ +  - ][ -  + ]:          1 :         TEST_EQUAL(doc.values_count(), 2);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     129 [ +  - ][ -  + ]:          1 :         TEST(doc.values_begin() != doc.values_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     130         [ +  - ]:          1 :         doc.clear_values();
     131 [ +  - ][ -  + ]:          1 :         TEST_EQUAL(doc.values_count(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     132 [ +  - ][ -  + ]:          1 :         TEST(doc.values_begin() == doc.values_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     133                 :            :         // Test clear_values() when there are no values.
     134         [ +  - ]:          1 :         doc.clear_values();
     135 [ +  - ][ -  + ]:          1 :         TEST_EQUAL(doc.values_count(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     136 [ +  - ][ -  + ]:          1 :         TEST(doc.values_begin() == doc.values_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     137                 :            :     }
     138                 :            : 
     139                 :            :     {
     140                 :            :         // Test clear_values() when there have never been any values.
     141         [ +  - ]:          1 :         Xapian::Document doc;
     142         [ +  - ]:          1 :         doc.clear_values();
     143 [ +  - ][ -  + ]:          1 :         TEST_EQUAL(doc.values_count(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     144 [ +  - ][ -  + ]:          1 :         TEST(doc.termlist_begin() == doc.termlist_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     145                 :            :     }
     146                 :            : 
     147                 :          1 :     return true;
     148                 :            : }
     149                 :            : 
     150                 :            : /// Feature tests for errors for empty terms.
     151                 :          1 : DEFINE_TESTCASE(documentemptyterm1, !backend) {
     152         [ +  - ]:          1 :     Xapian::Document doc;
     153 [ +  - ][ +  - ]:          1 :     TEST_EXCEPTION(Xapian::InvalidArgumentError,
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     154                 :            :             doc.add_boolean_term(string()));
     155 [ +  - ][ +  - ]:          1 :     TEST_EXCEPTION(Xapian::InvalidArgumentError,
           [ -  +  #  #  
          #  #  #  #  #  
             #  #  #  #  
              # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     156                 :            :             doc.add_term(string()));
     157 [ +  - ][ +  - ]:          1 :     TEST_EXCEPTION(Xapian::InvalidArgumentError,
           [ -  +  #  #  
          #  #  #  #  #  
             #  #  #  #  
              # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     158                 :            :             doc.add_posting(string(), 1));
     159 [ +  - ][ +  - ]:          1 :     TEST_EXCEPTION(Xapian::InvalidArgumentError,
           [ -  +  #  #  
          #  #  #  #  #  
             #  #  #  #  
              # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     160                 :            :             doc.add_posting(string(), 2, 3));
     161 [ +  - ][ +  - ]:          1 :     TEST_EXCEPTION(Xapian::InvalidArgumentError,
           [ -  +  #  #  
          #  #  #  #  #  
             #  #  #  #  
              # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     162                 :            :             doc.remove_term(string()));
     163 [ +  - ][ +  - ]:          1 :     TEST_EXCEPTION(Xapian::InvalidArgumentError,
           [ -  +  #  #  
          #  #  #  #  #  
             #  #  #  #  
              # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     164                 :            :             doc.remove_posting(string(), 1));
     165 [ +  - ][ +  - ]:          1 :     TEST_EXCEPTION(Xapian::InvalidArgumentError,
           [ -  +  #  #  
          #  #  #  #  #  
             #  #  #  #  
              # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     166                 :            :             doc.remove_posting(string(), 2, 3));
     167 [ +  - ][ +  - ]:          1 :     TEST_EXCEPTION(Xapian::InvalidArgumentError,
           [ -  +  #  #  
          #  #  #  #  #  
             #  #  #  #  
              # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     168                 :            :             doc.remove_postings(string(), 2, 3));
     169 [ +  - ][ +  - ]:          1 :     TEST_EXCEPTION(Xapian::InvalidArgumentError,
           [ -  +  #  #  
          #  #  #  #  #  
             #  #  #  #  
              # ][ -  + ]
           [ -  +  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
           #  # ][ +  - ]
     170                 :            :             doc.remove_postings(string(), 2, 3, 4));
     171                 :          1 :     return true;
     172                 :            : }
     173                 :            : 
     174                 :          1 : DEFINE_TESTCASE(emptyquery4, !backend) {
     175                 :            :     // Test we get an empty query from applying any of the following ops to
     176                 :            :     // an empty list of subqueries.
     177                 :          1 :     Xapian::Query q;
     178 [ +  - ][ -  + ]:          1 :     TEST(Xapian::Query(q.OP_AND, &q, &q).empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     179 [ +  - ][ -  + ]:          1 :     TEST(Xapian::Query(q.OP_OR, &q, &q).empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     180 [ +  - ][ -  + ]:          1 :     TEST(Xapian::Query(q.OP_AND_NOT, &q, &q).empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     181 [ +  - ][ -  + ]:          1 :     TEST(Xapian::Query(q.OP_XOR, &q, &q).empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     182 [ +  - ][ -  + ]:          1 :     TEST(Xapian::Query(q.OP_AND_MAYBE, &q, &q).empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     183 [ +  - ][ -  + ]:          1 :     TEST(Xapian::Query(q.OP_FILTER, &q, &q).empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     184 [ +  - ][ -  + ]:          1 :     TEST(Xapian::Query(q.OP_NEAR, &q, &q).empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     185 [ +  - ][ -  + ]:          1 :     TEST(Xapian::Query(q.OP_PHRASE, &q, &q).empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     186 [ +  - ][ -  + ]:          1 :     TEST(Xapian::Query(q.OP_ELITE_SET, &q, &q).empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     187 [ +  - ][ -  + ]:          1 :     TEST(Xapian::Query(q.OP_SYNONYM, &q, &q).empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     188 [ +  - ][ -  + ]:          1 :     TEST(Xapian::Query(q.OP_MAX, &q, &q).empty());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     189                 :          1 :     return true;
     190                 :            : }
     191                 :            : 
     192                 :          1 : DEFINE_TESTCASE(singlesubquery1, !backend) {
     193                 :            :     // Test that we get just the subquery if we apply any of the following
     194                 :            :     // ops to just that subquery.
     195                 :            : #define singlesubquery1_(OP) \
     196                 :            :     TEST_STRINGS_EQUAL(Xapian::Query(q->OP, q, q + 1).get_description(),\
     197                 :            :         "Query(test)")
     198 [ +  - ][ +  - ]:          2 :     Xapian::Query q[1] = { Xapian::Query("test") };
           [ #  #  #  # ]
     199 [ +  - ][ +  - ]:          1 :     singlesubquery1_(OP_AND);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     200 [ +  - ][ +  - ]:          1 :     singlesubquery1_(OP_OR);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     201 [ +  - ][ +  - ]:          1 :     singlesubquery1_(OP_AND_NOT);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     202 [ +  - ][ +  - ]:          1 :     singlesubquery1_(OP_XOR);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     203 [ +  - ][ +  - ]:          1 :     singlesubquery1_(OP_AND_MAYBE);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     204 [ +  - ][ +  - ]:          1 :     singlesubquery1_(OP_FILTER);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     205 [ +  - ][ +  - ]:          1 :     singlesubquery1_(OP_NEAR);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     206 [ +  - ][ +  - ]:          1 :     singlesubquery1_(OP_PHRASE);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     207 [ +  - ][ +  - ]:          1 :     singlesubquery1_(OP_ELITE_SET);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     208 [ +  - ][ +  - ]:          1 :     singlesubquery1_(OP_SYNONYM);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     209 [ +  - ][ +  - ]:          1 :     singlesubquery1_(OP_MAX);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     210 [ +  + ][ #  # ]:          2 :     return true;
     211                 :            : }
     212                 :            : 
     213                 :          1 : DEFINE_TESTCASE(singlesubquery2, !backend) {
     214                 :            :     // Like the previous test, but using MatchNothing as the subquery.
     215                 :            : #define singlesubquery2_(OP) \
     216                 :            :     TEST_STRINGS_EQUAL(Xapian::Query(q->OP, q, q + 1).get_description(),\
     217                 :            :         "Query()")
     218 [ +  - ][ #  # ]:          2 :     Xapian::Query q[1] = { Xapian::Query::MatchNothing };
     219 [ +  - ][ +  - ]:          1 :     singlesubquery2_(OP_AND);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     220 [ +  - ][ +  - ]:          1 :     singlesubquery2_(OP_OR);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     221 [ +  - ][ +  - ]:          1 :     singlesubquery2_(OP_AND_NOT);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     222 [ +  - ][ +  - ]:          1 :     singlesubquery2_(OP_XOR);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     223 [ +  - ][ +  - ]:          1 :     singlesubquery2_(OP_AND_MAYBE);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     224 [ +  - ][ +  - ]:          1 :     singlesubquery2_(OP_FILTER);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     225 [ +  - ][ +  - ]:          1 :     singlesubquery2_(OP_NEAR);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     226 [ +  - ][ +  - ]:          1 :     singlesubquery2_(OP_PHRASE);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     227 [ +  - ][ +  - ]:          1 :     singlesubquery2_(OP_ELITE_SET);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     228 [ +  - ][ +  - ]:          1 :     singlesubquery2_(OP_SYNONYM);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     229 [ +  - ][ +  - ]:          1 :     singlesubquery2_(OP_MAX);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     230         [ +  + ]:          2 :     return true;
           [ #  #  #  # ]
     231                 :            : }
     232                 :            : 
     233                 :          1 : DEFINE_TESTCASE(singlesubquery3, !backend) {
     234                 :            :     // Like the previous test, but using MatchAll as the subquery.
     235                 :            : #define singlesubquery3_(OP) \
     236                 :            :     TEST_STRINGS_EQUAL(Xapian::Query(q->OP, q, q + 1).get_description(),\
     237                 :            :         "Query(<alldocuments>)")
     238 [ +  - ][ #  # ]:          2 :     Xapian::Query q[1] = { Xapian::Query::MatchAll };
     239 [ +  - ][ +  - ]:          1 :     singlesubquery3_(OP_AND);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     240 [ +  - ][ +  - ]:          1 :     singlesubquery3_(OP_OR);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     241 [ +  - ][ +  - ]:          1 :     singlesubquery3_(OP_AND_NOT);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     242 [ +  - ][ +  - ]:          1 :     singlesubquery3_(OP_XOR);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     243 [ +  - ][ +  - ]:          1 :     singlesubquery3_(OP_AND_MAYBE);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     244 [ +  - ][ +  - ]:          1 :     singlesubquery3_(OP_FILTER);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     245                 :            :     // OP_NEAR and OP_PHRASE over MatchAll doesn't really make sense.
     246 [ +  - ][ +  - ]:          1 :     singlesubquery3_(OP_ELITE_SET);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     247 [ +  - ][ +  - ]:          1 :     singlesubquery3_(OP_SYNONYM);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     248 [ +  - ][ +  - ]:          1 :     singlesubquery3_(OP_MAX);
         [ +  - ][ -  + ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     249         [ +  + ]:          2 :     return true;
           [ #  #  #  # ]
     250                 :            : }
     251                 :            : 
     252                 :            : /// Check we no longer combine wqf for same term at the same position.
     253                 :          1 : DEFINE_TESTCASE(combinewqfnomore1, !backend) {
     254                 :            :     Xapian::Query q(Xapian::Query::OP_OR,
     255                 :            :                     Xapian::Query("beer", 1, 1),
     256 [ +  - ][ +  - ]:          1 :                     Xapian::Query("beer", 1, 1));
         [ +  - ][ +  - ]
                 [ +  - ]
     257                 :            :     // Prior to 1.3.0, we would have given beer@2, but we decided that wasn't
     258                 :            :     // really useful or helpful.
     259 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(q.get_description(), "Query((beer@1 OR beer@1))");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     260                 :          1 :     return true;
     261                 :            : }
     262                 :            : 
     263                 :            : class DestroyedFlag {
     264                 :            :     bool & destroyed;
     265                 :            : 
     266                 :            :   public:
     267                 :        175 :     DestroyedFlag(bool & destroyed_) : destroyed(destroyed_) {
     268                 :        175 :         destroyed = false;
     269                 :        175 :     }
     270                 :            : 
     271                 :        175 :     ~DestroyedFlag() {
     272                 :        175 :         destroyed = true;
     273                 :        175 :     }
     274                 :            : };
     275                 :            : 
     276         [ -  + ]:         18 : class TestRangeProcessor : public Xapian::RangeProcessor {
     277                 :            :     DestroyedFlag destroyed;
     278                 :            : 
     279                 :            :   public:
     280                 :          5 :     TestRangeProcessor(bool & destroyed_)
     281         [ +  - ]:          5 :         : Xapian::RangeProcessor(0), destroyed(destroyed_) { }
     282                 :            : 
     283                 :          0 :     Xapian::Query operator()(const std::string&, const std::string&)
     284                 :            :     {
     285                 :          0 :         return Xapian::Query::MatchAll;
     286                 :            :     }
     287                 :            : };
     288                 :            : 
     289                 :            : /// Check reference counting of user-subclassable classes.
     290                 :          1 : DEFINE_TESTCASE(subclassablerefcount1, !backend) {
     291                 :            :     bool gone_auto, gone;
     292                 :            : 
     293                 :            :     // Simple test of release().
     294                 :            :     {
     295 [ +  - ][ +  - ]:          1 :         Xapian::RangeProcessor * rp = new TestRangeProcessor(gone);
     296 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     297         [ +  - ]:          1 :         Xapian::QueryParser qp;
     298         [ +  - ]:          1 :         qp.add_rangeprocessor(rp->release());
     299 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     300                 :            :     }
     301 [ -  + ][ #  # ]:          1 :     TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     302                 :            : 
     303                 :            :     // Check a second call to release() has no effect.
     304                 :            :     {
     305 [ +  - ][ +  - ]:          1 :         Xapian::RangeProcessor * rp = new TestRangeProcessor(gone);
     306 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     307         [ +  - ]:          1 :         Xapian::QueryParser qp;
     308         [ +  - ]:          1 :         qp.add_rangeprocessor(rp->release());
     309                 :          1 :         rp->release();
     310 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     311                 :            :     }
     312 [ -  + ][ #  # ]:          1 :     TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     313                 :            : 
     314                 :            :     // Test reference counting works, and that a RangeProcessor with automatic
     315                 :            :     // storage works OK.
     316                 :            :     {
     317         [ +  - ]:          1 :         TestRangeProcessor rp_auto(gone_auto);
     318 [ -  + ][ #  # ]:          1 :         TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     319                 :            :         {
     320         [ +  - ]:          1 :             Xapian::QueryParser qp1;
     321                 :            :             {
     322         [ +  - ]:          1 :                 Xapian::QueryParser qp2;
     323                 :            :                 Xapian::RangeProcessor * rp;
     324 [ +  - ][ +  - ]:          1 :                 rp = new TestRangeProcessor(gone);
     325 [ -  + ][ #  # ]:          1 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     326         [ +  - ]:          1 :                 qp1.add_rangeprocessor(rp->release());
     327 [ -  + ][ #  # ]:          1 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     328         [ +  - ]:          1 :                 qp2.add_rangeprocessor(rp);
     329 [ -  + ][ #  # ]:          1 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     330         [ +  - ]:          1 :                 qp2.add_rangeprocessor(&rp_auto);
     331 [ -  + ][ #  # ]:          1 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     332 [ -  + ][ #  # ]:          1 :                 TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     333                 :            :             }
     334 [ -  + ][ #  # ]:          1 :             TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     335                 :            :         }
     336 [ -  + ][ #  # ]:          1 :         TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     337 [ -  + ][ #  # ]:          1 :         TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     338                 :            :     }
     339 [ -  + ][ #  # ]:          1 :     TEST(gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     340                 :            : 
     341                 :            :     // Regression test for initial implementation, where ~opt_intrusive_ptr()
     342                 :            :     // checked the reference of the object, which may have already been deleted
     343                 :            :     // if it wasn't been reference counted.
     344                 :            :     {
     345         [ +  - ]:          1 :         Xapian::QueryParser qp;
     346                 :            :         {
     347 [ +  - ][ +  - ]:          1 :             Xapian::RangeProcessor * rp = new TestRangeProcessor(gone);
     348 [ -  + ][ #  # ]:          1 :             TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     349         [ +  - ]:          1 :             qp.add_rangeprocessor(rp);
     350         [ +  - ]:          1 :             delete rp;
     351 [ -  + ][ #  # ]:          1 :             TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     352                 :          1 :         }
     353                 :            :         // At the end of this block, qp is destroyed, but mustn't dereference
     354                 :            :         // the pointer it has to rp.  If it does, that should get caught
     355                 :            :         // when tests are run under valgrind.
     356                 :            :     }
     357                 :            : 
     358                 :          1 :     return true;
     359                 :            : }
     360                 :            : 
     361         [ -  + ]:         14 : class TestFieldProcessor : public Xapian::FieldProcessor {
     362                 :            :     DestroyedFlag destroyed;
     363                 :            : 
     364                 :            :   public:
     365                 :          8 :     TestFieldProcessor(bool & destroyed_) : destroyed(destroyed_) { }
     366                 :            : 
     367                 :          0 :     Xapian::Query operator()(const string &str) {
     368                 :          0 :         return Xapian::Query(str);
     369                 :            :     }
     370                 :            : };
     371                 :            : 
     372                 :            : /// Check reference counting of user-subclassable classes.
     373                 :          1 : DEFINE_TESTCASE(subclassablerefcount2, !backend) {
     374                 :            :     bool gone_auto, gone;
     375                 :            : 
     376                 :            :     // Simple test of release().
     377                 :            :     {
     378         [ +  - ]:          1 :         Xapian::FieldProcessor * proc = new TestFieldProcessor(gone);
     379 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     380         [ +  - ]:          1 :         Xapian::QueryParser qp;
     381 [ +  - ][ +  - ]:          1 :         qp.add_prefix("foo", proc->release());
     382 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     383                 :            :     }
     384 [ -  + ][ #  # ]:          1 :     TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     385                 :            : 
     386                 :            :     // Check a second call to release() has no effect.
     387                 :            :     {
     388         [ +  - ]:          1 :         Xapian::FieldProcessor * proc = new TestFieldProcessor(gone);
     389 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     390         [ +  - ]:          1 :         Xapian::QueryParser qp;
     391 [ +  - ][ +  - ]:          1 :         qp.add_prefix("foo", proc->release());
     392                 :          1 :         proc->release();
     393 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     394                 :            :     }
     395 [ -  + ][ #  # ]:          1 :     TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     396                 :            : 
     397                 :            :     // Test reference counting works, and that a FieldProcessor with automatic
     398                 :            :     // storage works OK.
     399                 :            :     {
     400                 :          1 :         TestFieldProcessor proc_auto(gone_auto);
     401 [ -  + ][ #  # ]:          1 :         TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     402                 :            :         {
     403         [ +  - ]:          1 :             Xapian::QueryParser qp1;
     404                 :            :             {
     405         [ +  - ]:          1 :                 Xapian::QueryParser qp2;
     406                 :            :                 Xapian::FieldProcessor * proc;
     407         [ +  - ]:          1 :                 proc = new TestFieldProcessor(gone);
     408 [ -  + ][ #  # ]:          1 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     409 [ +  - ][ +  - ]:          1 :                 qp1.add_prefix("foo", proc->release());
     410 [ -  + ][ #  # ]:          1 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     411 [ +  - ][ +  - ]:          1 :                 qp2.add_prefix("foo", proc);
     412 [ -  + ][ #  # ]:          1 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     413 [ +  - ][ +  - ]:          1 :                 qp2.add_prefix("bar", &proc_auto);
     414 [ -  + ][ #  # ]:          1 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     415 [ -  + ][ #  # ]:          1 :                 TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     416                 :            :             }
     417 [ -  + ][ #  # ]:          1 :             TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     418                 :            :         }
     419 [ -  + ][ #  # ]:          1 :         TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     420 [ -  + ][ #  # ]:          1 :         TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     421                 :            :     }
     422 [ -  + ][ #  # ]:          1 :     TEST(gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     423                 :            : 
     424                 :          1 :     return true;
     425                 :            : }
     426                 :            : 
     427         [ -  + ]:         98 : class TestMatchSpy : public Xapian::MatchSpy {
     428                 :            :     DestroyedFlag destroyed;
     429                 :            : 
     430                 :            :   public:
     431                 :         56 :     TestMatchSpy(bool & destroyed_) : destroyed(destroyed_) { }
     432                 :            : 
     433                 :          0 :     void operator()(const Xapian::Document &, double) { }
     434                 :            : };
     435                 :            : 
     436                 :            : /// Check reference counting of MatchSpy.
     437                 :          7 : DEFINE_TESTCASE(subclassablerefcount3, backend) {
     438 [ +  - ][ +  - ]:          7 :     Xapian::Database db = get_database("apitest_simpledata");
     439                 :            : 
     440                 :            :     bool gone_auto, gone;
     441                 :            : 
     442                 :            :     // Simple test of release().
     443                 :            :     {
     444         [ +  - ]:          7 :         Xapian::MatchSpy * spy = new TestMatchSpy(gone);
     445 [ -  + ][ #  # ]:          7 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     446         [ +  - ]:          7 :         Xapian::Enquire enquire(db);
     447         [ +  - ]:          7 :         enquire.add_matchspy(spy->release());
     448 [ -  + ][ #  # ]:          7 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     449                 :            :     }
     450 [ -  + ][ #  # ]:          7 :     TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     451                 :            : 
     452                 :            :     // Check a second call to release() has no effect.
     453                 :            :     {
     454         [ +  - ]:          7 :         Xapian::MatchSpy * spy = new TestMatchSpy(gone);
     455 [ -  + ][ #  # ]:          7 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     456         [ +  - ]:          7 :         Xapian::Enquire enquire(db);
     457         [ +  - ]:          7 :         enquire.add_matchspy(spy->release());
     458                 :          7 :         spy->release();
     459 [ -  + ][ #  # ]:          7 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     460                 :            :     }
     461 [ -  + ][ #  # ]:          7 :     TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     462                 :            : 
     463                 :            :     // Test reference counting works, and that a MatchSpy with automatic
     464                 :            :     // storage works OK.
     465                 :            :     {
     466                 :          7 :         TestMatchSpy spy_auto(gone_auto);
     467 [ -  + ][ #  # ]:          7 :         TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     468                 :            :         {
     469         [ +  - ]:          7 :             Xapian::Enquire enq1(db);
     470                 :            :             {
     471         [ +  - ]:          7 :                 Xapian::Enquire enq2(db);
     472                 :            :                 Xapian::MatchSpy * spy;
     473         [ +  - ]:          7 :                 spy = new TestMatchSpy(gone);
     474 [ -  + ][ #  # ]:          7 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     475         [ +  - ]:          7 :                 enq1.add_matchspy(spy->release());
     476 [ -  + ][ #  # ]:          7 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     477         [ +  - ]:          7 :                 enq2.add_matchspy(spy);
     478 [ -  + ][ #  # ]:          7 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     479         [ +  - ]:          7 :                 enq2.add_matchspy(&spy_auto);
     480 [ -  + ][ #  # ]:          7 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     481 [ -  + ][ #  # ]:          7 :                 TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     482                 :            :             }
     483 [ -  + ][ #  # ]:          7 :             TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     484                 :            :         }
     485 [ -  + ][ #  # ]:          7 :         TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     486 [ -  + ][ #  # ]:          7 :         TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     487                 :            :     }
     488 [ -  + ][ #  # ]:          7 :     TEST(gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     489                 :            : 
     490                 :          7 :     return true;
     491                 :            : }
     492                 :            : 
     493         [ -  + ]:         44 : class TestStopper : public Xapian::Stopper {
     494                 :            :     DestroyedFlag destroyed;
     495                 :            : 
     496                 :            :   public:
     497                 :         24 :     TestStopper(bool & destroyed_) : destroyed(destroyed_) { }
     498                 :            : 
     499                 :          0 :     bool operator()(const std::string&) const { return true; }
     500                 :            : };
     501                 :            : 
     502                 :            : /// Check reference counting of Stopper with QueryParser.
     503                 :          1 : DEFINE_TESTCASE(subclassablerefcount4, !backend) {
     504                 :            :     bool gone_auto, gone;
     505                 :            : 
     506                 :            :     // Simple test of release().
     507                 :            :     {
     508         [ +  - ]:          1 :         Xapian::Stopper * stopper = new TestStopper(gone);
     509 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     510         [ +  - ]:          1 :         Xapian::QueryParser qp;
     511         [ +  - ]:          1 :         qp.set_stopper(stopper->release());
     512 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     513                 :            :     }
     514 [ -  + ][ #  # ]:          1 :     TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     515                 :            : 
     516                 :            :     // Test that setting a new stopper causes the previous one to be released.
     517                 :            :     {
     518                 :            :         bool gone0;
     519         [ +  - ]:          1 :         Xapian::Stopper * stopper0 = new TestStopper(gone0);
     520 [ -  + ][ #  # ]:          1 :         TEST(!gone0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     521         [ +  - ]:          1 :         Xapian::QueryParser qp;
     522         [ +  - ]:          1 :         qp.set_stopper(stopper0->release());
     523 [ -  + ][ #  # ]:          1 :         TEST(!gone0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     524                 :            : 
     525         [ +  - ]:          1 :         Xapian::Stopper * stopper = new TestStopper(gone);
     526 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     527         [ +  - ]:          1 :         qp.set_stopper(stopper->release());
     528 [ -  + ][ #  # ]:          1 :         TEST(gone0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     529 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     530                 :            :     }
     531 [ -  + ][ #  # ]:          1 :     TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     532                 :            : 
     533                 :            :     // Check a second call to release() has no effect.
     534                 :            :     {
     535         [ +  - ]:          1 :         Xapian::Stopper * stopper = new TestStopper(gone);
     536 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     537         [ +  - ]:          1 :         Xapian::QueryParser qp;
     538         [ +  - ]:          1 :         qp.set_stopper(stopper->release());
     539                 :          1 :         stopper->release();
     540 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     541                 :            :     }
     542 [ -  + ][ #  # ]:          1 :     TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     543                 :            : 
     544                 :            :     // Test reference counting works, and that a Stopper with automatic
     545                 :            :     // storage works OK.
     546                 :            :     {
     547                 :          1 :         TestStopper stopper_auto(gone_auto);
     548 [ -  + ][ #  # ]:          1 :         TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     549                 :            :         {
     550         [ +  - ]:          1 :             Xapian::QueryParser qp1;
     551                 :            :             {
     552         [ +  - ]:          1 :                 Xapian::QueryParser qp2;
     553                 :            :                 Xapian::Stopper * stopper;
     554         [ +  - ]:          1 :                 stopper = new TestStopper(gone);
     555 [ -  + ][ #  # ]:          1 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     556         [ +  - ]:          1 :                 qp1.set_stopper(stopper->release());
     557 [ -  + ][ #  # ]:          1 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     558         [ +  - ]:          1 :                 qp2.set_stopper(stopper);
     559 [ -  + ][ #  # ]:          1 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     560         [ +  - ]:          1 :                 qp2.set_stopper(&stopper_auto);
     561 [ -  + ][ #  # ]:          1 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     562 [ -  + ][ #  # ]:          1 :                 TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     563                 :            :             }
     564 [ -  + ][ #  # ]:          1 :             TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     565                 :            :         }
     566 [ -  + ][ #  # ]:          1 :         TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     567 [ -  + ][ #  # ]:          1 :         TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     568                 :            :     }
     569 [ -  + ][ #  # ]:          1 :     TEST(gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     570                 :            : 
     571                 :          1 :     return true;
     572                 :            : }
     573                 :            : 
     574                 :            : /// Check reference counting of Stopper with TermGenerator.
     575                 :          1 : DEFINE_TESTCASE(subclassablerefcount5, !backend) {
     576                 :            :     bool gone_auto, gone;
     577                 :            : 
     578                 :            :     // Simple test of release().
     579                 :            :     {
     580         [ +  - ]:          1 :         Xapian::Stopper * stopper = new TestStopper(gone);
     581 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     582         [ +  - ]:          1 :         Xapian::TermGenerator indexer;
     583         [ +  - ]:          1 :         indexer.set_stopper(stopper->release());
     584 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     585                 :            :     }
     586 [ -  + ][ #  # ]:          1 :     TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     587                 :            : 
     588                 :            :     // Test that setting a new stopper causes the previous one to be released.
     589                 :            :     {
     590                 :            :         bool gone0;
     591         [ +  - ]:          1 :         Xapian::Stopper * stopper0 = new TestStopper(gone0);
     592 [ -  + ][ #  # ]:          1 :         TEST(!gone0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     593         [ +  - ]:          1 :         Xapian::TermGenerator indexer;
     594         [ +  - ]:          1 :         indexer.set_stopper(stopper0->release());
     595 [ -  + ][ #  # ]:          1 :         TEST(!gone0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     596                 :            : 
     597         [ +  - ]:          1 :         Xapian::Stopper * stopper = new TestStopper(gone);
     598 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     599         [ +  - ]:          1 :         indexer.set_stopper(stopper->release());
     600 [ -  + ][ #  # ]:          1 :         TEST(gone0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     601 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     602                 :            :     }
     603 [ -  + ][ #  # ]:          1 :     TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     604                 :            : 
     605                 :            :     // Check a second call to release() has no effect.
     606                 :            :     {
     607         [ +  - ]:          1 :         Xapian::Stopper * stopper = new TestStopper(gone);
     608 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     609         [ +  - ]:          1 :         Xapian::TermGenerator indexer;
     610         [ +  - ]:          1 :         indexer.set_stopper(stopper->release());
     611                 :          1 :         stopper->release();
     612 [ -  + ][ #  # ]:          1 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     613                 :            :     }
     614 [ -  + ][ #  # ]:          1 :     TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     615                 :            : 
     616                 :            :     // Test reference counting works, and that a Stopper with automatic
     617                 :            :     // storage works OK.
     618                 :            :     {
     619                 :          1 :         TestStopper stopper_auto(gone_auto);
     620 [ -  + ][ #  # ]:          1 :         TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     621                 :            :         {
     622         [ +  - ]:          1 :             Xapian::TermGenerator indexer1;
     623                 :            :             {
     624         [ +  - ]:          1 :                 Xapian::TermGenerator indexer2;
     625                 :            :                 Xapian::Stopper * stopper;
     626         [ +  - ]:          1 :                 stopper = new TestStopper(gone);
     627 [ -  + ][ #  # ]:          1 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     628         [ +  - ]:          1 :                 indexer1.set_stopper(stopper->release());
     629 [ -  + ][ #  # ]:          1 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     630         [ +  - ]:          1 :                 indexer2.set_stopper(stopper);
     631 [ -  + ][ #  # ]:          1 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     632         [ +  - ]:          1 :                 indexer2.set_stopper(&stopper_auto);
     633 [ -  + ][ #  # ]:          1 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     634 [ -  + ][ #  # ]:          1 :                 TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     635                 :            :             }
     636 [ -  + ][ #  # ]:          1 :             TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     637                 :            :         }
     638 [ -  + ][ #  # ]:          1 :         TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     639 [ -  + ][ #  # ]:          1 :         TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     640                 :            :     }
     641 [ -  + ][ #  # ]:          1 :     TEST(gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     642                 :            : 
     643                 :          1 :     return true;
     644                 :            : }
     645                 :            : 
     646         [ -  + ]:        154 : class TestKeyMaker : public Xapian::KeyMaker {
     647                 :            :     DestroyedFlag destroyed;
     648                 :            : 
     649                 :            :   public:
     650                 :         84 :     TestKeyMaker(bool & destroyed_) : destroyed(destroyed_) { }
     651                 :            : 
     652                 :          0 :     string operator()(const Xapian::Document&) const { return string(); }
     653                 :            : };
     654                 :            : 
     655                 :            : /// Check reference counting of KeyMaker.
     656                 :          7 : DEFINE_TESTCASE(subclassablerefcount6, backend) {
     657 [ +  - ][ +  - ]:          7 :     Xapian::Database db = get_database("apitest_simpledata");
     658                 :            : 
     659                 :            :     bool gone_auto, gone;
     660                 :            : 
     661                 :            :     // Simple test of release().
     662                 :            :     {
     663         [ +  - ]:          7 :         Xapian::KeyMaker * keymaker = new TestKeyMaker(gone);
     664 [ -  + ][ #  # ]:          7 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     665         [ +  - ]:          7 :         Xapian::Enquire enq(db);
     666         [ +  - ]:          7 :         enq.set_sort_by_key(keymaker->release(), false);
     667 [ -  + ][ #  # ]:          7 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     668                 :            :     }
     669 [ -  + ][ #  # ]:          7 :     TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     670                 :            : 
     671                 :            :     // Test that setting a new keymaker causes the previous one to be released.
     672                 :            :     {
     673                 :            :         bool gone0;
     674         [ +  - ]:          7 :         Xapian::KeyMaker * keymaker0 = new TestKeyMaker(gone0);
     675 [ -  + ][ #  # ]:          7 :         TEST(!gone0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     676         [ +  - ]:          7 :         Xapian::Enquire enq(db);
     677         [ +  - ]:          7 :         enq.set_sort_by_key(keymaker0->release(), false);
     678 [ -  + ][ #  # ]:          7 :         TEST(!gone0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     679                 :            : 
     680         [ +  - ]:          7 :         Xapian::KeyMaker * keymaker = new TestKeyMaker(gone);
     681 [ -  + ][ #  # ]:          7 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     682         [ +  - ]:          7 :         enq.set_sort_by_key_then_relevance(keymaker->release(), false);
     683 [ -  + ][ #  # ]:          7 :         TEST(gone0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     684 [ -  + ][ #  # ]:          7 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     685                 :            :     }
     686 [ -  + ][ #  # ]:          7 :     TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     687                 :            : 
     688                 :            :     // Check a second call to release() has no effect.
     689                 :            :     {
     690         [ +  - ]:          7 :         Xapian::KeyMaker * keymaker = new TestKeyMaker(gone);
     691 [ -  + ][ #  # ]:          7 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     692         [ +  - ]:          7 :         Xapian::Enquire enq(db);
     693         [ +  - ]:          7 :         enq.set_sort_by_key(keymaker->release(), false);
     694                 :          7 :         keymaker->release();
     695 [ -  + ][ #  # ]:          7 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     696                 :            :     }
     697 [ -  + ][ #  # ]:          7 :     TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     698                 :            : 
     699                 :            :     // Test reference counting works, and that a KeyMaker with automatic
     700                 :            :     // storage works OK.
     701                 :            :     {
     702                 :          7 :         TestKeyMaker keymaker_auto(gone_auto);
     703 [ -  + ][ #  # ]:          7 :         TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     704                 :            :         {
     705         [ +  - ]:          7 :             Xapian::Enquire enq1(db);
     706                 :            :             {
     707         [ +  - ]:          7 :                 Xapian::Enquire enq2(db);
     708                 :            :                 Xapian::KeyMaker * keymaker;
     709         [ +  - ]:          7 :                 keymaker = new TestKeyMaker(gone);
     710 [ -  + ][ #  # ]:          7 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     711         [ +  - ]:          7 :                 enq1.set_sort_by_key(keymaker->release(), false);
     712 [ -  + ][ #  # ]:          7 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     713         [ +  - ]:          7 :                 enq2.set_sort_by_relevance_then_key(keymaker, false);
     714 [ -  + ][ #  # ]:          7 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     715         [ +  - ]:          7 :                 enq2.set_sort_by_key_then_relevance(&keymaker_auto, false);
     716 [ -  + ][ #  # ]:          7 :                 TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     717 [ -  + ][ #  # ]:          7 :                 TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     718                 :            :             }
     719 [ -  + ][ #  # ]:          7 :             TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     720                 :            :         }
     721 [ -  + ][ #  # ]:          7 :         TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     722 [ -  + ][ #  # ]:          7 :         TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     723                 :            :     }
     724 [ -  + ][ #  # ]:          7 :     TEST(gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     725                 :            : 
     726                 :          7 :     return true;
     727                 :            : }
     728                 :            : 
     729         [ -  + ]:        280 : class TestExpandDecider : public Xapian::ExpandDecider {
     730                 :            :     DestroyedFlag destroyed;
     731                 :            : 
     732                 :            :   public:
     733                 :        168 :     TestExpandDecider(bool & destroyed_) : destroyed(destroyed_) { }
     734                 :            : 
     735                 :       3528 :     bool operator()(const string&) const { return true; }
     736                 :            : };
     737                 :            : 
     738                 :            : /// Check reference counting of ExpandDecider.
     739                 :          7 : DEFINE_TESTCASE(subclassablerefcount7, backend) {
     740 [ +  - ][ +  - ]:          7 :     Xapian::Database db = get_database("apitest_simpledata");
     741         [ +  - ]:         14 :     Xapian::Enquire enq(db);
     742         [ +  - ]:         14 :     Xapian::RSet rset;
     743         [ +  - ]:          7 :     rset.add_document(1);
     744                 :            : 
     745                 :            :     bool gone_auto, gone;
     746                 :            : 
     747         [ +  + ]:         21 :     for (int flags = 0;
     748                 :            :          flags <= Xapian::Enquire::INCLUDE_QUERY_TERMS;
     749                 :            :          flags += Xapian::Enquire::INCLUDE_QUERY_TERMS) {
     750                 :            :         // Test of auto lifetime ExpandDecider.
     751                 :            :         {
     752                 :         14 :             TestExpandDecider edecider_auto(gone_auto);
     753 [ -  + ][ #  # ]:         14 :             TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     754         [ +  - ]:         14 :             (void)enq.get_eset(5, rset, 0, &edecider_auto);
     755 [ -  + ][ #  # ]:         14 :             TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     756                 :            :         }
     757 [ -  + ][ #  # ]:         14 :         TEST(gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     758                 :            : 
     759                 :            :         // Simple test of release().
     760                 :            :         {
     761         [ +  - ]:         14 :             Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
     762 [ -  + ][ #  # ]:         14 :             TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     763         [ +  - ]:         14 :             (void)enq.get_eset(5, rset, 0, edecider);
     764 [ -  + ][ #  # ]:         14 :             TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     765         [ +  - ]:         14 :             delete edecider;
     766 [ -  + ][ #  # ]:         14 :             TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     767                 :            :         }
     768                 :            : 
     769                 :            :         // Test that a released ExpandDecider gets cleaned up by get_eset().
     770                 :            :         {
     771         [ +  - ]:         14 :             Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
     772 [ -  + ][ #  # ]:         14 :             TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     773         [ +  - ]:         14 :             (void)enq.get_eset(5, rset, 0, edecider->release());
     774 [ -  + ][ #  # ]:         14 :             TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     775                 :            :         }
     776                 :            : 
     777                 :            :         // Check a second call to release() has no effect.
     778                 :            :         {
     779         [ +  - ]:         14 :             Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
     780 [ -  + ][ #  # ]:         14 :             TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     781                 :         14 :             edecider->release();
     782 [ -  + ][ #  # ]:         14 :             TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     783         [ +  - ]:         14 :             (void)enq.get_eset(5, rset, 0, edecider->release());
     784 [ -  + ][ #  # ]:         14 :             TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     785                 :            :         }
     786                 :            :     }
     787                 :            : 
     788                 :            :     // Test combinations of released/non-released with ExpandDeciderAnd.
     789                 :            :     {
     790                 :          7 :         TestExpandDecider edecider_auto(gone_auto);
     791 [ -  + ][ #  # ]:          7 :         TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     792         [ +  - ]:          7 :         Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
     793 [ -  + ][ #  # ]:          7 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     794                 :            :         (void)enq.get_eset(5, rset, 0,
     795                 :            :                 (new Xapian::ExpandDeciderAnd(
     796                 :            :                     &edecider_auto,
     797 [ +  - ][ +  - ]:          7 :                     edecider->release()))->release());
                 [ +  - ]
     798 [ -  + ][ #  # ]:          7 :         TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     799 [ -  + ][ #  # ]:          7 :         TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     800                 :            :     }
     801 [ -  + ][ #  # ]:          7 :     TEST(gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     802                 :            :     {
     803                 :          7 :         TestExpandDecider edecider_auto(gone_auto);
     804 [ -  + ][ #  # ]:          7 :         TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     805         [ +  - ]:          7 :         Xapian::ExpandDecider * edecider = new TestExpandDecider(gone);
     806 [ -  + ][ #  # ]:          7 :         TEST(!gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     807                 :            :         (void)enq.get_eset(5, rset, 0,
     808                 :            :                 (new Xapian::ExpandDeciderAnd(
     809                 :            :                     edecider->release(),
     810 [ +  - ][ +  - ]:          7 :                     &edecider_auto))->release());
                 [ +  - ]
     811 [ -  + ][ #  # ]:          7 :         TEST(!gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     812 [ -  + ][ #  # ]:          7 :         TEST(gone);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     813                 :            :     }
     814 [ -  + ][ #  # ]:          7 :     TEST(gone_auto);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     815                 :            : 
     816                 :          7 :     return true;
     817                 :            : }
     818                 :            : 
     819                 :            : /// Check encoding of non-UTF8 document data.
     820                 :          1 : DEFINE_TESTCASE(nonutf8docdesc1, !backend) {
     821         [ +  - ]:          1 :     Xapian::Document doc;
     822 [ +  - ][ +  - ]:          1 :     doc.set_data("\xc0\x80\xf5\x80\x80\x80\xfe\xff");
     823 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(doc.get_description(),
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     824                 :            :               "Document(docid=0, data=\\xc0\\x80\\xf5\\x80\\x80\\x80\\xfe\\xff)");
     825 [ +  - ][ +  - ]:          1 :     doc.set_data(string("\x00\x1f", 2));
     826 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(doc.get_description(),
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     827                 :            :               "Document(docid=0, data=\\x00\\x1f)");
     828                 :            :     // Check that backslashes are encoded so output isn't ambiguous.
     829 [ +  - ][ +  - ]:          1 :     doc.set_data("back\\slash");
     830 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(doc.get_description(),
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     831                 :            :               "Document(docid=0, data=back\\x5cslash)");
     832                 :          1 :     return true;
     833                 :            : }
     834                 :            : 
     835                 :          1 : DEFINE_TESTCASE(orphaneddoctermitor1, !backend) {
     836                 :          1 :     Xapian::TermIterator t;
     837                 :            :     {
     838         [ +  - ]:          1 :         Xapian::Document doc;
     839 [ +  - ][ +  - ]:          1 :         doc.add_term("foo");
     840 [ +  - ][ +  - ]:          1 :         t = doc.termlist_begin();
     841                 :            :     }
     842 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(*t, "foo");
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
     843                 :          1 :     return true;
     844                 :            : }
     845                 :            : 
     846                 :            : /** Test removal of terms from a document while iterating over them.
     847                 :            :  *
     848                 :            :  *  Prior to 1.5.0 and 1.4.6 the underlying iterator was invalidated when
     849                 :            :  *  preinc == false, leading to undefined behaviour (typically a segmentation
     850                 :            :  *  fault).
     851                 :            :  */
     852                 :          1 : DEFINE_TESTCASE(deletewhileiterating1, !backend) {
     853         [ +  + ]:          3 :     for (bool preinc : { false, true }) {
     854         [ +  - ]:          2 :         Xapian::Document doc;
     855         [ +  - ]:          4 :         Xapian::TermGenerator indexer;
     856         [ +  - ]:          2 :         indexer.set_document(doc);
     857 [ +  - ][ +  - ]:          2 :         indexer.index_text("Pull the rug out from under ourselves", 1, "S");
                 [ +  - ]
     858         [ +  - ]:          4 :         Xapian::TermIterator term_iterator = doc.termlist_begin();
     859 [ +  - ][ +  - ]:          2 :         term_iterator.skip_to("S");
     860         [ +  + ]:         16 :         while (term_iterator != doc.termlist_end()) {
     861         [ +  - ]:         14 :             const string& term = *term_iterator;
     862         [ -  + ]:         14 :             if (!startswith(term, "S")) {
     863                 :          0 :                 break;
     864                 :            :             }
     865 [ +  + ][ +  - ]:         14 :             if (preinc) ++term_iterator;
     866         [ +  - ]:         14 :             doc.remove_term(term);
     867 [ +  + ][ +  - ]:         14 :             if (!preinc) ++term_iterator;
                 [ +  - ]
     868                 :         14 :         }
     869 [ +  - ][ -  + ]:          2 :         TEST_EQUAL(doc.termlist_count(), 0);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     870 [ +  - ][ -  + ]:          2 :         TEST(doc.termlist_begin() == doc.termlist_end());
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     871                 :          2 :     }
     872                 :          1 :     return true;
     873                 :            : }
     874                 :            : 
     875                 :            : /// Feature test for Document::remove_postings().
     876                 :          1 : DEFINE_TESTCASE(removepostings, !backend) {
     877         [ +  - ]:          1 :     Xapian::Document doc;
     878                 :            :     // Add Fibonacci sequence as positions.
     879                 :          1 :     Xapian::termpos prev_pos = 1;
     880                 :          1 :     Xapian::termpos pos = 1;
     881         [ +  + ]:         16 :     while (pos < 1000) {
     882 [ +  - ][ +  - ]:         15 :         doc.add_posting("foo", pos);
     883                 :         15 :         auto new_pos = prev_pos + pos;
     884                 :         15 :         prev_pos = pos;
     885                 :         15 :         pos = new_pos;
     886                 :            :     }
     887                 :            : 
     888                 :            :     // Check we added exactly one term.
     889 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(doc.termlist_count(), 1);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     890                 :            : 
     891         [ +  - ]:          2 :     Xapian::TermIterator t = doc.termlist_begin();
     892         [ +  - ]:          1 :     auto num_pos = t.positionlist_count();
     893 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(t.get_wdf(), num_pos);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     894                 :            : 
     895                 :            :     // Out of order is a no-op.
     896 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(doc.remove_postings("foo", 2, 1), 0);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     897 [ +  - ][ +  - ]:          1 :     t = doc.termlist_begin();
     898 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(t.positionlist_count(), num_pos);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     899 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(t.get_wdf(), num_pos);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     900                 :            : 
     901                 :            :     // 6 and 7 aren't in the sequence.
     902 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(doc.remove_postings("foo", 6, 7), 0);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     903 [ +  - ][ +  - ]:          1 :     t = doc.termlist_begin();
     904 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(t.positionlist_count(), num_pos);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     905 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(t.get_wdf(), num_pos);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     906                 :            : 
     907                 :            :     // Beyond the end of the positions.
     908 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(doc.remove_postings("foo", 1000, 2000), 0);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     909 [ +  - ][ +  - ]:          1 :     t = doc.termlist_begin();
     910 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(t.positionlist_count(), num_pos);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     911 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(t.get_wdf(), num_pos);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     912                 :            : 
     913                 :            :     // 1, 2, 3 are in the sequence, 4 isn't.
     914 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(doc.remove_postings("foo", 1, 4), 3);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     915 [ +  - ][ +  - ]:          1 :     t = doc.termlist_begin();
     916 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(t.positionlist_count(), num_pos - 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     917 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(t.get_wdf(), num_pos - 3);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     918                 :            : 
     919                 :            :     // Remove the end position.
     920 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(doc.remove_postings("foo", 876, 987), 1);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     921 [ +  - ][ +  - ]:          1 :     t = doc.termlist_begin();
     922 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(t.positionlist_count(), num_pos - 4);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     923 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(t.get_wdf(), num_pos - 4);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     924                 :            : 
     925                 :            :     // Remove a range in the middle.
     926 [ +  - ][ +  - ]:          1 :     TEST_EQUAL(doc.remove_postings("foo", 33, 233), 5);
         [ -  + ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     927 [ +  - ][ +  - ]:          1 :     t = doc.termlist_begin();
     928 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(t.positionlist_count(), num_pos - 9);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     929 [ +  - ][ -  + ]:          1 :     TEST_EQUAL(t.get_wdf(), num_pos - 9);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     930                 :            : 
     931                 :            :     // Check the expected positions are left.
     932 [ +  - ][ +  - ]:          1 :     t = doc.termlist_begin();
     933                 :            :     static const Xapian::termpos expected[] = { 5, 8, 13, 21, 377, 610, 9999 };
     934                 :          1 :     const Xapian::termpos* expect = expected;
     935 [ +  - ][ +  - ]:          7 :     for (auto p = t.positionlist_begin(); p != t.positionlist_end(); ++p) {
                 [ +  + ]
     936 [ +  - ][ -  + ]:          6 :         TEST_EQUAL(*p, *expect);
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     937                 :          6 :         ++expect;
     938                 :          1 :     }
     939                 :            : 
     940                 :          1 :     return true;
     941                 :            : }

Generated by: LCOV version 1.11