1 // Simple test that we can use xapian from csharp
3 // Copyright (C) 2004,2005,2006,2007,2008,2011,2016,2019,2023 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
20 class TestMatchDecider
: Xapian
.MatchDecider
{
21 public override bool Apply(Xapian
.Document doc
) {
22 return (doc
.GetValue(0) == "yes");
27 public static void Main() {
29 // Test the version number reporting functions give plausible
32 v
+= Xapian
.Version
.Major();
34 v
+= Xapian
.Version
.Minor();
36 v
+= Xapian
.Version
.Revision();
37 string v2
= Xapian
.Version
.String();
39 System
.Console
.WriteLine("Unexpected version output (" + v
+ " != " + v2
+ ")");
40 System
.Environment
.Exit(1);
43 Xapian
.Stem stem
= new Xapian
.Stem("english");
44 if (stem
.GetDescription() != "Xapian::Stem(english)") {
45 System
.Console
.WriteLine("Unexpected stem.GetDescription()");
46 System
.Environment
.Exit(1);
48 Xapian
.Document doc
= new Xapian
.Document();
49 // Currently SWIG doesn't generate zero-byte clean code for
50 // transferring strings between C# and C++.
52 if (doc
.GetData() != "a") {
53 System
.Console
.WriteLine("XPASS: GetData+SetData truncates at a zero byte");
54 System
.Environment
.Exit(1);
56 if (doc
.GetData() == "a\0b") {
57 System
.Console
.WriteLine("XPASS: GetData+SetData doesn't transparently handle a zero byte");
58 System
.Environment
.Exit(1);
60 if (doc
.GetDescription() != "Document(docid=0, data=a)") {
61 System
.Console
.WriteLine("XPASS: UTF-8 encoding of zero byte fixed!");
62 System
.Environment
.Exit(1);
65 // Surrogate pair case:
66 string falafel
= "\U0001f9c6";
68 if (doc
.GetData() != falafel
) {
69 System
.Console
.WriteLine("getData+setData doesn't transparently handle a surrogate pair");
70 System
.Environment
.Exit(1);
72 if (doc
.GetDescription() != "Document(docid=0, data=" + falafel
+ ")") {
73 System
.Console
.WriteLine("GetData+SetData doesn't transparently handle character >= U+10000");
74 System
.Environment
.Exit(1);
77 doc
.SetData("is there anybody out there?");
79 doc
.AddPosting(stem
.Apply("is"), 1);
80 doc
.AddPosting(stem
.Apply("there"), 2);
81 doc
.AddPosting(stem
.Apply("anybody"), 3);
82 doc
.AddPosting(stem
.Apply("out"), 4);
83 doc
.AddPosting(stem
.Apply("there"), 5);
85 Xapian
.WritableDatabase db
= new Xapian
.WritableDatabase("", Xapian
.Xapian
.DB_BACKEND_INMEMORY
);
87 if (db
.GetDocCount() != 1) {
88 System
.Environment
.Exit(1);
91 if (doc
.TermListCount() != 5) {
92 System
.Environment
.Exit(1);
95 Xapian
.TermIterator i
= doc
.TermListBegin();
96 while (i
!= doc
.TermListEnd()) {
101 System
.Environment
.Exit(1);
104 // Check exception handling for Xapian::DocNotFoundError.
106 Xapian
.Document doc2
= db
.GetDocument(2);
107 System
.Console
.WriteLine("Retrieved non-existent document: " + doc2
.GetDescription());
108 System
.Environment
.Exit(1);
109 } catch (System
.Exception e
) {
110 // We expect DocNotFoundError
111 if (e
.Message
.Substring(0, 16) != "DocNotFoundError") {
112 System
.Console
.WriteLine("Unexpected exception from accessing non-existent document: " + e
.Message
);
113 System
.Environment
.Exit(1);
117 Xapian
.QueryParser qp
= new Xapian
.QueryParser();
119 // Check QueryParser parsing error.
121 qp
.ParseQuery("test AND");
122 System
.Console
.WriteLine("Successfully parsed bad query");
123 System
.Environment
.Exit(1);
124 } catch (System
.Exception e
) {
125 if (e
.Message
!= "QueryParserError: Syntax: <expression> AND <expression>") {
126 System
.Console
.WriteLine("Exception string not as expected, got: '" + e
.Message
+ "'");
127 System
.Environment
.Exit(1);
131 // FIXME: It would be better if the (uint) cast wasn't required here.
132 qp
.ParseQuery("hello world", (uint)Xapian
.QueryParser
.feature_flag
.FLAG_BOOLEAN
);
134 // Test wrapping of null-able grouping parameter.
135 qp
.AddBooleanPrefix("colour", "XC");
136 qp
.AddBooleanPrefix("color", "XC");
137 qp
.AddBooleanPrefix("foo", "XFOO", null);
138 qp
.AddBooleanPrefix("bar", "XBAR", "XBA*");
139 qp
.AddBooleanPrefix("baa", "XBAA", "XBA*");
140 // FIXME: It would be better if the (uint) cast wasn't required here.
141 Xapian
.DateRangeProcessor rpdate
= new Xapian
.DateRangeProcessor(1, (uint)Xapian
.Xapian
.RP_DATE_PREFER_MDY
, 1960);
142 qp
.AddRangeprocessor(rpdate
);
143 qp
.AddRangeprocessor(rpdate
, null);
144 qp
.AddRangeprocessor(rpdate
, "foo");
146 if (Xapian
.Query
.MatchAll
.GetDescription() != "Query(<alldocuments>)") {
147 System
.Console
.WriteLine("Unexpected Query.MatchAll.GetDescription()");
148 System
.Environment
.Exit(1);
151 if (Xapian
.Query
.MatchNothing
.GetDescription() != "Query()") {
152 System
.Console
.WriteLine("Unexpected Query.MatchNothing.GetDescription()");
153 System
.Environment
.Exit(1);
156 // Check that OP_ELITE_SET works (in 0.9.6 and earlier it had the
157 // wrong value in C#).
159 Xapian
.Query foo
= new Xapian
.Query(Xapian
.Query
.op
.OP_OR
, "hello", "world");
160 Xapian
.Query foo2
= new Xapian
.Query(Xapian
.Query
.op
.OP_ELITE_SET
, foo
, foo
);
161 foo
= foo2
; // Avoid "unused variable" warning.
162 } catch (System
.Exception e
) {
163 System
.Console
.WriteLine("Using OP_ELITE_SET cause exception '" + e
.Message
+ "'");
164 System
.Environment
.Exit(1);
167 // Feature test for MatchDecider.
168 doc
= new Xapian
.Document();
170 doc
.AddPosting(stem
.Apply("out"), 1);
171 doc
.AddPosting(stem
.Apply("source"), 2);
172 doc
.AddValue(0, "yes");
175 Xapian
.Query query
= new Xapian
.Query(stem
.Apply("out"));
176 Xapian
.Enquire enquire
= new Xapian
.Enquire(db
);
178 // Check Xapian::BAD_VALUENO is wrapped suitably.
179 enquire
.SetCollapseKey(Xapian
.Xapian
.BAD_VALUENO
);
181 enquire
.SetQuery(query
);
182 Xapian
.MSet mset
= enquire
.GetMSet(0, 10, null, new TestMatchDecider());
183 if (mset
.Size() != 1) {
184 System
.Console
.WriteLine("MatchDecider found " + mset
.Size().ToString() + " documents, expected 1");
185 System
.Environment
.Exit(1);
187 if (mset
.GetDocId(0) != 2) {
188 System
.Console
.WriteLine("MatchDecider mset has wrong docid in");
189 System
.Environment
.Exit(1);
192 mset
= enquire
.GetMSet(0, 10);
193 for (Xapian
.MSetIterator m
= mset
.Begin(); m
!= mset
.End(); m
++) {
194 // In Xapian 1.2.6 and earlier, the iterator would become
195 // eligible for garbage collection after being advanced.
196 // It didn't actually get garbage collected often, but when
197 // it did, it caused a crash. Here we force a GC run to make
198 // this issue manifest if it is present.
200 System
.GC
.WaitForPendingFinalizers();
203 // Test setting and getting metadata
204 if (db
.GetMetadata("Foo") != "") {
205 System
.Console
.WriteLine("db.GetMetadata(\"Foo\") returned wrong value \"" + db
.GetMetadata("Foo") + "\" - expected \"\"");
206 System
.Environment
.Exit(1);
208 db
.SetMetadata("Foo", "Foo");
209 if (db
.GetMetadata("Foo") != "Foo") {
210 System
.Console
.WriteLine("db.GetMetadata(\"Foo\") returned wrong value \"" + db
.GetMetadata("Foo") + "\" - expected \"Foo\"");
211 System
.Environment
.Exit(1);
214 // Test OP_SCALE_WEIGHT and corresponding constructor
215 Xapian
.Query query4
= new Xapian
.Query(Xapian
.Query
.op
.OP_SCALE_WEIGHT
, new Xapian
.Query("foo"), 5.0);
216 if (query4
.GetDescription() != "Query(5 * foo)") {
217 System
.Console
.WriteLine("Unexpected query4.GetDescription()");
218 System
.Environment
.Exit(1);
221 } catch (System
.Exception e
) {
222 System
.Console
.WriteLine("Exception: " + e
.ToString());
223 System
.Environment
.Exit(1);