Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
test-table-patricia-trie-cursor.c
Go to the documentation of this file.
1 /* -*- c-basic-offset: 2; coding: utf-8 -*- */
2 /*
3  Copyright (C) 2010-2011 Kouhei Sutou <kou@clear-code.com>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public
7  License version 2.1 as published by the Free Software Foundation.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Lesser General Public License for more details.
13 
14  You should have received a copy of the GNU Lesser General Public
15  License along with this library; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #include <groonga.h>
20 #include <db.h>
21 
22 #include <gcutter.h>
23 #include <glib/gstdio.h>
24 
25 #include "../lib/grn-assertions.h"
26 
27 #define COORDINATE(hours, minutes, seconds) \
28  GRN_TEST_GEO_COORDINATE(hours, minutes, seconds)
29 
30 #define POINT(latitude_hours, latitude_minutes, latitude_seconds, \
31  longitude_hours, longitude_minutes, longitude_seconds) \
32  GRN_TEST_GEO_POINT_STRING( \
33  COORDINATE(latitude_hours, latitude_minutes, latitude_seconds), \
34  COORDINATE(longitude_hours, longitude_minutes, longitude_seconds))
35 
36 #define TAKEN_POINT(latitude_hours, latitude_minutes, latitude_seconds, \
37  longitude_hours, longitude_minutes, longitude_seconds) \
38  cut_take_string(POINT(latitude_hours, latitude_minutes, latitude_seconds, \
39  longitude_hours, longitude_minutes, longitude_seconds))
40 
41 void data_prefix_error(void);
42 void test_prefix_error(gpointer data);
43 void data_prefix_short_text(void);
44 void test_prefix_short_text(gpointer data);
45 void data_prefix_geo_point(void);
46 void test_prefix_geo_point(gpointer data);
47 void data_prefix_rk(void);
48 void test_prefix_rk(gpointer data);
49 void data_near_uint32(void);
50 void test_near_uint32(gpointer data);
51 void data_near_geo_point(void);
52 void test_near_geo_point(gpointer data);
53 void data_common_prefix_search(void);
54 void test_common_prefix_search(gpointer data);
55 void data_by_id_encoded(void);
56 void test_by_id_encoded(gpointer data);
57 
58 static gchar *tmp_directory;
59 
60 static grn_ctx *context;
61 static grn_obj *database, *table;
62 static grn_table_cursor *cursor;
63 
64 void
66 {
67  tmp_directory = g_build_filename(grn_test_get_tmp_dir(),
68  "table-patricia-trie-cursor",
69  NULL);
70 }
71 
72 void
74 {
75  g_free(tmp_directory);
76  cut_remove_path(grn_test_get_tmp_dir(), NULL);
77 }
78 
79 static void
80 remove_tmp_directory(void)
81 {
82  cut_remove_path(tmp_directory, NULL);
83 }
84 
85 void
86 cut_setup(void)
87 {
88  const gchar *database_path;
89 
90  remove_tmp_directory();
91  g_mkdir_with_parents(tmp_directory, 0700);
92 
93  context = g_new0(grn_ctx, 1);
94  grn_ctx_init(context, 0);
95 
96  database_path = cut_build_path(tmp_directory, "database.groonga", NULL);
97  database = grn_db_create(context, database_path, NULL);
98  table = NULL;
99  cursor = NULL;
100 }
101 
102 void
104 {
105  if (cursor) {
106  grn_obj_unlink(context, cursor);
107  }
108 
109  if (table) {
110  grn_obj_unlink(context, table);
111  }
112 
113  grn_obj_close(context, database);
114  grn_ctx_fin(context);
115  g_free(context);
116 }
117 
118 static void
119 create_short_text_table(const GList *texts)
120 {
121  const gchar *table_name = "ShortTextPat";
122  GString *command;
123  const GList *node;
124 
126  cut_take_printf("table_create %s TABLE_PAT_KEY ShortText", table_name));
127 
128  command = g_string_new(NULL);
129  g_string_append_printf(command, "load --table %s\n", table_name);
130  g_string_append(command, "[\n");
131  g_string_append(command, " [\"_key\"],\n");
132  for (node = texts; node; node = g_list_next(node)) {
133  const gchar *text = node->data;
134  g_string_append_printf(command, " [\"%s\"]", text);
135  if (g_list_next(node)) {
136  g_string_append(command, ",");
137  }
138  g_string_append(command, "\n");
139  }
140  g_string_append(command, "]");
141  assert_send_commands(cut_take_string(g_string_free(command, FALSE)));
142 
143  table = grn_ctx_get(context, table_name, strlen(table_name));
144 }
145 
146 static void
147 create_uint32_table(void)
148 {
149  const char *table_name = "UInt32Pat";
150 
152  cut_take_printf("table_create %s TABLE_PAT_KEY UInt32", table_name));
154  cut_take_printf("load --table %s\n"
155  "[\n"
156  " [\"_key\"],\n"
157  " [%u],"
158  " [%u],"
159  " [%u],"
160  " [%u],"
161  " [%u]"
162  "]",
163  table_name,
164  0x00000000U,
165  0x00000004U,
166  0x00000080U,
167  0xdeadbeefU,
168  0xffffffffU));
169 
170  table = grn_ctx_get(context, table_name, strlen(table_name));
171 }
172 
173 static void
174 create_geo_point_table(const gchar *data)
175 {
176  const char *table_name = "GeoPointPat";
177 
179  cut_take_printf("table_create %s TABLE_PAT_KEY WGS84GeoPoint", table_name));
181  cut_take_printf("load --table %s\n"
182  "[\n"
183  " [\"_key\"],\n"
184  "%s"
185  "]",
186  table_name,
187  data));
188 
189  table = grn_ctx_get(context, table_name, strlen(table_name));
190 }
191 
192 static void
193 cast_to_geo_point(grn_obj *geo_point, const gchar *geo_point_string)
194 {
195  grn_obj geo_point_text;
196 
197  if (!geo_point_string) {
198  return;
199  }
200 
201  GRN_TEXT_INIT(&geo_point_text, 0);
202  GRN_TEXT_PUTS(context, &geo_point_text, geo_point_string);
203  grn_obj_cast(context, &geo_point_text, geo_point, FALSE);
204  grn_obj_unlink(context, &geo_point_text);
205 }
206 
207 void
209 {
210 #define ADD_DATA(label, rc, message, offset, limit) \
211  gcut_add_datum(label, \
212  "rc", G_TYPE_UINT, rc, \
213  "message", G_TYPE_STRING, message, \
214  "offset", G_TYPE_INT, offset, \
215  "limit", G_TYPE_INT, limit, \
216  NULL)
217 
218  ADD_DATA("negative offset",
220  "can't use negative offset with GRN_CURSOR_PREFIX: -1",
221  -1, -1);
222  ADD_DATA("large offset",
224  "offset is rather than table size: offset:100, table_size:8",
225  100, -1);
226  ADD_DATA("negative limit",
228  "can't use small limit rather than -1 with GRN_CURSOR_PREFIX: -2",
229  0, -2);
230 
231 #undef ADD_DATA
232 }
233 
234 void
235 test_prefix_error(gpointer data)
236 {
237  const gchar *min = "ab";
238  int offset, limit;
239 
240  create_short_text_table(gcut_take_new_list_string("abra",
241  "abracada",
242  "abracadabra",
243  "abubu",
244  "あ",
245  "ああ",
246  "あああ",
247  "い",
248  NULL));
249 
250  offset = gcut_data_get_int(data, "offset");
251  limit = gcut_data_get_int(data, "limit");
252  cursor = grn_table_cursor_open(context, table,
253  min, strlen(min),
254  NULL, 0,
255  offset, limit,
257  grn_test_assert_error(gcut_data_get_uint(data, "rc"),
258  gcut_data_get_string(data, "message"),
259  context);
260 }
261 
262 void
264 {
265 #define ADD_DATA(label, expected, min, offset, limit, flags) \
266  gcut_add_datum(label, \
267  "expected", G_TYPE_POINTER, \
268  expected, gcut_list_string_free, \
269  "min", G_TYPE_STRING, min, \
270  "offset", G_TYPE_INT, offset, \
271  "limit", G_TYPE_INT, limit, \
272  "flags", G_TYPE_INT, flags, \
273  NULL)
274 
275  ADD_DATA("alphabet - ascending",
276  gcut_list_string_new("abra", "abracada", "abracadabra", "abubu",
277  NULL),
278  "ab",
279  0, -1,
280  0);
281  ADD_DATA("alphabet - descending",
282  gcut_list_string_new("abubu", "abracadabra", "abracada", "abra",
283  NULL),
284  "ab",
285  0, -1,
287  ADD_DATA("alphabet - ascending - greater than",
288  gcut_list_string_new("abracada", "abracadabra", NULL),
289  "abra",
290  0, -1,
291  GRN_CURSOR_GT);
292  ADD_DATA("alphabet - descending - greater than",
293  gcut_list_string_new("abracadabra", "abracada", NULL),
294  "abra",
295  0, -1,
297  ADD_DATA("alphabet - offset and limit",
298  gcut_list_string_new("abracadabra", NULL),
299  "ab",
300  2, 1,
301  0);
302  ADD_DATA("no match",
303  NULL,
304  "bubuzera",
305  0, -1,
306  0);
307  ADD_DATA("no match - common prefix",
308  NULL,
309  "abraura",
310  0, -1,
311  0);
312  ADD_DATA("empty key",
313  gcut_list_string_new("abra", "abracada", "abracadabra", "abubu",
314  "あ", "ああ", "あああ", "い",
315  NULL),
316  "",
317  0, -1,
318  0);
319  {
320  gchar *long_key;
321  long_key = g_alloca(GRN_TABLE_MAX_KEY_SIZE + 2);
322  memset(long_key, 'a', GRN_TABLE_MAX_KEY_SIZE + 1);
323  ADD_DATA("long key",
324  NULL,
325  long_key,
326  0, -1,
327  0);
328  }
329 
330 #undef ADD_DATA
331 }
332 
333 void
335 {
336  grn_id id;
337  const gchar *min;
338  int offset, limit, flags;
339  const GList *expected_keys;
340  GList *actual_keys = NULL;
341 
342  create_short_text_table(gcut_take_new_list_string("abra",
343  "abracada",
344  "abracadabra",
345  "abubu",
346  "あ",
347  "ああ",
348  "あああ",
349  "い",
350  NULL));
351 
352  min = gcut_data_get_string(data, "min");
353  offset = gcut_data_get_int(data, "offset");
354  limit = gcut_data_get_int(data, "limit");
355  flags = gcut_data_get_int(data, "flags");
356  cursor = grn_table_cursor_open(context, table,
357  min, strlen(min),
358  NULL, 0,
359  offset, limit,
360  flags | GRN_CURSOR_PREFIX);
361  grn_test_assert_context(context);
362  while ((id = grn_table_cursor_next(context, cursor))) {
363  gchar *key;
364  int key_size;
365 
366  key_size = grn_table_cursor_get_key(context, cursor, (void **)&key);
367  actual_keys = g_list_append(actual_keys, g_strndup(key, key_size));
368  }
369  gcut_take_list(actual_keys, g_free);
370 
371  expected_keys = gcut_data_get_pointer(data, "expected");
372  gcut_assert_equal_list_string(expected_keys, actual_keys);
373 }
374 
375 static const gchar *
376 geo_byte_parse(const gchar *geo_byte_string)
377 {
378  gint i = 0;
379  uint8_t geo_byte[sizeof(grn_geo_point)];
380  grn_geo_point geo_point;
381 
382  while (geo_byte_string[0]) {
383  switch (geo_byte_string[0]) {
384  case '0':
385  geo_byte[i / 8] &= ~(1 << (7 - (i % 8)));
386  i++;
387  break;
388  case '1':
389  geo_byte[i / 8] |= 1 << (7 - (i % 8));
390  i++;
391  break;
392  default:
393  break;
394  }
395  geo_byte_string++;
396  }
397  grn_ntog((uint8_t *)(&geo_point), geo_byte, sizeof(grn_geo_point));
398  return cut_take_printf("%dx%d",
399  geo_point.latitude,
400  geo_point.longitude);
401 }
402 
403 static GList *
404 geo_byte_list_new_va_list(const gchar *value, va_list args)
405 {
406  GList *list = NULL;
407 
408  while (value) {
409  list = g_list_prepend(list, g_strdup(geo_byte_parse(value)));
410  value = va_arg(args, const gchar *);
411  }
412 
413  return g_list_reverse(list);
414 }
415 
416 static const gchar *
417 geo_byte_load_data(const gchar *value, ...)
418 {
419  GString *data;
420  GList *list, *node;
421  va_list args;
422 
423  va_start(args, value);
424  list = geo_byte_list_new_va_list(value, args);
425  va_end(args);
426 
427  data = g_string_new(NULL);
428  for (node = list; node; node = g_list_next(node)) {
429  const gchar *point = node->data;
430  g_string_append_printf(data, "[\"%s\"]", point);
431  if (g_list_next(node)) {
432  g_string_append_printf(data, ",\n");
433  }
434  }
435  gcut_list_string_free(list);
436 
437  return cut_take_string(g_string_free(data, FALSE));
438 }
439 
440 void
442 {
443 #define ADD_DATA(label, expected, min, min_size, offset, limit, flags) \
444  gcut_add_datum(label, \
445  "expected", G_TYPE_POINTER, \
446  expected, gcut_list_string_free, \
447  "min", G_TYPE_STRING, min, \
448  "min-size", G_TYPE_UINT, min_size, \
449  "offset", G_TYPE_INT, offset, \
450  "limit", G_TYPE_INT, limit, \
451  "flags", G_TYPE_INT, flags, \
452  NULL)
453 
454  ADD_DATA(
455  "bit - ascending",
456  gcut_list_string_new(
457  "00000000 00111111 01010000 00000000 01111101 00010000 00011101 00001111",
458  "00000000 00111111 01010000 00000001 00011110 01010001 01101001 00110000",
459  "00000000 00111111 01010000 00001101 01011101 01011011 01011001 01010011",
460  "00000000 00111111 01010000 00001111 00101011 00011111 00110011 00001001",
461  "00000000 00111111 01010000 00010010 00110001 00001000 00001010 00110011",
462  "00000000 00111111 01010000 00010010 00110001 00110111 01111000 01110000",
463  "00000000 00111111 01010000 00011000 01110000 00001011 00101110 01001010",
464  "00000000 00111111 01010000 00100000 00010111 01000111 00110100 00101010",
465  "00000000 00111111 01010000 00100010 00100111 01000011 00000010 01101001",
466  "00000000 00111111 01010000 00100010 00111011 01000000 00111000 01100100",
467  "00000000 00111111 01010000 00100011 00000001 00000111 01011100 01110011",
468  "00000000 00111111 01010000 00100011 00001010 00000000 00001101 00111010",
469  "00000000 00111111 01010000 00100011 01100100 01011000 00000111 01110010",
470  "00000000 00111111 01010000 00101101 00101000 00111111 01010110 00010110",
471  "00000000 00111111 01010000 00101101 01111100 01101100 00111000 01111001",
472  "00000000 00111111 01010000 00101110 01010011 00101001 00101001 00100011",
473  "00000000 00111111 01010000 00101110 01110010 00111001 00011011 01101010",
474  "00000000 00111111 01010000 00101111 00011000 01000110 00100101 01011110",
475  "00000000 00111111 01010000 00101111 01001010 01101000 01000100 01100011",
476  "00000000 00111111 01010000 00110000 01001010 01011100 01101010 00010001",
477  "00000000 00111111 01010000 00111000 01100100 01101011 01111100 01111011",
478  "00000000 00111111 01010000 00111001 00111101 00001001 00001011 01010011",
479  "00000000 00111111 01010000 00111010 01011111 00000010 00101001 01010000",
480  NULL),
481  "00000000 00111111 01010000 00000000 00000000 00000000 00000000 00000000",
482  26,
483  0, -1,
485  ADD_DATA(
486  "bit - descending",
487  gcut_list_string_new(
488  "00000000 00111111 01010000 00111010 01011111 00000010 00101001 01010000",
489  "00000000 00111111 01010000 00111001 00111101 00001001 00001011 01010011",
490  "00000000 00111111 01010000 00111000 01100100 01101011 01111100 01111011",
491  "00000000 00111111 01010000 00110000 01001010 01011100 01101010 00010001",
492  "00000000 00111111 01010000 00101111 01001010 01101000 01000100 01100011",
493  "00000000 00111111 01010000 00101111 00011000 01000110 00100101 01011110",
494  "00000000 00111111 01010000 00101110 01110010 00111001 00011011 01101010",
495  "00000000 00111111 01010000 00101110 01010011 00101001 00101001 00100011",
496  "00000000 00111111 01010000 00101101 01111100 01101100 00111000 01111001",
497  "00000000 00111111 01010000 00101101 00101000 00111111 01010110 00010110",
498  "00000000 00111111 01010000 00100011 01100100 01011000 00000111 01110010",
499  "00000000 00111111 01010000 00100011 00001010 00000000 00001101 00111010",
500  "00000000 00111111 01010000 00100011 00000001 00000111 01011100 01110011",
501  "00000000 00111111 01010000 00100010 00111011 01000000 00111000 01100100",
502  "00000000 00111111 01010000 00100010 00100111 01000011 00000010 01101001",
503  "00000000 00111111 01010000 00100000 00010111 01000111 00110100 00101010",
504  "00000000 00111111 01010000 00011000 01110000 00001011 00101110 01001010",
505  "00000000 00111111 01010000 00010010 00110001 00110111 01111000 01110000",
506  "00000000 00111111 01010000 00010010 00110001 00001000 00001010 00110011",
507  "00000000 00111111 01010000 00001111 00101011 00011111 00110011 00001001",
508  "00000000 00111111 01010000 00001101 01011101 01011011 01011001 01010011",
509  "00000000 00111111 01010000 00000001 00011110 01010001 01101001 00110000",
510  "00000000 00111111 01010000 00000000 01111101 00010000 00011101 00001111",
511  NULL),
512  "00000000 00111111 01010000 00000000 00000000 00000000 00000000 00000000",
513  26,
514  0, -1,
516  ADD_DATA(
517  "bit - different prefix",
518  gcut_list_string_new(
519  "00000000 00111101 01010101 00111101 01110000 01001011 01110011 00101100",
520  NULL),
521  "00000000 00111101 01010101 00111101 01110000 00000000 00000000 00000001",
522  38,
523  0, -1,
525  ADD_DATA(
526  "bit - border prefix",
527  gcut_list_string_new(
528  "00000000 00111101 00000101 00111101 01110000 01001011 01110011 00101100",
529  NULL),
530  "00000000 00111101 00000101 00111101 01110000 00000000 00000000 00000001",
531  18,
532  0, -1,
534 
535 #undef ADD_DATA
536 }
537 
538 void
539 test_prefix_geo_point(gpointer data)
540 {
541  grn_id id;
542  grn_obj min;
543  int offset, limit, flags;
544  unsigned min_size;
545  const GList *expected_keys;
546  GList *actual_keys = NULL;
547  GRN_WGS84_GEO_POINT_INIT(&min, 0);
548 
549  create_geo_point_table(
550  geo_byte_load_data(
551  "00000000 00111111 01010000 00110000 01001010 01011100 01101010 00010001",
552  "00000000 00111111 01010000 00001101 01011101 01011011 01011001 01010011",
553  "00000000 00111111 01010000 00000001 00011110 01010001 01101001 00110000",
554  "00000000 00111111 01010000 00011000 01110000 00001011 00101110 01001010",
555  "00000000 00111111 01010000 00010010 00110001 00110111 01111000 01110000",
556  "00000000 00111111 01010000 00010010 00110001 00001000 00001010 00110011",
557  "00000000 00111111 01010000 00101110 01110010 00111001 00011011 01101010",
558  "00000000 00111111 01010000 00101101 00101000 00111111 01010110 00010110",
559  "00000000 00111111 01010000 00101111 01001010 01101000 01000100 01100011",
560  "00000000 00111111 01010000 00101111 00011000 01000110 00100101 01011110",
561  "00000000 00111111 01000101 01011001 01010110 00000111 00110100 01111111",
562  "00000000 00111111 01000101 01010010 01100101 01100110 00010111 01111110",
563  "00000000 00111111 01000101 01111111 01011011 01111101 00001001 01100001",
564  "00000000 00111111 01010000 00100011 00001010 00000000 00001101 00111010",
565  "00000000 00111111 01010000 00101110 01010011 00101001 00101001 00100011",
566  "00000000 00111111 01010000 00111010 01011111 00000010 00101001 01010000",
567  "00000000 00111111 01010000 00111001 00111101 00001001 00001011 01010011",
568  "00000000 00111111 01000101 01011100 00001100 01000001 01011010 00010011",
569  "00000000 00111111 01010000 00100011 00000001 00000111 01011100 01110011",
570  "00000000 00111111 01010000 00100011 01100100 01011000 00000111 01110010",
571  "00000000 00111111 01010000 00111000 01100100 01101011 01111100 01111011",
572  "00000000 00111111 01010000 00001111 00101011 00011111 00110011 00001001",
573  "00000000 00111111 01000101 01111011 01001011 01101011 00001001 00000001",
574  "00000000 00111111 01000101 01011010 00110100 00000010 01111010 00000000",
575  "00000000 00111111 01000101 01011011 00011010 00010111 00011000 00100000",
576  "00000000 00111111 01010000 00100000 00010111 01000111 00110100 00101010",
577  "00000000 00111111 01010000 00000000 01111101 00010000 00011101 00001111",
578  "00000000 00111111 01000101 01000100 01010010 00100100 01100011 00111011",
579  "00000000 00111111 01000101 01010001 00011100 01010110 00100110 00000110",
580  "00000000 00111111 01010000 00101101 01111100 01101100 00111000 01111001",
581  "00000000 00111111 01000101 01001101 00111110 00000101 00101010 01000101",
582  "00000000 00111111 01000101 01000100 01111100 01101011 01101111 00010101",
583  "00000000 00111111 01000101 01110111 01010100 01110100 01111000 01111000",
584  "00000000 00111111 01010000 00100010 00111011 01000000 00111000 01100100",
585  "00000000 00111111 01010000 00100010 00100111 01000011 00000010 01101001",
586  "00000000 00111111 01000101 01011100 00110110 00100010 00111000 01100001",
587  "00000000 00111101 01010101 00111101 01110000 01001011 01110011 00101100",
588  "00000000 00111101 00000101 00111101 01110000 01001011 01110011 00101100",
589  NULL));
590 
591  cast_to_geo_point(&min, geo_byte_parse(gcut_data_get_string(data, "min")));
592 
593  min_size = gcut_data_get_uint(data, "min-size");
594  offset = gcut_data_get_int(data, "offset");
595  limit = gcut_data_get_int(data, "limit");
596  flags = gcut_data_get_int(data, "flags");
597  cursor = grn_table_cursor_open(context, table,
598  GRN_BULK_HEAD(&min), min_size,
599  NULL, 0,
600  offset, limit,
601  flags | GRN_CURSOR_PREFIX);
602  grn_obj_unlink(context, &min);
603  grn_test_assert_context(context);
604  while ((id = grn_table_cursor_next(context, cursor))) {
605  grn_geo_point *key;
606  int i, j, key_size;
607  uint8_t encoded_key[sizeof(grn_geo_point)];
608  GString *geo_byte;
609 
610  key_size = grn_table_cursor_get_key(context, cursor, (void **)&key);
611  grn_gton(encoded_key, key, key_size);
612  geo_byte = g_string_new(NULL);
613  for (i = 0; i < sizeof(grn_geo_point); i++) {
614  if (i != 0) {
615  g_string_append(geo_byte, " ");
616  }
617  for (j = 0; j < 8; j++) {
618  g_string_append_printf(geo_byte, "%d", (encoded_key[i] >> (7 - j)) & 1);
619  }
620  }
621  actual_keys = g_list_append(actual_keys, g_string_free(geo_byte, FALSE));
622  }
623  gcut_take_list(actual_keys, g_free);
624 
625  expected_keys = gcut_data_get_pointer(data, "expected");
626  gcut_assert_equal_list_string(expected_keys, actual_keys);
627 }
628 
629 #define ADD_DATA(label, expected, min, offset, limit) \
630  gcut_add_datum(label " - [" min "]", \
631  "expected", G_TYPE_POINTER, \
632  expected, gcut_list_string_free, \
633  "min", G_TYPE_STRING, min, \
634  "offset", G_TYPE_INT, offset, \
635  "limit", G_TYPE_INT, limit, \
636  NULL)
637 
638 static void
639 data_prefix_rk_basic(void)
640 {
641  ADD_DATA("roman - 1byte",
642  gcut_list_string_new("カネソナエタ",
643  "カノウ",
644  "キノウ",
645  "キョウカ",
646  "クミコミ",
647  "クミコム",
648  "ケンサク",
649  "ケンサクヨウキュウ",
650  "コウセイド",
651  "コウソク",
652  "コンパクト",
653  NULL),
654  "k",
655  0, -1);
656  ADD_DATA("ひらがな",
657  gcut_list_string_new("コウセイド",
658  "コウソク",
659  NULL),
660  "こう",
661  0, -1);
662  ADD_DATA("カタカナ",
663  gcut_list_string_new("コウセイド",
664  "コウソク",
665  NULL),
666  "コウ",
667  0, -1);
668  ADD_DATA("ひらがな and カタカナ",
669  gcut_list_string_new("コウセイド",
670  "コウソク",
671  NULL),
672  "こウ",
673  0, -1);
674 }
675 
676 static void
677 data_prefix_rk_xtsu(void)
678 {
679  ADD_DATA("roman - ッ - full",
680  gcut_list_string_new("インデックス",
681  NULL),
682  "indekk",
683  0, -1);
684  ADD_DATA("roman - ッ - half",
685  gcut_list_string_new("インデックス",
686  NULL),
687  "indek",
688  0, -1);
689  ADD_DATA("roman - ック - half",
690  gcut_list_string_new("インデックス",
691  NULL),
692  "indekk",
693  0, -1);
694  ADD_DATA("roman - xtu - half",
695  gcut_list_string_new("インデックス",
696  NULL),
697  "indextu",
698  0, -1);
699  ADD_DATA("roman - xtsu - half",
700  gcut_list_string_new("インデックス",
701  NULL),
702  "indextsu",
703  0, -1);
704  ADD_DATA("roman - ltu - half",
705  gcut_list_string_new("インデックス",
706  NULL),
707  "indeltu",
708  0, -1);
709  ADD_DATA("roman - ltsu - half",
710  gcut_list_string_new("インデックス",
711  NULL),
712  "indeltsu",
713  0, -1);
714  ADD_DATA("ひらがな - ッ",
715  gcut_list_string_new("インデックス",
716  NULL),
717  "いんでっ",
718  0, -1);
719  ADD_DATA("カタカナ - ッ",
720  gcut_list_string_new("インデックス",
721  NULL),
722  "インデッ",
723  0, -1);
724 }
725 
726 static void
727 data_prefix_rk_xyu(void)
728 {
729  ADD_DATA("roman - ュ - full",
730  gcut_list_string_new("ヨウキュウ",
731  NULL),
732  "youkyu",
733  0, -1);
734  ADD_DATA("roman - ュ - x",
735  gcut_list_string_new("ヨウキュウ",
736  NULL),
737  "youkix",
738  0, -1);
739  ADD_DATA("roman - ュ - xy",
740  gcut_list_string_new("ヨウキュウ",
741  NULL),
742  "youkixy",
743  0, -1);
744  ADD_DATA("roman - ュ - xyu",
745  gcut_list_string_new("ヨウキュウ",
746  NULL),
747  "youkixyu",
748  0, -1);
749  ADD_DATA("roman - ュ - ly",
750  gcut_list_string_new("ヨウキュウ",
751  NULL),
752  "youkily",
753  0, -1);
754  ADD_DATA("roman - ュ - lyu",
755  gcut_list_string_new("ヨウキュウ",
756  NULL),
757  "youkilyu",
758  0, -1);
759  ADD_DATA("ひらがな - ュ",
760  gcut_list_string_new("ヨウキュウ",
761  NULL),
762  "ようきゅ",
763  0, -1);
764  ADD_DATA("カタカナ - ュ",
765  gcut_list_string_new("ヨウキュウ",
766  NULL),
767  "ヨウキュ",
768  0, -1);
769 }
770 
771 static void
772 data_prefix_rk_offset_and_limit(void)
773 {
774  ADD_DATA("offset",
775  gcut_list_string_new("キノウ",
776  "キョウカ",
777  "クミコミ",
778  "クミコム",
779  "ケンサクヨウキュウ",
780  "コウセイド",
781  "コウソク",
782  "コンパクト",
783  NULL),
784  "k",
785  3, -1);
786  ADD_DATA("limit",
787  gcut_list_string_new("カネソナエタ",
788  "カノウ",
789  "ケンサク",
790  NULL),
791  "k",
792  0, 3);
793  ADD_DATA("offset - limit",
794  gcut_list_string_new("キノウ",
795  "キョウカ",
796  "ケンサクヨウキュウ",
797  "コウセイド",
798  "コウソク",
799  NULL),
800  "k",
801  3, 5);
802 }
803 
804 static void
805 data_prefix_rk_no_match(void)
806 {
807  ADD_DATA("roman - no match",
808  NULL,
809  "kumikomuy",
810  0, -1);
811  ADD_DATA("roman - upcase - no match",
812  NULL,
813  "K",
814  0, -1);
815  ADD_DATA("ひらがな - no match",
816  NULL,
817  "くみこむよ",
818  0, -1);
819  ADD_DATA("カタカナ - no match",
820  NULL,
821  "クミコムヨ",
822  0, -1);
823 }
824 
825 void
827 {
828  data_prefix_rk_basic();
829  data_prefix_rk_xtsu();
830  data_prefix_rk_xyu();
831  data_prefix_rk_offset_and_limit();
832  data_prefix_rk_no_match();
833 }
834 #undef ADD_DATA
835 
836 void
837 test_prefix_rk(gpointer data)
838 {
839  grn_id id;
840  const gchar *min;
841  int offset, limit;
842  const GList *expected_keys;
843  GList *actual_keys = NULL;
844 
845  create_short_text_table(
846  gcut_take_new_list_string("インデックス",
847  "エヌグラム",
848  "エンジン",
849  "カネソナエタ",
850  "カノウ",
851  "キノウ",
852  "キョウカ",
853  "クミコミ",
854  "クミコム",
855  "グルンガ",
856  "ケンサク",
857  "ケンサクヨウキュウ",
858  "ゲンゴ",
859  "コウセイド",
860  "コウソク",
861  "コンパクト",
862  "サクセイ",
863  "ショリ",
864  "ショリケイ",
865  "ジッソウ",
866  "ジュンスイ",
867  "スクリプト",
868  "セッケイ",
869  "ゼンブン",
870  "タイプ",
871  "タンゴ",
872  "ダイキボ",
873  "テンチ",
874  "ディービーエムエス",
875  "トウ",
876  "トクチョウ",
877  "ブンショリョウ",
878  "ヨウキュウ",
879  NULL));
880 
881  min = gcut_data_get_string(data, "min");
882  offset = gcut_data_get_int(data, "offset");
883  limit = gcut_data_get_int(data, "limit");
884  cursor = grn_table_cursor_open(context, table,
885  min, strlen(min),
886  NULL, 0,
887  offset, limit,
889  grn_test_assert_context(context);
890  while ((id = grn_table_cursor_next(context, cursor))) {
891  gchar *key;
892  int key_size;
893 
894  key_size = grn_table_cursor_get_key(context, cursor, (void **)&key);
895  actual_keys = g_list_append(actual_keys, g_strndup(key, key_size));
896  }
897  actual_keys = g_list_sort(actual_keys, (GCompareFunc)strcmp);
898  gcut_take_list(actual_keys, g_free);
899 
900  expected_keys = gcut_data_get_pointer(data, "expected");
901  gcut_assert_equal_list_string(expected_keys, actual_keys);
902 }
903 
904 static GList *
905 uint_list_new(gint n, guint value, ...)
906 {
907  GList *list = NULL;
908  va_list args;
909  gint i;
910 
911  va_start(args, value);
912  for (i = 0; i < n; i++) {
913  list = g_list_prepend(list, GUINT_TO_POINTER(value));
914  value = va_arg(args, guint);
915  }
916  va_end(args);
917 
918  return g_list_reverse(list);
919 }
920 
921 void
923 {
924 #define ADD_DATA(label, expected, min_size, max, offset, limit, flags) \
925  gcut_add_datum(label, \
926  "expected", G_TYPE_POINTER, \
927  expected, g_list_free, \
928  "min-size", G_TYPE_INT, min_size, \
929  "max", G_TYPE_UINT, max, \
930  "offset", G_TYPE_INT, offset, \
931  "limit", G_TYPE_INT, limit, \
932  "flags", G_TYPE_INT, flags, \
933  NULL)
934 
935  ADD_DATA("no limit",
936  uint_list_new(5,
937  0x00000000U, 0x00000004U, 0x00000080U,
938  0xdeadbeefU, 0xffffffffU),
939  0, 0,
940  0, -1,
941  0);
942  ADD_DATA("min limit",
943  uint_list_new(3, 0x00000000U, 0x00000004U, 0x00000080U),
944  1, 0,
945  0, -1,
946  0);
947 
948 #undef ADD_DATA
949 }
950 
951 void
952 test_near_uint32(gpointer data)
953 {
954  grn_id id;
955  int min_size, offset, limit, flags;
956  guint32 max;
957  const GList *expected_keys;
958  GList *actual_keys = NULL;
959 
960  create_uint32_table();
961 
962  min_size = gcut_data_get_int(data, "min-size");
963  max = gcut_data_get_uint(data, "max");
964  offset = gcut_data_get_int(data, "offset");
965  limit = gcut_data_get_int(data, "limit");
966  flags = gcut_data_get_int(data, "flags");
967  cursor = grn_table_cursor_open(context, table,
968  NULL, min_size,
969  &max, sizeof(max),
970  offset, limit,
971  flags | GRN_CURSOR_PREFIX);
972  grn_test_assert_context(context);
973  while ((id = grn_table_cursor_next(context, cursor))) {
974  guint32 *key;
975  int key_size;
976 
977  key_size = grn_table_cursor_get_key(context, cursor, (void **)&key);
978  actual_keys = g_list_append(actual_keys, GUINT_TO_POINTER(*key));
979  }
980  gcut_take_list(actual_keys, NULL);
981 
982  expected_keys = gcut_data_get_pointer(data, "expected");
983  gcut_assert_equal_list_uint(expected_keys, actual_keys);
984 }
985 
986 void
988 {
989 #define ADD_DATA(label, expected, min_size, max, offset, limit, flags) \
990  gcut_add_datum(label, \
991  "expected", G_TYPE_POINTER, \
992  expected, gcut_list_string_free, \
993  "min-size", G_TYPE_UINT, min_size, \
994  "max", G_TYPE_STRING, max, \
995  "offset", G_TYPE_INT, offset, \
996  "limit", G_TYPE_INT, limit, \
997  "flags", G_TYPE_INT, flags, \
998  NULL)
999 
1000  ADD_DATA("no limit",
1001  gcut_list_string_new(TAKEN_POINT(1, 2, 3,
1002  4, 5, 6),
1003  TAKEN_POINT(1, 2, 3,
1004  7, 8, 9),
1005  TAKEN_POINT(7, 8, 9,
1006  4, 5, 6),
1007  TAKEN_POINT(88, 58, 58,
1008  178, 58, 58),
1009  TAKEN_POINT(89, 59, 59,
1010  179, -59, -59),
1011  TAKEN_POINT(89, 59, 59,
1012  179, 59, 59),
1013  TAKEN_POINT(-89, -59, -59,
1014  179, 59, 59),
1015  TAKEN_POINT(-89, -59, -59,
1016  -179, -59, -59),
1017  TAKEN_POINT(-88, -58, -58,
1018  -178, -58, -58),
1019  NULL),
1020  0,
1021  TAKEN_POINT(0, 0, 0,
1022  0, 0, 0),
1023  0, -1,
1024  0);
1025  ADD_DATA("min-size",
1026  gcut_list_string_new(TAKEN_POINT(1, 2, 3,
1027  4, 5, 6),
1028  TAKEN_POINT(1, 2, 3,
1029  7, 8, 9),
1030  TAKEN_POINT(7, 8, 9,
1031  4, 5, 6),
1032  NULL),
1033  1,
1034  TAKEN_POINT(0, 0, 0,
1035  0, 0, 0),
1036  0, -1,
1037  0);
1038 
1039 #undef ADD_DATA
1040 }
1041 
1042 void
1043 test_near_geo_point(gpointer data)
1044 {
1045  grn_id id;
1046  int min_size, offset, limit, flags;
1047  grn_obj max;
1048  const GList *expected_keys;
1049  GList *actual_keys = NULL;
1050  GRN_WGS84_GEO_POINT_INIT(&max, 0);
1051 
1052  create_geo_point_table(
1053  cut_take_printf(" [\"%s\"],"
1054  " [\"%s\"],"
1055  " [\"%s\"],"
1056  " [\"%s\"],"
1057  " [\"%s\"],"
1058  " [\"%s\"],"
1059  " [\"%s\"],"
1060  " [\"%s\"],"
1061  " [\"%s\"]",
1062  TAKEN_POINT(1, 2, 3,
1063  4, 5, 6),
1064  TAKEN_POINT(1, 2, 3,
1065  7, 8, 9),
1066  TAKEN_POINT(7, 8, 9,
1067  4, 5, 6),
1068  TAKEN_POINT(89, 59, 59,
1069  179, 59, 59),
1070  TAKEN_POINT(89, 59, 59,
1071  179, -59, -59),
1072  TAKEN_POINT(88, 58, 58,
1073  178, 58, 58),
1074  TAKEN_POINT(-89, -59, -59,
1075  -179, -59, -59),
1076  TAKEN_POINT(-89, -59, -59,
1077  179, 59, 59),
1078  TAKEN_POINT(-88, -58, -58,
1079  -178, -58, -58)));
1080 
1081  min_size = gcut_data_get_int(data, "min-size");
1082  cast_to_geo_point(&max, gcut_data_get_string(data, "max"));
1083  offset = gcut_data_get_int(data, "offset");
1084  limit = gcut_data_get_int(data, "limit");
1085  flags = gcut_data_get_int(data, "flags");
1086  cursor = grn_table_cursor_open(context, table,
1087  NULL, min_size,
1088  GRN_BULK_HEAD(&max), GRN_BULK_VSIZE(&max),
1089  offset, limit,
1090  flags | GRN_CURSOR_PREFIX);
1091  grn_obj_unlink(context, &max);
1092  grn_test_assert_context(context);
1093  while ((id = grn_table_cursor_next(context, cursor))) {
1094  grn_geo_point *key;
1095  int key_size;
1096 
1097  key_size = grn_table_cursor_get_key(context, cursor, (void **)&key);
1098  actual_keys = g_list_append(actual_keys,
1099  g_strdup_printf("%dx%d",
1100  key->latitude,
1101  key->longitude));
1102  }
1103  gcut_take_list(actual_keys, g_free);
1104 
1105  expected_keys = gcut_data_get_pointer(data, "expected");
1106  gcut_assert_equal_list_string(expected_keys, actual_keys);
1107 }
1108 
1109 void
1111 {
1112 #define ADD_DATA(label, expected, min_size, max, offset, limit, flags) \
1113  gcut_add_datum(label, \
1114  "expected", G_TYPE_POINTER, \
1115  expected, gcut_list_string_free, \
1116  "min-size", G_TYPE_INT, min_size, \
1117  "max", G_TYPE_STRING, max, \
1118  "offset", G_TYPE_INT, offset, \
1119  "limit", G_TYPE_INT, limit, \
1120  "flags", G_TYPE_INT, flags, \
1121  NULL)
1122 
1123  ADD_DATA("alphabet",
1124  gcut_list_string_new("abracada", "abra",
1125  NULL),
1126  0, "abracada",
1127  0, -1,
1128  0);
1129  ADD_DATA("alphabet - min size",
1130  gcut_list_string_new("abracadabra", "abracada",
1131  NULL),
1132  5, "abracadabra",
1133  0, -1,
1134  0);
1135  ADD_DATA("alphabet - offset and limit",
1136  gcut_list_string_new("abra", NULL),
1137  0, "abracadabra",
1138  2, 1,
1139  0);
1140  ADD_DATA("no match",
1141  NULL,
1142  0, "bubuzera",
1143  0, -1,
1144  0);
1145  ADD_DATA("no match - common prefix",
1146  NULL,
1147  0, "aburaura",
1148  0, -1,
1149  0);
1150  ADD_DATA("empty key",
1151  gcut_list_string_new("abra", "abracada", "abracadabra", "abubu",
1152  "あ", "ああ", "あああ", "い",
1153  NULL),
1154  0, "",
1155  0, -1,
1156  0);
1157  {
1158  gchar *long_key;
1159  long_key = g_alloca(GRN_TABLE_MAX_KEY_SIZE + 2);
1160  memset(long_key, 'a', GRN_TABLE_MAX_KEY_SIZE + 1);
1161  ADD_DATA("long key",
1162  NULL,
1163  0, long_key,
1164  0, -1,
1165  0);
1166  }
1167 
1168 #undef ADD_DATA
1169 }
1170 
1171 void
1173 {
1174  grn_id id;
1175  const gchar *max;
1176  int min_size, offset, limit, flags;
1177  const GList *expected_keys;
1178  GList *actual_keys = NULL;
1179 
1180  create_short_text_table(gcut_take_new_list_string("abra",
1181  "abracada",
1182  "abracadabra",
1183  "abubu",
1184  "あ",
1185  "ああ",
1186  "あああ",
1187  "い",
1188  NULL));
1189 
1190  min_size = gcut_data_get_int(data, "min-size");
1191  max = gcut_data_get_string(data, "max");
1192  offset = gcut_data_get_int(data, "offset");
1193  limit = gcut_data_get_int(data, "limit");
1194  flags = gcut_data_get_int(data, "flags");
1195  cursor = grn_table_cursor_open(context, table,
1196  NULL, min_size,
1197  max, strlen(max),
1198  offset, limit,
1199  flags | GRN_CURSOR_PREFIX);
1200  grn_test_assert_context(context);
1201  while ((id = grn_table_cursor_next(context, cursor))) {
1202  gchar *key;
1203  int key_size;
1204 
1205  key_size = grn_table_cursor_get_key(context, cursor, (void **)&key);
1206  actual_keys = g_list_append(actual_keys, g_strndup(key, key_size));
1207  }
1208  gcut_take_list(actual_keys, g_free);
1209 
1210  expected_keys = gcut_data_get_pointer(data, "expected");
1211  gcut_assert_equal_list_string(expected_keys, actual_keys);
1212 }
1213 
1214 void
1216 {
1217 #define ADD_DATA(label, expected, min, min_size, max, max_size, \
1218  offset, limit, flags) \
1219  gcut_add_datum(label, \
1220  "expected", G_TYPE_POINTER, \
1221  expected, gcut_list_string_free, \
1222  "min", G_TYPE_STRING, min, \
1223  "min-size", G_TYPE_UINT, min_size, \
1224  "max", G_TYPE_STRING, max, \
1225  "max-size", G_TYPE_UINT, max_size, \
1226  "offset", G_TYPE_INT, offset, \
1227  "limit", G_TYPE_INT, limit, \
1228  "flags", G_TYPE_INT, flags, \
1229  NULL)
1230 
1231  ADD_DATA("ascending",
1232  gcut_list_string_new("128592911x503145263",
1233  "128597458x502942345",
1234  "128572751x502866155",
1235  "128513714x503319780",
1236  "128320340x502334363",
1237  NULL),
1238  NULL, 0,
1239  NULL, 0,
1240  0, -1,
1241  0);
1242  ADD_DATA("descending",
1243  gcut_list_string_new("128320340x502334363",
1244  "128513714x503319780",
1245  "128572751x502866155",
1246  "128597458x502942345",
1247  "128592911x503145263",
1248  NULL),
1249  NULL, 0,
1250  NULL, 0,
1251  0, -1,
1253  ADD_DATA("ascending - offset",
1254  gcut_list_string_new("128572751x502866155",
1255  "128513714x503319780",
1256  "128320340x502334363",
1257  NULL),
1258  NULL, 0,
1259  NULL, 0,
1260  2, -1,
1261  0);
1262  ADD_DATA("descending - offset",
1263  gcut_list_string_new("128572751x502866155",
1264  "128597458x502942345",
1265  "128592911x503145263",
1266  NULL),
1267  NULL, 0,
1268  NULL, 0,
1269  2, -1,
1271 
1272 #undef ADD_DATA
1273 }
1274 
1275 void
1276 test_by_id_encoded(gpointer data)
1277 {
1278  grn_id id;
1279  grn_obj min, max;
1280  unsigned min_size, max_size;
1281  int offset, limit, flags;
1282  const GList *expected_keys;
1283  GList *actual_keys = NULL;
1284  GRN_WGS84_GEO_POINT_INIT(&min, 0);
1285  GRN_WGS84_GEO_POINT_INIT(&max, 0);
1286 
1287  create_geo_point_table("[\"128592911x503145263\"],\n"
1288  "[\"128565076x502976128\"],\n"
1289  "[\"128597458x502942345\"],\n"
1290  "[\"128572751x502866155\"],\n"
1291  "[\"128521858x503341754\"],\n"
1292  "[\"128513714x503319780\"],\n"
1293  "[\"128534177x502693614\"],\n"
1294  "[\"128320340x502334363\"]\n");
1295  assert_send_command("delete GeoPointPat \"128565076x502976128\"");
1296  assert_send_command("delete GeoPointPat \"128521858x503341754\"");
1297  assert_send_command("delete GeoPointPat \"128534177x502693614\"");
1298 
1299  cast_to_geo_point(&min, gcut_data_get_string(data, "min"));
1300  min_size = gcut_data_get_uint(data, "min-size");
1301  cast_to_geo_point(&max, gcut_data_get_string(data, "max"));
1302  max_size = gcut_data_get_uint(data, "max-size");
1303  offset = gcut_data_get_int(data, "offset");
1304  limit = gcut_data_get_int(data, "limit");
1305  flags = gcut_data_get_int(data, "flags");
1306  cursor = grn_table_cursor_open(context, table,
1307  min_size > 0 ? GRN_BULK_HEAD(&min) : NULL,
1308  min_size,
1309  max_size > 0 ? GRN_BULK_HEAD(&max) : NULL,
1310  max_size,
1311  offset, limit,
1312  flags | GRN_CURSOR_BY_ID);
1313  grn_obj_unlink(context, &min);
1314  grn_obj_unlink(context, &max);
1315  grn_test_assert_context(context);
1316  while ((id = grn_table_cursor_next(context, cursor))) {
1317  grn_geo_point *key;
1318  int key_size;
1319 
1320  key_size = grn_table_cursor_get_key(context, cursor, (void **)&key);
1321  actual_keys = g_list_append(actual_keys,
1322  g_strdup_printf("%dx%d",
1323  key->latitude,
1324  key->longitude));
1325  }
1326  gcut_take_list(actual_keys, g_free);
1327 
1328  expected_keys = gcut_data_get_pointer(data, "expected");
1329  gcut_assert_equal_list_string(expected_keys, actual_keys);
1330 }