1 // Simple test that we can use xapian from java 2 // 3 // Copyright (C) 2005,2006,2007,2008,2011,2016,2017,2019 Olly Betts 4 // 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. 9 // 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. 14 // 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 18 // USA 19 20 import org.xapian.*; 21 22 // FIXME: need to sort out throwing wrapped Xapian::Error subclasses 23 //import org.xapian.errors.*; 24 25 // FIXME: "implements" not "extends" in JNI Java API 26 class MyMatchDecider extends MatchDecider { accept(Document d)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. 30 /* try { */ 31 return d.getData().length() == 0; 32 /* 33 } catch (XapianError e) { 34 return true; 35 } 36 */ 37 } 38 } 39 40 // FIXME: "implements" not "extends" in JNI Java API 41 class MyExpandDecider extends ExpandDecider { accept(String s)42 public boolean accept(String s) { return s.charAt(0) != 'a'; } 43 } 44 45 class MyFieldProcessor extends FieldProcessor { apply(String str)46 public Query apply(String str) { 47 if (str.equals("spam")) 48 return new Query("eggs"); 49 return new Query("spam"); 50 } 51 } 52 53 public class SmokeTest { main(String[] args)54 public static void main(String[] args) throws Exception { 55 TermGenerator termGenerator = new TermGenerator(); 56 termGenerator.setFlags(TermGenerator.FLAG_SPELLING); 57 try { 58 // Test the version number reporting functions give plausible 59 // results. 60 String v = ""; 61 v += Version.major(); 62 v += "."; 63 v += Version.minor(); 64 v += "."; 65 v += Version.revision(); 66 String v2 = Version.string(); 67 if (!v.equals(v2)) { 68 System.err.println("Unexpected version output (" + v + " != " + v2 + ")"); 69 System.exit(1); 70 } 71 72 Stem stem = new Stem("english"); 73 if (!stem.toString().equals("Xapian::Stem(english)")) { 74 System.err.println("Unexpected stem.toString()"); 75 System.exit(1); 76 } 77 Document doc = new Document(); 78 doc.setData("a\000b"); 79 String s = doc.getData(); 80 if (s.equals("a")) { 81 System.err.println("getData+setData truncates at a zero byte"); 82 System.exit(1); 83 } 84 if (!s.equals("a\000b")) { 85 System.err.println("getData+setData doesn't transparently handle a zero byte"); 86 System.exit(1); 87 } 88 doc.setData("is there anybody out there?"); 89 doc.addTerm("XYzzy"); 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); 97 db.addDocument(doc); 98 if (db.getDocCount() != 1) { 99 System.err.println("Unexpected db.getDocCount()"); 100 System.exit(1); 101 } 102 103 QueryParser qp = new QueryParser(); 104 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"); 115 116 if (!Query.MatchAll.toString().equals("Query(<alldocuments>)")) { 117 System.err.println("Unexpected Query.MatchAll.toString()"); 118 System.exit(1); 119 } 120 121 if (!Query.MatchNothing.toString().equals("Query()")) { 122 System.err.println("Unexpected Query.MatchNothing.toString()"); 123 System.exit(1); 124 } 125 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()"); 130 System.exit(1); 131 } 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()"); 136 System.exit(1); 137 } 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()"); 142 System.exit(1); 143 } 144 Enquire enq = new Enquire(db); 145 146 // Check Xapian::BAD_VALUENO is wrapped suitably. 147 enq.setCollapseKey(Xapian.BAD_VALUENO); 148 149 // Test that the non-constant wrapping prior to 1.4.10 still works. 150 enq.setCollapseKey(Xapian.getBAD_VALUENO()); 151 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()"); 156 System.exit(1); 157 } 158 MSetIterator m_itor = mset.begin(); 159 Document m_doc = null; 160 long m_id; 161 while(m_itor.hasNext()) { 162 m_id = m_itor.next(); 163 if(m_itor.hasNext()) { 164 m_doc = mset.getDocument(m_id); 165 } 166 } 167 168 // Only one doc exists in this mset 169 if(m_doc != null && m_doc.getDocId() != 0) { 170 System.err.println("Unexpected docid"); 171 System.exit(1); 172 } 173 174 String term_str = ""; 175 TermIterator itor = enq.getMatchingTermsBegin(mset.getElement(0)); 176 while (itor.hasNext()) { 177 term_str += itor.next(); 178 if (itor.hasNext()) 179 term_str += ' '; 180 } 181 if (!term_str.equals("is there")) { 182 System.err.println("Unexpected term_str"); 183 System.exit(1); 184 } 185 /* FIXME:dc: Fails since Xapian::Error is still unmapped 186 boolean ok = false; 187 try { 188 Database db_fail = new Database("NOsuChdaTabASe"); 189 // Ignore the return value. 190 db_fail.getDocCount(); 191 } catch (DatabaseOpeningError e) { 192 ok = true; 193 } 194 if (!ok) { 195 System.err.println("Managed to open non-existent database"); 196 System.exit(1); 197 } 198 */ 199 /* 200 if (Query.OP_ELITE_SET != 10) { 201 System.err.println("OP_ELITE_SET is " + Query.OP_ELITE_SET + " not 10"); 202 System.exit(1); 203 } 204 */ 205 RSet rset = new RSet(); 206 rset.addDocument(1); 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"); 211 System.exit(1); 212 } 213 214 int count = 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"); 219 System.exit(1); 220 } 221 ++count; 222 eit.next(); 223 } 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()); 227 System.exit(1); 228 } 229 230 /* 231 MSet mset2 = enq.getMSet(0, 10, null, new MyMatchDecider()); 232 if (mset2.size() > 0) { 233 System.err.println("MyMatchDecider wasn't used"); 234 System.exit(1); 235 } 236 */ 237 238 if (!enq.getQuery().toString().equals("Query((there OR is))")) { 239 System.err.println("Enquire::getQuery() returned the wrong query: " + enq.getQuery().toString()); 240 System.exit(1); 241 } 242 243 { 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"); 247 System.exit(1); 248 } 249 } 250 251 { 252 // Wrapped functions which take/return byte[] for std::string. 253 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"); 259 System.exit(1); 260 } 261 262 // Check that serialisation returns byte[], that 263 // unserialisation takes byte[], and round-tripping works. 264 Query q = new Query("foo"); 265 res = q.serialise(); 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"); 269 System.exit(1); 270 } 271 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(); 276 d.setData("xyzzy"); 277 d.addValue(7, res); 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()"); 281 System.exit(1); 282 } 283 res = d.serialise(); 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()); 291 System.exit(1); 292 } 293 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"); 302 System.exit(1); 303 } 304 305 // Check that serialisation returns byte[], that 306 // unserialisation takes byte[], and round-tripping works. 307 LatLongCoords llcs = new LatLongCoords(); 308 llcs.append(llc); 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"); 314 System.exit(1); 315 } 316 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"); 322 System.exit(1); 323 } 324 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"); 330 System.exit(1); 331 } 332 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"); 338 System.exit(1); 339 } 340 341 // Check ValueSetMatchDecider.addValue() and removeValue() take 342 // byte[]. 343 ValueSetMatchDecider vsmd = new ValueSetMatchDecider(1, false); 344 vsmd.addValue(res); 345 vsmd.removeValue(res); 346 347 // Check Database.getValueLowerBound() and getValueUpperBound() 348 // return byte[]. 349 byte[] lo = "abba".getBytes(); 350 byte[] hi = "xyzzy".getBytes(); 351 { 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); 358 db = wdb; 359 } 360 361 if (!java.util.Arrays.equals(db.getValueLowerBound(42), lo)) { 362 System.err.println("Database.getValueLowerBound() doesn't work as expected"); 363 System.exit(1); 364 } 365 if (!java.util.Arrays.equals(db.getValueUpperBound(42), hi)) { 366 System.err.println("Database.getValueUpperBound() doesn't work as expected"); 367 System.exit(1); 368 } 369 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"); 373 System.exit(1); 374 } 375 } 376 } catch (Exception e) { 377 System.err.println("Caught unexpected exception " + e.toString()); 378 System.exit(1); 379 } 380 } 381 } 382