Branch data Line data Source code
1 : : /** @file api_metadata.cc
2 : : * @brief Test the user metadata functionality.
3 : : */
4 : : /* Copyright (C) 2007,2009 Olly Betts
5 : : * Copyright (C) 2007,2008,2009 Lemur Consulting Ltd
6 : : *
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.
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 USA
20 : : */
21 : :
22 : : #include <config.h>
23 : :
24 : : #include "api_metadata.h"
25 : :
26 : : #include <xapian.h>
27 : :
28 : : #include "apitest.h"
29 : : #include "testsuite.h"
30 : : #include "testutils.h"
31 : :
32 : : #include <string>
33 : :
34 : : using namespace std;
35 : :
36 : : // Test basic metadata access methods.
37 : 10 : DEFINE_TESTCASE(metadata1, writable) {
38 : 10 : Xapian::WritableDatabase db = get_writable_database();
39 : :
40 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_metadata("foo"), "");
41 : : try {
42 : 10 : db.set_metadata("foo", "bar");
43 : 0 : } catch (const Xapian::UnimplementedError &) {
44 [ # # ]: 0 : SKIP_TEST("Metadata not supported by this backend");
45 : : }
46 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_metadata("foo"), "bar");
47 : 10 : db.set_metadata("foo", "baz");
48 [ - + # # ]: 10 : TEST_EQUAL(db.get_doccount(), 0);
49 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_metadata("foo"), "baz");
50 : 10 : db.set_metadata("foo", "");
51 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_metadata("foo"), "");
52 : :
53 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_doccount(), 0);
54 : :
55 : : // Check for transparent handling of zero bytes.
56 : 10 : db.set_metadata("foo", "value of foo");
57 : 10 : db.set_metadata(string("foo\0bar", 7), string(1, '\0'));
58 : 10 : db.set_metadata(string("foo\0", 4), string("foo\0bar", 7));
59 : :
60 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_metadata("foo"), "value of foo");
61 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_metadata(string("foo\0bar", 7)), string(1, '\0'));
62 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_metadata(string("foo\0", 4)), string("foo\0bar", 7));
63 : :
64 : 10 : db.commit();
65 : :
66 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_metadata("foo"), "value of foo");
67 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_metadata(string("foo\0bar", 7)), string(1, '\0'));
68 [ - + ][ # # ]: 10 : TEST_EQUAL(db.get_metadata(string("foo\0", 4)), string("foo\0bar", 7));
69 : :
70 : 10 : return true;
71 : : }
72 : :
73 : : // Test that metadata gets applied at same time as other changes.
74 : 9 : DEFINE_TESTCASE(metadata2, metadata && !inmemory) {
75 : 9 : Xapian::WritableDatabase db = get_writable_database();
76 : 9 : Xapian::Database dbr = get_writable_database_as_database();
77 : :
78 [ - + ][ # # ]: 9 : TEST_EQUAL(db.get_metadata("foo"), "");
79 : 9 : db.set_metadata("foo", "bar");
80 [ - + ][ # # ]: 9 : TEST_EQUAL(db.get_metadata("foo"), "bar");
81 [ - + ][ # # ]: 9 : TEST_EQUAL(dbr.get_metadata("foo"), "");
82 : 9 : db.commit();
83 [ - + ][ # # ]: 9 : TEST_EQUAL(dbr.get_metadata("foo"), "");
84 : 9 : dbr.reopen();
85 [ - + ][ # # ]: 9 : TEST_EQUAL(db.get_metadata("foo"), "bar");
86 [ - + ][ # # ]: 9 : TEST_EQUAL(dbr.get_metadata("foo"), "bar");
87 [ - + ][ # # ]: 9 : TEST_EQUAL(dbr.get_doccount(), 0);
88 : :
89 : 9 : db.add_document(Xapian::Document());
90 : 9 : db.set_metadata("foo", "baz");
91 [ - + # # ]: 9 : TEST_EQUAL(db.get_doccount(), 1);
92 [ - + ][ # # ]: 9 : TEST_EQUAL(db.get_metadata("foo"), "baz");
93 : 9 : db.commit();
94 : :
95 [ - + ][ # # ]: 9 : TEST_EQUAL(dbr.get_metadata("foo"), "bar");
96 : 9 : dbr.reopen();
97 [ - + ][ # # ]: 9 : TEST_EQUAL(dbr.get_metadata("foo"), "baz");
98 : :
99 : 9 : db.set_metadata("foo", "");
100 [ - + ][ # # ]: 9 : TEST_EQUAL(db.get_metadata("foo"), "");
101 : 9 : db.commit();
102 [ - + ][ # # ]: 9 : TEST_EQUAL(dbr.get_metadata("foo"), "baz");
103 : 9 : dbr.reopen();
104 [ - + ][ # # ]: 9 : TEST_EQUAL(dbr.get_metadata("foo"), "");
105 : :
106 [ - + ][ # # ]: 9 : TEST_EQUAL(db.get_doccount(), 1);
107 : :
108 : 9 : return true;
109 : : }
110 : :
111 : : // Test the empty metadata keys give an error correctly.
112 : 10 : DEFINE_TESTCASE(metadata3, metadata) {
113 : 10 : Xapian::WritableDatabase db = get_writable_database();
114 : :
115 [ + - ][ - + ]: 40 : TEST_EXCEPTION(Xapian::InvalidArgumentError, db.get_metadata(""));
[ # # ][ - + ]
116 [ + - ][ - + ]: 60 : TEST_EXCEPTION(Xapian::InvalidArgumentError, db.set_metadata("", "foo"));
[ # # ][ - + ]
117 [ + - ][ - + ]: 40 : TEST_EXCEPTION(Xapian::InvalidArgumentError, db.get_metadata(""));
[ # # ][ - + ]
118 : :
119 : 10 : return true;
120 : : }
121 : :
122 : : // Regression test for adding a piece of metadata on its own before adding
123 : : // other things.
124 : 9 : DEFINE_TESTCASE(metadata4, metadata && !inmemory) {
125 : 9 : Xapian::WritableDatabase db = get_writable_database();
126 : :
127 : 9 : db.set_metadata("foo", "foo");
128 : 9 : db.commit();
129 : :
130 : 9 : Xapian::Document doc;
131 : 9 : doc.add_posting("foo", 1);
132 : 9 : db.add_document(doc);
133 : :
134 : 9 : Xapian::Database dbr(get_writable_database_as_database());
135 : :
136 : 9 : return true;
137 : : }
138 : :
139 : : // Test metadata iterators.
140 : 10 : DEFINE_TESTCASE(metadata5, writable) {
141 : 10 : Xapian::WritableDatabase db = get_writable_database();
142 : :
143 : : // Check that iterator on empty database returns nothing.
144 : 10 : Xapian::TermIterator iter;
145 : 10 : iter = db.metadata_keys_begin();
146 [ - + ][ # # ]: 10 : TEST_EQUAL(iter, db.metadata_keys_end());
147 : :
148 : : // FIXME: inmemory doesn't implement metadata iterators yet, except in the
149 : : // trivial case of there being no keys to iterate.
150 : 12 : SKIP_TEST_FOR_BACKEND("inmemory");
151 : :
152 : : try {
153 : 9 : db.set_metadata("foo", "val");
154 : 0 : } catch (const Xapian::UnimplementedError &) {
155 [ # # ]: 0 : SKIP_TEST("Metadata not supported by this backend");
156 : : }
157 : 9 : db.commit();
158 : :
159 : : // Check iterator on a database with only metadata items.
160 : 9 : iter = db.metadata_keys_begin();
161 [ - + ][ # # ]: 9 : TEST(iter != db.metadata_keys_end());
162 [ - + ][ # # ]: 9 : TEST_EQUAL(*iter, "foo");
163 : 9 : ++iter;
164 [ - + ][ # # ]: 9 : TEST(iter == db.metadata_keys_end());
165 : :
166 : : // Check iterator on a database with metadata items and documents.
167 : 9 : Xapian::Document doc;
168 : 9 : doc.add_posting("foo", 1);
169 : 9 : db.add_document(doc);
170 : 9 : db.commit();
171 : :
172 : 9 : iter = db.metadata_keys_begin();
173 [ - + ][ # # ]: 9 : TEST(iter != db.metadata_keys_end());
174 [ - + ][ # # ]: 9 : TEST_EQUAL(*iter, "foo");
175 : 9 : ++iter;
176 [ - + ][ # # ]: 9 : TEST(iter == db.metadata_keys_end());
177 : :
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 : 9 : db.set_metadata("foo", "");
181 : 9 : db.commit();
182 : 9 : iter = db.metadata_keys_begin();
183 [ - + ][ # # ]: 9 : TEST(iter == db.metadata_keys_end());
184 : :
185 : : // Check use of a prefix, and skip_to.
186 : 9 : db.set_metadata("a", "val");
187 : 9 : db.set_metadata("foo", "val");
188 : 9 : db.set_metadata("foo1", "val");
189 : 9 : db.set_metadata("foo2", "val");
190 : 9 : db.set_metadata("z", "val");
191 : 9 : db.commit();
192 : :
193 : 9 : iter = db.metadata_keys_begin();
194 [ - + ][ # # ]: 9 : TEST(iter != db.metadata_keys_end());
195 [ - + ][ # # ]: 9 : TEST_EQUAL(*iter, "a");
196 : 9 : ++iter;
197 [ - + ][ # # ]: 9 : TEST(iter != db.metadata_keys_end());
198 [ - + ][ # # ]: 9 : TEST_EQUAL(*iter, "foo");
199 : 9 : ++iter;
200 [ - + ][ # # ]: 9 : TEST(iter != db.metadata_keys_end());
201 [ - + ][ # # ]: 9 : TEST_EQUAL(*iter, "foo1");
202 : 9 : ++iter;
203 [ - + ][ # # ]: 9 : TEST(iter != db.metadata_keys_end());
204 [ - + ][ # # ]: 9 : TEST_EQUAL(*iter, "foo2");
205 : 9 : ++iter;
206 [ - + ][ # # ]: 9 : TEST(iter != db.metadata_keys_end());
207 [ - + ][ # # ]: 9 : TEST_EQUAL(*iter, "z");
208 : 9 : ++iter;
209 [ - + ][ # # ]: 9 : TEST(iter == db.metadata_keys_end());
210 : :
211 : 9 : iter = db.metadata_keys_begin("foo");
212 [ - + ][ # # ]: 9 : TEST(iter != db.metadata_keys_end("foo"));
213 [ - + ][ # # ]: 9 : TEST_EQUAL(*iter, "foo");
214 : 9 : ++iter;
215 [ - + ][ # # ]: 9 : TEST(iter != db.metadata_keys_end("foo"));
216 [ - + ][ # # ]: 9 : TEST_EQUAL(*iter, "foo1");
217 : 9 : ++iter;
218 [ - + ][ # # ]: 9 : TEST(iter != db.metadata_keys_end("foo"));
219 [ - + ][ # # ]: 9 : TEST_EQUAL(*iter, "foo2");
220 : 9 : ++iter;
221 [ - + ][ # # ]: 9 : TEST(iter == db.metadata_keys_end("foo"));
222 : :
223 : 9 : iter = db.metadata_keys_begin("foo1");
224 [ - + ][ # # ]: 9 : TEST(iter != db.metadata_keys_end("foo1"));
225 [ - + ][ # # ]: 9 : TEST_EQUAL(*iter, "foo1");
226 : 9 : ++iter;
227 [ - + ][ # # ]: 9 : TEST(iter == db.metadata_keys_end("foo1"));
228 : :
229 : 9 : iter = db.metadata_keys_begin();
230 [ - + ][ # # ]: 9 : TEST(iter != db.metadata_keys_end());
231 [ - + ][ # # ]: 9 : TEST_EQUAL(*iter, "a");
232 : :
233 : : // Skip to "" should move to the first key.
234 : 9 : iter.skip_to("");
235 [ - + ][ # # ]: 9 : TEST(iter != db.metadata_keys_end());
236 [ - + ][ # # ]: 9 : TEST_EQUAL(*iter, "a");
237 : :
238 : : // This skip_to should skip the "foo" key.
239 : 9 : iter.skip_to("foo1");
240 [ - + ][ # # ]: 9 : TEST(iter != db.metadata_keys_end());
241 [ - + ][ # # ]: 9 : TEST_EQUAL(*iter, "foo1");
242 : :
243 : : // Check that skipping to the current key works.
244 : 9 : iter.skip_to("foo1");
245 [ - + ][ # # ]: 9 : TEST(iter != db.metadata_keys_end());
246 [ - + ][ # # ]: 9 : TEST_EQUAL(*iter, "foo1");
247 : :
248 : : // Check that skip_to a key before the current one doesn't move forwards.
249 : 9 : iter.skip_to("a");
250 [ - + ][ # # ]: 9 : TEST(iter != db.metadata_keys_end());
251 [ - + ][ # # ]: 9 : TEST_REL(*iter, <=, "foo1");
252 : :
253 : : // Make sure we're back on foo1.
254 : 9 : iter.skip_to("foo1");
255 [ - + ][ # # ]: 9 : TEST(iter != db.metadata_keys_end());
256 [ - + ][ # # ]: 9 : TEST_EQUAL(*iter, "foo1");
257 : :
258 : : // Check that advancing after a skip_to() works correctly.
259 : 9 : ++iter;
260 [ - + ][ # # ]: 9 : TEST(iter != db.metadata_keys_end());
261 [ - + ][ # # ]: 9 : TEST_EQUAL(*iter, "foo2");
262 : :
263 : : // Check that skipping to a key after the last key works.
264 : 9 : iter.skip_to("zoo");
265 [ - + ][ # # ]: 9 : TEST(iter == db.metadata_keys_end());
266 : :
267 : 11 : return true;
268 : : }
269 : :
270 : : /// Regression test of reading after writing but not committing.
271 : 10 : DEFINE_TESTCASE(writeread1, writable && metadata) {
272 : 10 : Xapian::WritableDatabase db_w = get_writable_database();
273 : 10 : db_w.set_metadata("1", "2");
274 : 10 : string longitem(20000, 'j');
275 : 10 : db_w.set_metadata("2", longitem);
276 : :
277 : 10 : string readitem = db_w.get_metadata("2");
278 [ - + # # ]: 10 : TEST_EQUAL(readitem, longitem);
279 : :
280 : 10 : return true;
281 : : }
|