1 // Simple test that we can use xapian from java
3 // Copyright (C) 2005,2006,2007,2008,2011,2016,2017,2019 Olly Betts
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation; either version 2 of the
8 // License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
22 // FIXME: need to sort out throwing wrapped Xapian::Error subclasses
23 //import org.xapian.errors.*;
25 // FIXME: "implements" not "extends" in JNI Java API
26 class MyMatchDecider
extends MatchDecider
{
27 public boolean accept(Document d
) {
28 // NB It's not normally appropriate to call getData() in a MatchDecider
29 // but we do it here to make sure we don't get an empty document.
31 return d
.getData().length() == 0;
33 } catch (XapianError e) {
40 // FIXME: "implements" not "extends" in JNI Java API
41 class MyExpandDecider
extends ExpandDecider
{
42 public boolean accept(String s
) { return s
.charAt(0) != 'a'; }
45 class MyFieldProcessor
extends FieldProcessor
{
46 public Query
apply(String str
) {
47 if (str
.equals("spam"))
48 return new Query("eggs");
49 return new Query("spam");
53 public class SmokeTest
{
54 public static void main(String
[] args
) throws Exception
{
55 TermGenerator termGenerator
= new TermGenerator();
56 termGenerator
.setFlags(TermGenerator
.FLAG_SPELLING
);
58 // Test the version number reporting functions give plausible
65 v
+= Version
.revision();
66 String v2
= Version
.string();
68 System
.err
.println("Unexpected version output (" + v
+ " != " + v2
+ ")");
72 Stem stem
= new Stem("english");
73 if (!stem
.toString().equals("Xapian::Stem(english)")) {
74 System
.err
.println("Unexpected stem.toString()");
77 Document doc
= new Document();
78 doc
.setData("a\000b");
79 String s
= doc
.getData();
81 System
.err
.println("getData+setData truncates at a zero byte");
84 if (!s
.equals("a\000b")) {
85 System
.err
.println("getData+setData doesn't transparently handle a zero byte");
88 doc
.setData("is there anybody out there?");
90 // apply was stemWord() in the JNI bindings
91 doc
.addPosting(stem
.apply("is"), 1);
92 doc
.addPosting(stem
.apply("there"), 2);
93 doc
.addPosting(stem
.apply("anybody"), 3);
94 doc
.addPosting(stem
.apply("out"), 4);
95 doc
.addPosting(stem
.apply("there"), 5);
96 WritableDatabase db
= new WritableDatabase("", Xapian
.DB_BACKEND_INMEMORY
);
98 if (db
.getDocCount() != 1) {
99 System
.err
.println("Unexpected db.getDocCount()");
103 QueryParser qp
= new QueryParser();
105 // Test wrapping of null-able grouping parameter.
106 qp
.addBooleanPrefix("colour", "XC");
107 qp
.addBooleanPrefix("color", "XC");
108 qp
.addBooleanPrefix("foo", "XFOO", null);
109 qp
.addBooleanPrefix("bar", "XBAR", "XBA*");
110 qp
.addBooleanPrefix("baa", "XBAA", "XBA*");
111 DateRangeProcessor rpdate
= new DateRangeProcessor(1, Xapian
.RP_DATE_PREFER_MDY
, 1960);
112 qp
.addRangeprocessor(rpdate
);
113 qp
.addRangeprocessor(rpdate
, null);
114 qp
.addRangeprocessor(rpdate
, "foo");
116 if (!Query
.MatchAll
.toString().equals("Query(<alldocuments>)")) {
117 System
.err
.println("Unexpected Query.MatchAll.toString()");
121 if (!Query
.MatchNothing
.toString().equals("Query()")) {
122 System
.err
.println("Unexpected Query.MatchNothing.toString()");
126 String
[] terms
= { "smoke", "test", "terms" };
127 Query query
= new Query(Query
.OP_OR
, terms
);
128 if (!query
.toString().equals("Query((smoke OR test OR terms))")) {
129 System
.err
.println("Unexpected query.toString()");
132 Query
[] queries
= { new Query("smoke"), query
, new Query("string") };
133 Query query2
= new Query(Query
.OP_XOR
, queries
);
134 if (!query2
.toString().equals("Query((smoke XOR (smoke OR test OR terms) XOR string))")) {
135 System
.err
.println("Unexpected query2.toString()");
138 String
[] subqs
= { "a", "b" };
139 Query query3
= new Query(Query
.OP_OR
, subqs
);
140 if (!query3
.toString().equals("Query((a OR b))")) {
141 System
.err
.println("Unexpected query3.toString()");
144 Enquire enq
= new Enquire(db
);
146 // Check Xapian::BAD_VALUENO is wrapped suitably.
147 enq
.setCollapseKey(Xapian
.BAD_VALUENO
);
149 // Test that the non-constant wrapping prior to 1.4.10 still works.
150 enq
.setCollapseKey(Xapian
.getBAD_VALUENO());
152 enq
.setQuery(new Query(Query
.OP_OR
, "there", "is"));
153 MSet mset
= enq
.getMSet(0, 10);
154 if (mset
.size() != 1) {
155 System
.err
.println("Unexpected mset.size()");
158 MSetIterator m_itor
= mset
.begin();
159 Document m_doc
= null;
161 while(m_itor
.hasNext()) {
162 m_id
= m_itor
.next();
163 if(m_itor
.hasNext()) {
164 m_doc
= mset
.getDocument(m_id
);
168 // Only one doc exists in this mset
169 if(m_doc
!= null && m_doc
.getDocId() != 0) {
170 System
.err
.println("Unexpected docid");
174 String term_str
= "";
175 TermIterator itor
= enq
.getMatchingTermsBegin(mset
.getElement(0));
176 while (itor
.hasNext()) {
177 term_str
+= itor
.next();
181 if (!term_str
.equals("is there")) {
182 System
.err
.println("Unexpected term_str");
185 /* FIXME:dc: Fails since Xapian::Error is still unmapped
188 Database db_fail = new Database("NOsuChdaTabASe");
189 // Ignore the return value.
190 db_fail.getDocCount();
191 } catch (DatabaseOpeningError e) {
195 System.err.println("Managed to open non-existent database");
200 if (Query.OP_ELITE_SET != 10) {
201 System.err.println("OP_ELITE_SET is " + Query.OP_ELITE_SET + " not 10");
205 RSet rset
= new RSet();
207 ESet eset
= enq
.getESet(10, rset
, new MyExpandDecider());
208 // FIXME: temporary simple check
209 if (0 == eset
.size()) {
210 System
.err
.println("ESet.size() was 0");
215 for(ESetIterator eit
= eset
.begin(); eit
.hasNext(); ) {
216 // for (int i = 0; i < eset.size(); i++) {
217 if (eit
.getTerm().charAt(0) == 'a') {
218 System
.err
.println("MyExpandDecider wasn't used");
224 if (count
!= eset
.size()) {
225 System
.err
.println("ESet.size() mismatched number of terms returned by ESetIterator");
226 System
.err
.println(count
+ " " + eset
.size());
231 MSet mset2 = enq.getMSet(0, 10, null, new MyMatchDecider());
232 if (mset2.size() > 0) {
233 System.err.println("MyMatchDecider wasn't used");
238 if (!enq
.getQuery().toString().equals("Query((there OR is))")) {
239 System
.err
.println("Enquire::getQuery() returned the wrong query: " + enq
.getQuery().toString());
244 qp
.addPrefix("food", new MyFieldProcessor());
245 if (!qp
.parseQuery("food:spam").toString().equals("Query(eggs)")) {
246 System
.err
.println("FieldProcessor subclass doesn't work as expected");
252 // Wrapped functions which take/return byte[] for std::string.
254 // Check that serialisation returns byte[], that
255 // unserialisation takes byte[], and round-tripping works.
256 byte[] res
= Xapian
.sortableSerialise(1.675);
257 if (Xapian
.sortableUnserialise(res
) != 1.675) {
258 System
.err
.println("sortableSerialise() and/or sortableUnserialise() don't work as expected");
262 // Check that serialisation returns byte[], that
263 // unserialisation takes byte[], and round-tripping works.
264 Query q
= new Query("foo");
266 Query q_out
= Query
.unserialise(res
);
267 if (!q
.toString().equals(q_out
.toString())) {
268 System
.err
.println("Query serialisation doesn't work as expected");
272 // Check Document.addValue() takes byte[], that getValue()
273 // returns byte[], that serialisation returns byte[], that
274 // unserialisation takes byte[], and round-tripping works.
275 Document d
= new Document();
278 byte[] res2
= d
.getValue(7);
279 if (!java
.util
.Arrays
.equals(res
, res2
)) {
280 System
.err
.println("Document.getValue() returns a different byte[] to the one set with addValue()");
284 Document d_out
= Document
.unserialise(res
);
285 // Make sure the "terms_here" flag is set so the descriptions match.
286 d_out
.termListCount();
287 if (!d
.toString().equals(d_out
.toString())) {
288 System
.err
.println("Document serialisation doesn't work as expected");
289 System
.err
.println(d
.toString());
290 System
.err
.println(d_out
.toString());
294 // Check that serialisation returns byte[], that
295 // unserialisation takes byte[], and round-tripping works.
296 LatLongCoord llc
= new LatLongCoord(10.5, 45.25);
297 res
= llc
.serialise();
298 LatLongCoord llc_out
= new LatLongCoord();
299 llc_out
.unserialise(res
);
300 if (!llc
.toString().equals(llc_out
.toString())) {
301 System
.err
.println("LatLongCoord serialisation doesn't work as expected");
305 // Check that serialisation returns byte[], that
306 // unserialisation takes byte[], and round-tripping works.
307 LatLongCoords llcs
= new LatLongCoords();
309 res
= llcs
.serialise();
310 LatLongCoords llcs_out
= new LatLongCoords();
311 llcs_out
.unserialise(res
);
312 if (!llcs
.toString().equals(llcs_out
.toString())) {
313 System
.err
.println("LatLongCoords serialisation doesn't work as expected");
317 // Check `range_limit` mapped to byte[].
318 q
= new Query(Query
.op
.OP_VALUE_GE
, 0, res
);
319 if (q
.toString().length() == 0) {
320 // Mostly just a way to actually use the constructed object.
321 System
.err
.println("Query description shouldn't be empty");
325 // Check `range_limit` mapped to byte[].
326 q
= new Query(Query
.op
.OP_VALUE_LE
, 1, res
);
327 if (q
.toString().length() == 0) {
328 // Mostly just a way to actually use the constructed object.
329 System
.err
.println("Query description shouldn't be empty");
333 // Check `range_lower` and `range_upper` mapped to byte[].
334 q
= new Query(Query
.op
.OP_VALUE_RANGE
, 2, res
, res
);
335 if (q
.toString().length() == 0) {
336 // Mostly just a way to actually use the constructed object.
337 System
.err
.println("Query description shouldn't be empty");
341 // Check ValueSetMatchDecider.addValue() and removeValue() take
343 ValueSetMatchDecider vsmd
= new ValueSetMatchDecider(1, false);
345 vsmd
.removeValue(res
);
347 // Check Database.getValueLowerBound() and getValueUpperBound()
349 byte[] lo
= "abba".getBytes();
350 byte[] hi
= "xyzzy".getBytes();
352 WritableDatabase wdb
= new WritableDatabase("", Xapian
.DB_BACKEND_INMEMORY
);
353 Document document
= new Document();
354 document
.addValue(42, hi
);
355 wdb
.addDocument(document
);
356 document
.addValue(42, lo
);
357 wdb
.addDocument(document
);
361 if (!java
.util
.Arrays
.equals(db
.getValueLowerBound(42), lo
)) {
362 System
.err
.println("Database.getValueLowerBound() doesn't work as expected");
365 if (!java
.util
.Arrays
.equals(db
.getValueUpperBound(42), hi
)) {
366 System
.err
.println("Database.getValueUpperBound() doesn't work as expected");
370 ValueIterator it
= db
.valuestreamBegin(42);
371 if (!java
.util
.Arrays
.equals(it
.getValue(), hi
)) {
372 System
.err
.println("ValueIterator.getValue() doesn't work as expected");
376 } catch (Exception e
) {
377 System
.err
.println("Caught unexpected exception " + e
.toString());