Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
test-patricia-trie.c
Go to the documentation of this file.
1 /* -*- c-basic-offset: 2; coding: utf-8 -*- */
2 /*
3  Copyright (C) 2008-2012 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 "test-patricia-trie.h"
20 
21 void data_create(void);
22 void test_create(gconstpointer data);
23 void data_open_success(void);
24 void test_open_success(gconstpointer data);
25 void data_open_without_path(void);
26 void test_open_without_path(gconstpointer data);
27 void test_remove(void);
29 void data_lookup_add(void);
30 void test_lookup_add(gconstpointer data);
31 void data_delete_by_id(void);
32 void test_delete_by_id(gconstpointer data);
36 void data_delete(void);
37 void test_delete(gconstpointer data);
39 void test_lookup_and_delete_for_same_prefix_key(gconstpointer data);
40 void test_get_key(void);
41 void data_get_value(void);
42 void test_get_value(gconstpointer data);
43 void test_set_value(void);
45 void data_add_and_delete(void);
46 void test_add_and_delete(gconstpointer data);
47 void data_at(void);
48 void test_at(gconstpointer data);
49 
50 static GArray *ids;
51 static GList *expected_keys, *actual_keys;
52 static grn_obj *database;
53 
54 void
55 cut_setup(void)
56 {
57  setup_trie_common("patricia-trie");
58 
59  ids = NULL;
60  expected_keys = NULL;
61  actual_keys = NULL;
62  database = NULL;
63 }
64 
65 static void
66 ids_free(void)
67 {
68  if (ids)
69  g_array_free(ids, TRUE);
70  ids = NULL;
71 }
72 
73 void
75 {
76  ids_free();
77  if (expected_keys)
78  gcut_list_string_free(expected_keys);
79  if (actual_keys)
80  gcut_list_string_free(actual_keys);
81  if (database)
82  grn_obj_close(context, database);
83  teardown_trie_common();
84 }
85 
86 
87 static void
88 set_key_size_to_zero(void)
89 {
90  default_key_size = 0;
91 }
92 
93 static void
94 set_value_size_to_zero(void)
95 {
96  default_value_size = 0;
97 }
98 
99 static void
100 set_sis_and_utf8_encoding(void)
101 {
102  set_sis();
103  default_encoding = GRN_ENC_UTF8;
104 }
105 
106 void
107 data_create(void)
108 {
109  cut_add_data("default", NULL, NULL,
110  "zero key size", set_key_size_to_zero, NULL,
111  "zero value size", set_value_size_to_zero, NULL);
112 }
113 
114 void
115 test_create(gconstpointer data)
116 {
117  const grn_test_set_parameters_func set_parameters = data;
118 
119  if (set_parameters)
120  set_parameters();
121 
123 }
124 
125 void
127 {
128  cut_add_data("default", NULL, NULL,
129  "sis", set_sis, NULL);
130 }
131 
132 void
133 test_open_success(gconstpointer data)
134 {
135  const grn_test_set_parameters_func set_parameters = data;
136 
137  if (set_parameters)
138  set_parameters();
139 
142 }
143 
144 void
146 {
147  cut_add_data("default", NULL, NULL,
148  "sis", set_sis, NULL);
149 }
150 
151 void
152 test_open_without_path(gconstpointer data)
153 {
154  const grn_test_set_parameters_func set_parameters = data;
155  const gchar *saved_default_path;
156 
157  if (set_parameters)
158  set_parameters();
159 
160  saved_default_path = cut_take_string(default_path);
161  default_path = NULL;
162 
163  cut_assert_path_not_exist(saved_default_path);
165  cut_assert_path_not_exist(saved_default_path);
167  cut_assert_path_not_exist(saved_default_path);
168 }
169 
170 void
172 {
173  cut_assert_path_not_exist(default_path);
175  cut_assert_path_exist(default_path);
176  grn_test_assert(grn_pat_remove(context, default_path));
177  cut_assert_path_not_exist(default_path);
178 }
179 
180 void
182 {
183  gchar expected_error_message[] = "path is null";
184 
186  gcut_assert_equal_list_string(NULL, messages());
188  grn_pat_remove(context, NULL));
189  cut_assert_equal_substring(expected_error_message,
190  messages()->data,
191  strlen(expected_error_message));
192 }
193 
194 static grn_trie_test_data *
195 test_data_new(const gchar *key, grn_test_set_parameters_func set_parameters)
196 {
197  return trie_test_data_newv(key, NULL, NULL, GRN_SUCCESS, NULL, NULL,
198  set_parameters, NULL);
199 }
200 
201 static void
202 test_data_free(grn_trie_test_data *data)
203 {
204  trie_test_data_free(data);
205 }
206 
207 void
208 data_lookup_add(void)
209 {
210  cut_add_data("default",
211  test_data_new("Cutter", NULL),
212  test_data_free,
213  "sis",
214  test_data_new("Groonga", set_sis),
215  test_data_free,
216  "sis - multi byte key",
217  test_data_new("セナ", set_sis_and_utf8_encoding),
218  test_data_free);
219 }
220 
221 void
222 test_lookup_add(gconstpointer data)
223 {
224  const grn_trie_test_data *test_data = data;
225 
226  trie_test_data_set_parameters(test_data);
227 
229  cut_assert_lookup_add(test_data->key);
230 }
231 
232 void
233 data_delete_by_id(void)
234 {
235  cut_add_data("default",
236  test_data_new("Cutter", NULL),
237  test_data_free,
238  "sis",
239  test_data_new("Groonga", set_sis),
240  test_data_free,
241  "sis - multi byte key",
242  test_data_new("セナ", set_sis_and_utf8_encoding),
243  test_data_free);
244 }
245 
246 void
247 test_delete_by_id(gconstpointer data)
248 {
249  const grn_trie_test_data *test_data = data;
250  grn_search_flags flags;
251  uint32_t key_size;
252 
253  trie_test_data_set_parameters(test_data);
254 
256 
258  grn_pat_delete_by_id(context, trie, 0, NULL));
259 
260  cut_assert_lookup_add(test_data->key);
261 
262  flags = 0;
263  key_size = strlen(test_data->key);
264  cut_assert_lookup(test_data->key, key_size, &flags);
265 
267  grn_pat_delete_by_id(context, NULL, id, NULL));
268  grn_test_assert(grn_pat_delete_by_id(context, trie, id, NULL));
269  flags = 0;
270  cut_assert_lookup_failed(test_data->key, key_size, &flags);
271 
273  grn_pat_delete_by_id(context, trie, id, NULL));
274 }
275 
276 void
278 {
279  grn_id short_term_id, long_term_id;
280 
281  set_sis_and_utf8_encoding();
282 
284 
285  cut_assert_lookup_add("セナ");
286  short_term_id = id;
287  cut_assert_lookup_add("セナセナ");
288  long_term_id = id;
289 
290  expected_keys = gcut_list_string_new("セナ", "セナセナ", "ナ", "ナセナ", NULL);
291  actual_keys = grn_test_pat_get_keys(context, (grn_obj *)trie);
292  gcut_assert_equal_list_string(expected_keys, actual_keys);
293 
295  grn_pat_delete_by_id(context, trie, short_term_id, NULL));
296 
297  gcut_list_string_free(actual_keys);
298  actual_keys = grn_test_pat_get_keys(context, (grn_obj *)trie);
299  gcut_assert_equal_list_string(expected_keys, actual_keys);
300 }
301 
302 void
304 {
305  cut_set_attributes("ML", "1010",
306  NULL);
307 }
308 
309 void
311 {
312  grn_id short_term_id, long_term_id;
313 
314  set_sis_and_utf8_encoding();
315 
317 
318  cut_assert_lookup_add("セナ");
319  short_term_id = id;
320  cut_assert_lookup_add("セナセナ");
321  long_term_id = id;
322 
323  expected_keys = gcut_list_string_new("セナ", "セナセナ", "ナ", "ナセナ", NULL);
324  actual_keys = grn_test_pat_get_keys(context, (grn_obj *)trie);
325  gcut_assert_equal_list_string(expected_keys, actual_keys);
326 
327  grn_test_assert(grn_pat_delete_by_id(context, trie, long_term_id, NULL));
328 
329  gcut_list_string_free(actual_keys);
330  actual_keys = grn_test_pat_get_keys(context, (grn_obj *)trie);
331  gcut_assert_equal_list_string(NULL, actual_keys);
332 }
333 
334 #define cut_assert_delete(key) do \
335 { \
336  const gchar *_key; \
337  uint32_t key_size = 0; \
338  grn_search_flags flags; \
339  \
340  _key = (key); \
341  if (_key) \
342  key_size = strlen(_key); \
343  \
344  grn_test_assert(grn_pat_delete(context, trie, _key, key_size, NULL)); \
345  grn_test_assert_equal_rc(GRN_INVALID_ARGUMENT, \
346  grn_pat_delete(context, trie, \
347  _key, key_size, NULL)); \
348  \
349  flags = 0; \
350  cut_assert_lookup_failed(_key, key_size, &flags); \
351 } while (0)
352 
353 void
354 data_delete(void)
355 {
356  cut_add_data("default",
357  test_data_new("29", NULL),
358  test_data_free,
359  "sis",
360  test_data_new("29", set_sis),
361  test_data_free,
362  "sis - multi byte key",
363  test_data_new("肉ニク", set_sis_and_utf8_encoding),
364  test_data_free);
365 }
366 
367 void
368 test_delete(gconstpointer data)
369 {
370  const grn_trie_test_data *test_data = data;
371 
372  trie_test_data_set_parameters(test_data);
373 
375  cut_assert_lookup_add(test_data->key);
376  cut_assert_delete(test_data->key);
377 }
378 
379 void
381 {
382  cut_add_data("default", NULL, NULL,
383  "sis", set_sis, NULL);
384 }
385 
386 void
388 {
389  const grn_test_set_parameters_func set_parameters = data;
390  grn_search_flags flags;
391  const gchar key1[] = "セナ + PostgreSQL";
392  const gchar key2[] = "セナ + MySQL";
393  const gchar key3[] = "セナ + Ruby";
394 
395  if (set_parameters)
396  set_parameters();
397 
398  default_encoding = GRN_ENC_UTF8;
399 
401 
402  cut_assert_lookup_add(key1);
403  cut_assert_lookup_add(key2);
404  cut_assert_lookup_add(key3);
405  cut_assert_delete(key3);
406 
407  flags = 0;
408  cut_assert_lookup(key1, strlen(key1), &flags);
409 
410  flags = 0;
411  cut_assert_lookup(key2, strlen(key2), &flags);
412 
413  flags = 0;
414  cut_assert_lookup_failed(key3, strlen(key3), &flags);
415 }
416 
417 void
419 {
420  const gchar key[] = "Groonga";
421  const gchar initial_key[] = "Ludia";
422  gchar got_key[GRN_PAT_MAX_KEY_SIZE];
423  grn_id nonexistence_id = 12345;
424  int got_key_size;
425  grn_search_flags flags;
426 
428 
429  strcpy(got_key, initial_key);
430  cut_assert_equal_int(0, grn_pat_get_key(context, trie, nonexistence_id,
431  &got_key, GRN_PAT_MAX_KEY_SIZE));
432  cut_assert_equal_string(initial_key, got_key);
433 
434  flags = GRN_TABLE_ADD;
435  cut_assert_lookup(key, strlen(key), &flags);
436 
437  strcpy(got_key, initial_key);
438  got_key_size = grn_pat_get_key(context, trie, nonexistence_id,
439  &got_key, GRN_PAT_MAX_KEY_SIZE);
440  /* don't need to show the below. */
441  /*
442  cut_notify("grn_pat_get_key() with nonexistence ID is undefined:\n"
443  " got_key_size: %d (may != 0)\n"
444  " got_key: <%s> (may != initial_key)\n"
445  " initial_key: <%s>",
446  got_key_size,
447  got_key,
448  initial_key);
449  */
450 
451  got_key_size = grn_pat_get_key(context, trie, id,
452  &got_key, GRN_PAT_MAX_KEY_SIZE);
453  cut_assert_equal_int(strlen(key), got_key_size);
454  got_key[got_key_size] = '\0';
455  cut_assert_equal_string(key, got_key);
456 }
457 
458 void
459 data_get_value(void)
460 {
461  cut_add_data("default",
462  test_data_new("Cutter", NULL),
463  test_data_free,
464  "sis",
465  test_data_new("Groonga", set_sis),
466  test_data_free,
467  "sis - multi byte",
468  test_data_new("セナ", set_sis_and_utf8_encoding),
469  test_data_free);
470 }
471 
472 void
473 test_get_value(gconstpointer data)
474 {
475  const grn_trie_test_data *test_data = data;
476  const gchar *set_value;
477  const gchar *initial_value;
478  gchar got_value[DEFAULT_VALUE_SIZE];
479  grn_id nonexistence_id = 12345;
480  int got_value_size;
481 
482  trie_test_data_set_parameters(test_data);
483 
485 
486  initial_value = cut_take_string(g_strjoin(" - ",
487  test_data->key,
488  test_data->key,
489  NULL));
490  strcpy(got_value, initial_value);
491  cut_assert_equal_int(0, grn_pat_get_value(context, trie,
492  nonexistence_id, got_value));
493  cut_assert_equal_string(initial_value, got_value);
494 
495  cut_assert_lookup_add(test_data->key);
496  set_value = cut_take_string(g_strjoin(" - ",
497  test_data->key,
498  test_data->key,
499  test_data->key,
500  NULL));
501  strcpy(value, set_value);
502 
503  strcpy(got_value, initial_value);
504  got_value_size = grn_pat_get_value(context, trie,
505  nonexistence_id, got_value);
506  /* don't need to show the below. */
507  /*
508  cut_notify("grn_pat_get_value() with nonexistence ID is undefined:\n"
509  " got_value_size: %d (may != 0)\n"
510  " got_value: <%s> (may != initial_value)\n"
511  " initial_value: <%s>",
512  got_value_size,
513  got_value,
514  initial_value);
515  */
516 
517  cut_assert_equal_int(DEFAULT_VALUE_SIZE,
518  grn_pat_get_value(context, trie, id, got_value));
519  cut_assert_equal_string(set_value, got_value);
520 }
521 
522 void
523 test_set_value(void)
524 {
525  gchar got_value[DEFAULT_VALUE_SIZE];
526 
528 
530 
532  sample_id, "XXX", GRN_OBJ_SET));
533  cut_assert_equal_int(DEFAULT_VALUE_SIZE,
534  grn_pat_get_value(context, trie, sample_id, got_value));
535  cut_assert_equal_string("XXX", got_value);
536 }
537 
538 void
540 {
542 
545  999, NULL, GRN_OBJ_SET));
546 
550  sample_id, NULL, GRN_OBJ_SET));
551 }
552 
553 static grn_trie_test_data *
554 increment_test_data_new(const gchar *key, increment_key_func increment,
555  grn_test_set_parameters_func set_parameters)
556 {
557  return trie_test_data_newv(key, NULL, NULL, GRN_SUCCESS, NULL, increment,
558  set_parameters, NULL);
559 }
560 
561 static void
562 increment_test_data_free(grn_trie_test_data *data)
563 {
564  trie_test_data_free(data);
565 }
566 
567 static void
568 string_increment(grn_trie_test_data *data)
569 {
570  gchar *original_string = data->key;
571  gchar *string;
572  gint last;
573 
574  last = strlen(original_string);
575  if (original_string[last - 1] < 'X') {
576  original_string[last - 1]++;
577  } else {
578  string = g_strconcat(data->key, "A", NULL);
579  g_free(data->key);
580  data->key = string;
581  }
582 }
583 
584 static void
585 utf8_string_increment(grn_trie_test_data *data)
586 {
587  gchar *original_string = data->key;
588  gchar *character;
589 
590  for (character = original_string;
591  *character;
592  character = g_utf8_next_char(character)) {
593  gunichar unicode;
594 
595  if (g_random_int_range(0, 100) < 99)
596  continue;
597 
598  unicode = g_utf8_get_char(character);
599  if (unicode < g_utf8_get_char("ン")) {
600  gchar buffer[6];
601  gint i, length;
602 
603  length = g_unichar_to_utf8(unicode + 1, buffer);
604  for (i = 0; i < length; i++) {
605  character[i] = buffer[i];
606  }
607  return;
608  }
609  }
610 
611  {
612  gchar *string;
613  gunichar new_unicode;
614  gchar new_character[6];
615  gint length;
616 
617  new_unicode = g_random_int_range(g_utf8_get_char("ア"),
618  g_utf8_get_char("ン"));
619  length = g_unichar_to_utf8(new_unicode, new_character);
620  new_character[length] = '\0';
621  string = g_strconcat(data->key, new_character, NULL);
622  g_free(data->key);
623  data->key = string;
624  }
625 }
626 
627 static void
628 utf8_string_same_prefix_increment(grn_trie_test_data *data)
629 {
630  gchar *original_string = data->key;
631  gchar *character;
632 
633  for (character = original_string;
634  *character;
635  character = g_utf8_next_char(character)) {
636  gunichar unicode;
637 
638  unicode = g_utf8_get_char(character);
639  if (unicode < g_utf8_get_char("ン")) {
640  gchar buffer[6];
641  gint i, length;
642 
643  length = g_unichar_to_utf8(unicode + 1, buffer);
644  for (i = 0; i < length; i++) {
645  character[i] = buffer[i];
646  }
647  return;
648  }
649  }
650 
651  {
652  gchar *string;
653  string = g_strconcat(data->key, "ア", NULL);
654  g_free(data->key);
655  data->key = string;
656  }
657 }
658 
659 static void
660 increment_test_data_add_n_data(guint n, grn_trie_test_data *test_data)
661 {
662  guint i;
663 
664  ids_free();
665  ids = g_array_new(TRUE, TRUE, sizeof(grn_id));
666  for (i = 0; i < n; i++) {
667  cut_assert_lookup_add(test_data->key);
668  test_data->increment(test_data);
669  g_array_append_val(ids, id);
670  }
671 }
672 
673 static gboolean
674 is_sis_utf8_increment_test_data(grn_trie_test_data *test_data)
675 {
676  return test_data->increment == utf8_string_increment ||
677  test_data->increment == utf8_string_same_prefix_increment;
678 }
679 
680 static void
681 add_increment_test_data(void)
682 {
683  cut_add_data("default",
684  increment_test_data_new("Cutter", string_increment, NULL),
685  increment_test_data_free,
686  "sis",
687  increment_test_data_new("Groonga", string_increment, set_sis),
688  increment_test_data_free,
689  "sis - multi byte key (katakana)",
690  increment_test_data_new("セナ", utf8_string_increment,
691  set_sis_and_utf8_encoding),
692  increment_test_data_free,
693  "sis - multi byte key (katakana) - many same prefix",
694  increment_test_data_new("セナ", utf8_string_same_prefix_increment,
695  set_sis_and_utf8_encoding),
696  increment_test_data_free);
697 }
698 
699 void
701 {
702  add_increment_test_data();
703 }
704 
705 void
706 test_add_and_delete(gconstpointer data)
707 {
708  grn_trie_test_data *test_data;
709  guint i;
710  const guint n_operations = 750;
711  gboolean sis_utf8_data = FALSE;
712 
713  test_data = (grn_trie_test_data *)data;
714  if (is_sis_utf8_increment_test_data(test_data))
715  sis_utf8_data = TRUE;
716 
717  trie_test_data_set_parameters(test_data);
718 
720 
721  increment_test_data_add_n_data(n_operations, test_data);
722 
723  if (sis_utf8_data)
724  cut_assert_operator_int(n_operations, <, grn_pat_size(context, trie));
725  else
726  cut_assert_equal_int(n_operations, grn_pat_size(context, trie));
727 
728  for (i = 0; i < ids->len; i++) {
729  grn_id delete_id;
730 
731  delete_id = g_array_index(ids, grn_id, i);
732  if (sis_utf8_data) {
733  grn_pat_delete_by_id(context, trie, delete_id, NULL);
734  } else {
735  grn_test_assert(grn_pat_delete_by_id(context, trie, delete_id, NULL),
736  cut_message("i = %d; id = %d", i, delete_id));
737  }
738  }
739 
740  actual_keys = grn_test_pat_get_keys(context, (grn_obj *)trie);
741  gcut_assert_equal_list_string(NULL, actual_keys);
742 }
743 
744 #define cut_assert_truncate(key) do \
745 { \
746  const gchar *_key; \
747  uint32_t key_size = 0; \
748  grn_search_flags flags; \
749  \
750  _key = (key); \
751  if (_key) \
752  key_size = strlen(_key); \
753  \
754  grn_test_assert(grn_pat_truncate(context, trie, _key, key_size, NULL));\
755  grn_test_assert_equal_rc(GRN_INVALID_ARGUMENT, \
756  grn_pat_delete(context, trie, \
757  _key, key_size, NULL)); \
758  \
759  flags = 0; \
760  cut_assert_lookup_failed(_key, key_size, &flags); \
761 } while (0)
762 
763 void
765 {
766  add_increment_test_data();
767 }
768 
769 void
770 test_truncate(gconstpointer data)
771 {
772  grn_trie_test_data *test_data;
773  gboolean sis_utf8_data = FALSE;
774  guint n_data = 100;
775 
776  test_data = (grn_trie_test_data *)data;
777  if (is_sis_utf8_increment_test_data(test_data))
778  sis_utf8_data = TRUE;
779 
780  trie_test_data_set_parameters(test_data);
782  cut_assert_equal_uint(0, grn_pat_size(context, trie));
783 
784  increment_test_data_add_n_data(n_data, test_data);
785  if (sis_utf8_data) {
786  cut_assert_operator_uint(n_data, <, grn_pat_size(context, trie));
787  } else {
788  cut_assert_equal_uint(n_data, grn_pat_size(context, trie));
789  }
790 
792  cut_assert_equal_uint(0, grn_pat_size(context, trie));
793 }
794 
795 void
796 data_at(void)
797 {
798 #define ADD_DATUM(label, commands) \
799  gcut_add_datum(label, \
800  "commands", G_TYPE_STRING, commands, \
801  NULL)
802 
803  ADD_DATUM("Int32",
804  "table_create Pat TABLE_PAT_KEY Int32\n"
805  "load --table Pat\n"
806  "[{\"_key\": -29}]");
807  ADD_DATUM("UInt32",
808  "table_create Pat TABLE_PAT_KEY UInt32\n"
809  "load --table Pat\n"
810  "[{\"_key\": 29}]");
811  ADD_DATUM("GeoPoint",
812  "table_create Pat TABLE_PAT_KEY TokyoGeoPoint\n"
813  "load --table Pat\n"
814  "[{\"_key\": \"128467228x503222332\"}]");
815  ADD_DATUM("ShortText",
816  "table_create Pat TABLE_PAT_KEY ShortText\n"
817  "load --table Pat\n"
818  "[{\"_key\": \"niku\"}]");
819 
820 #undef ADD_DATUM
821 }
822 
823 void
824 test_at(gconstpointer data)
825 {
826  grn_obj *pat;
827 
829 
830  database = grn_db_create(context,
831  cut_build_path(grn_test_get_tmp_dir(),
832  "patricia-trie.db",
833  NULL),
834  NULL);
836 
837  assert_send_commands(gcut_data_get_string(data, "commands"));
838  pat = grn_ctx_get(context, "Pat", strlen("Pat"));
840  1,
841  grn_pat_at(context, (grn_pat *)pat, 1));
843  0,
844  grn_pat_at(context, (grn_pat *)pat, 2));
845 }