1 /** @file api_metadata.cc
2 * @brief Test the user metadata functionality.
4 /* Copyright (C) 2007,2009,2011 Olly Betts
5 * Copyright (C) 2007,2008,2009 Lemur Consulting Ltd
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
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.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "api_metadata.h"
29 #include "testsuite.h"
30 #include "testutils.h"
36 // Test basic metadata access methods.
37 DEFINE_TESTCASE(metadata1
, writable
) {
38 Xapian::WritableDatabase db
= get_writable_database();
40 TEST_EQUAL(db
.get_metadata("foo"), "");
42 db
.set_metadata("foo", "bar");
43 } catch (const Xapian::UnimplementedError
&) {
44 SKIP_TEST("Metadata not supported by this backend");
46 TEST_EQUAL(db
.get_metadata("foo"), "bar");
47 db
.set_metadata("foo", "baz");
48 TEST_EQUAL(db
.get_doccount(), 0);
49 TEST_EQUAL(db
.get_metadata("foo"), "baz");
50 db
.set_metadata("foo", "");
51 TEST_EQUAL(db
.get_metadata("foo"), "");
53 TEST_EQUAL(db
.get_doccount(), 0);
55 // Check for transparent handling of zero bytes.
56 db
.set_metadata("foo", "value of foo");
57 db
.set_metadata(string("foo\0bar", 7), string(1, '\0'));
58 db
.set_metadata(string("foo\0", 4), string("foo\0bar", 7));
60 TEST_EQUAL(db
.get_metadata("foo"), "value of foo");
61 TEST_EQUAL(db
.get_metadata(string("foo\0bar", 7)), string(1, '\0'));
62 TEST_EQUAL(db
.get_metadata(string("foo\0", 4)), string("foo\0bar", 7));
66 TEST_EQUAL(db
.get_metadata("foo"), "value of foo");
67 TEST_EQUAL(db
.get_metadata(string("foo\0bar", 7)), string(1, '\0'));
68 TEST_EQUAL(db
.get_metadata(string("foo\0", 4)), string("foo\0bar", 7));
73 // Test that metadata gets applied at same time as other changes.
74 DEFINE_TESTCASE(metadata2
, metadata
&& !inmemory
) {
75 Xapian::WritableDatabase db
= get_writable_database();
76 Xapian::Database dbr
= get_writable_database_as_database();
78 TEST_EQUAL(db
.get_metadata("foo"), "");
79 db
.set_metadata("foo", "bar");
80 TEST_EQUAL(db
.get_metadata("foo"), "bar");
81 TEST_EQUAL(dbr
.get_metadata("foo"), "");
83 TEST_EQUAL(dbr
.get_metadata("foo"), "");
85 TEST_EQUAL(db
.get_metadata("foo"), "bar");
86 TEST_EQUAL(dbr
.get_metadata("foo"), "bar");
87 TEST_EQUAL(dbr
.get_doccount(), 0);
89 db
.add_document(Xapian::Document());
90 db
.set_metadata("foo", "baz");
91 TEST_EQUAL(db
.get_doccount(), 1);
92 TEST_EQUAL(db
.get_metadata("foo"), "baz");
95 TEST_EQUAL(dbr
.get_metadata("foo"), "bar");
97 TEST_EQUAL(dbr
.get_metadata("foo"), "baz");
99 db
.set_metadata("foo", "");
100 TEST_EQUAL(db
.get_metadata("foo"), "");
102 TEST_EQUAL(dbr
.get_metadata("foo"), "baz");
104 TEST_EQUAL(dbr
.get_metadata("foo"), "");
106 TEST_EQUAL(db
.get_doccount(), 1);
111 // Test the empty metadata keys give an error correctly.
112 DEFINE_TESTCASE(metadata3
, metadata
) {
113 Xapian::WritableDatabase db
= get_writable_database();
115 TEST_EXCEPTION(Xapian::InvalidArgumentError
, db
.get_metadata(""));
116 TEST_EXCEPTION(Xapian::InvalidArgumentError
, db
.set_metadata("", "foo"));
117 TEST_EXCEPTION(Xapian::InvalidArgumentError
, db
.get_metadata(""));
122 // Regression test for adding a piece of metadata on its own before adding
124 DEFINE_TESTCASE(metadata4
, metadata
&& !inmemory
) {
125 Xapian::WritableDatabase db
= get_writable_database();
127 db
.set_metadata("foo", "foo");
130 Xapian::Document doc
;
131 doc
.add_posting("foo", 1);
132 db
.add_document(doc
);
134 Xapian::Database
dbr(get_writable_database_as_database());
139 // Test metadata iterators.
140 DEFINE_TESTCASE(metadata5
, writable
) {
141 Xapian::WritableDatabase db
= get_writable_database();
143 // Check that iterator on empty database returns nothing.
144 Xapian::TermIterator iter
;
145 iter
= db
.metadata_keys_begin();
146 TEST_EQUAL(iter
, db
.metadata_keys_end());
148 // FIXME: inmemory doesn't implement metadata iterators yet, except in the
149 // trivial case of there being no keys to iterate.
150 SKIP_TEST_FOR_BACKEND("inmemory");
153 db
.set_metadata("foo", "val");
154 } catch (const Xapian::UnimplementedError
&) {
155 SKIP_TEST("Metadata not supported by this backend");
159 // Check iterator on a database with only metadata items.
160 iter
= db
.metadata_keys_begin();
161 TEST(iter
!= db
.metadata_keys_end());
162 TEST_EQUAL(*iter
, "foo");
164 TEST(iter
== db
.metadata_keys_end());
166 // Check iterator on a database with metadata items and documents.
167 Xapian::Document doc
;
168 doc
.add_posting("foo", 1);
169 db
.add_document(doc
);
172 iter
= db
.metadata_keys_begin();
173 TEST(iter
!= db
.metadata_keys_end());
174 TEST_EQUAL(*iter
, "foo");
176 TEST(iter
== db
.metadata_keys_end());
178 // Check iterator on a database with documents but no metadata. Also
179 // checks that setting metadata to empty stops the iterator returning it.
180 db
.set_metadata("foo", "");
182 iter
= db
.metadata_keys_begin();
183 TEST(iter
== db
.metadata_keys_end());
185 // Check use of a prefix, and skip_to.
186 db
.set_metadata("a", "val");
187 db
.set_metadata("foo", "val");
188 db
.set_metadata("foo1", "val");
189 db
.set_metadata("foo2", "val");
190 db
.set_metadata("z", "val");
193 iter
= db
.metadata_keys_begin();
194 TEST(iter
!= db
.metadata_keys_end());
195 TEST_EQUAL(*iter
, "a");
197 TEST(iter
!= db
.metadata_keys_end());
198 TEST_EQUAL(*iter
, "foo");
200 TEST(iter
!= db
.metadata_keys_end());
201 TEST_EQUAL(*iter
, "foo1");
203 TEST(iter
!= db
.metadata_keys_end());
204 TEST_EQUAL(*iter
, "foo2");
206 TEST(iter
!= db
.metadata_keys_end());
207 TEST_EQUAL(*iter
, "z");
209 TEST(iter
== db
.metadata_keys_end());
211 iter
= db
.metadata_keys_begin("foo");
212 TEST(iter
!= db
.metadata_keys_end("foo"));
213 TEST_EQUAL(*iter
, "foo");
215 TEST(iter
!= db
.metadata_keys_end("foo"));
216 TEST_EQUAL(*iter
, "foo1");
218 TEST(iter
!= db
.metadata_keys_end("foo"));
219 TEST_EQUAL(*iter
, "foo2");
221 TEST(iter
== db
.metadata_keys_end("foo"));
223 iter
= db
.metadata_keys_begin("foo1");
224 TEST(iter
!= db
.metadata_keys_end("foo1"));
225 TEST_EQUAL(*iter
, "foo1");
227 TEST(iter
== db
.metadata_keys_end("foo1"));
229 iter
= db
.metadata_keys_begin();
230 TEST(iter
!= db
.metadata_keys_end());
231 TEST_EQUAL(*iter
, "a");
233 // Skip to "" should move to the first key.
235 TEST(iter
!= db
.metadata_keys_end());
236 TEST_EQUAL(*iter
, "a");
238 // This skip_to should skip the "foo" key.
239 iter
.skip_to("foo1");
240 TEST(iter
!= db
.metadata_keys_end());
241 TEST_EQUAL(*iter
, "foo1");
243 // Check that skipping to the current key works.
244 iter
.skip_to("foo1");
245 TEST(iter
!= db
.metadata_keys_end());
246 TEST_EQUAL(*iter
, "foo1");
248 // Check that skip_to a key before the current one doesn't move forwards.
250 TEST(iter
!= db
.metadata_keys_end());
251 TEST_REL(*iter
, <=, "foo1");
253 // Make sure we're back on foo1.
254 iter
.skip_to("foo1");
255 TEST(iter
!= db
.metadata_keys_end());
256 TEST_EQUAL(*iter
, "foo1");
258 // Check that advancing after a skip_to() works correctly.
260 TEST(iter
!= db
.metadata_keys_end());
261 TEST_EQUAL(*iter
, "foo2");
263 // Check that skipping to a key after the last key works.
265 TEST(iter
== db
.metadata_keys_end());
270 /// Regression test of reading after writing but not committing.
271 DEFINE_TESTCASE(writeread1
, writable
&& metadata
) {
272 Xapian::WritableDatabase db_w
= get_writable_database();
273 db_w
.set_metadata("1", "2");
274 string
longitem(20000, 'j');
275 db_w
.set_metadata("2", longitem
);
277 string readitem
= db_w
.get_metadata("2");
278 TEST_EQUAL(readitem
, longitem
);