Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
grn-test-utils.c
Go to the documentation of this file.
1 /* -*- c-basic-offset: 2; coding: utf-8 -*- */
2 /*
3  Copyright (C) 2008-2010 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 <str.h>
20 #include <db.h>
21 
22 #include "grn-assertions.h"
23 
24 const gchar *
26 {
27  switch (rc) {
28  case GRN_SUCCESS:
29  return "GRN_SUCCESS";
30  case GRN_END_OF_DATA:
31  return "GRN_END_OF_DATA";
32  case GRN_UNKNOWN_ERROR:
33  return "GRN_UNKNOWN_ERROR";
35  return "GRN_OPERATION_NOT_PERMITTED";
37  return "GRN_NO_SUCH_FILE_OR_DIRECTORY";
39  return "GRN_NO_SUCH_PROCESS";
41  return "GRN_INTERRUPTED_FUNCTION_CALL";
43  return "GRN_INPUT_OUTPUT_ERROR";
45  return "GRN_NO_SUCH_DEVICE_OR_ADDRESS";
47  return "GRN_ARG_LIST_TOO_LONG";
49  return "GRN_EXEC_FORMAT_ERROR";
51  return "GRN_BAD_FILE_DESCRIPTOR";
53  return "GRN_NO_CHILD_PROCESSES";
55  return "GRN_RESOURCE_TEMPORARILY_UNAVAILABLE";
57  return "GRN_NOT_ENOUGH_SPACE";
59  return "GRN_PERMISSION_DENIED";
60  case GRN_BAD_ADDRESS:
61  return "GRN_BAD_ADDRESS";
62  case GRN_RESOURCE_BUSY:
63  return "GRN_RESOURCE_BUSY";
64  case GRN_FILE_EXISTS:
65  return "GRN_FILE_EXISTS";
66  case GRN_IMPROPER_LINK:
67  return "GRN_IMPROPER_LINK";
68  case GRN_NO_SUCH_DEVICE:
69  return "GRN_NO_SUCH_DEVICE";
71  return "GRN_NOT_A_DIRECTORY";
72  case GRN_IS_A_DIRECTORY:
73  return "GRN_IS_A_DIRECTORY";
75  return "GRN_INVALID_ARGUMENT";
77  return "GRN_TOO_MANY_OPEN_FILES_IN_SYSTEM";
79  return "GRN_TOO_MANY_OPEN_FILES";
81  return "GRN_INAPPROPRIATE_I_O_CONTROL_OPERATION";
82  case GRN_FILE_TOO_LARGE:
83  return "GRN_FILE_TOO_LARGE";
85  return "GRN_NO_SPACE_LEFT_ON_DEVICE";
86  case GRN_INVALID_SEEK:
87  return "GRN_INVALID_SEEK";
89  return "GRN_READ_ONLY_FILE_SYSTEM";
90  case GRN_TOO_MANY_LINKS:
91  return "GRN_TOO_MANY_LINKS";
92  case GRN_BROKEN_PIPE:
93  return "GRN_BROKEN_PIPE";
94  case GRN_DOMAIN_ERROR:
95  return "GRN_DOMAIN_ERROR";
97  return "GRN_RESULT_TOO_LARGE";
99  return "GRN_RESOURCE_DEADLOCK_AVOIDED";
101  return "GRN_NO_MEMORY_AVAILABLE";
103  return "GRN_FILENAME_TOO_LONG";
105  return "GRN_NO_LOCKS_AVAILABLE";
107  return "GRN_FUNCTION_NOT_IMPLEMENTED";
109  return "GRN_DIRECTORY_NOT_EMPTY";
111  return "GRN_ILLEGAL_BYTE_SEQUENCE";
113  return "GRN_SOCKET_NOT_INITIALIZED";
115  return "GRN_OPERATION_WOULD_BLOCK";
117  return "GRN_ADDRESS_IS_NOT_AVAILABLE";
118  case GRN_NETWORK_IS_DOWN:
119  return "GRN_NETWORK_IS_DOWN";
120  case GRN_NO_BUFFER:
121  return "GRN_NO_BUFFER";
123  return "GRN_SOCKET_IS_ALREADY_CONNECTED";
125  return "GRN_SOCKET_IS_NOT_CONNECTED";
127  return "GRN_SOCKET_IS_ALREADY_SHUTDOWNED";
129  return "GRN_OPERATION_TIMEOUT";
131  return "GRN_CONNECTION_REFUSED";
132  case GRN_RANGE_ERROR:
133  return "GRN_RANGE_ERROR";
134  case GRN_TOKENIZER_ERROR:
135  return "GRN_TOKENIZER_ERROR";
136  case GRN_FILE_CORRUPT:
137  return "GRN_FILE_CORRUPT";
138  case GRN_INVALID_FORMAT:
139  return "GRN_INVALID_FORMAT";
140  case GRN_OBJECT_CORRUPT:
141  return "GRN_OBJECT_CORRUPT";
143  return "GRN_TOO_MANY_SYMBOLIC_LINKS";
144  case GRN_NOT_SOCKET:
145  return "GRN_NOT_SOCKET";
147  return "GRN_OPERATION_NOT_SUPPORTED";
149  return "GRN_ADDRESS_IS_IN_USE";
150  case GRN_ZLIB_ERROR:
151  return "GRN_ZLIB_ERROR";
152  case GRN_LZO_ERROR:
153  return "GRN_LZO_ERROR";
154  case GRN_STACK_OVER_FLOW:
155  return "GRN_STACK_OVER_FLOW";
156  case GRN_SYNTAX_ERROR:
157  return "GRN_SYNTAX_ERROR";
158  case GRN_RETRY_MAX:
159  return "GRN_RETRY_MAX";
161  return "GRN_INCOMPATIBLE_FILE_FORMAT";
163  return "GRN_UPDATE_NOT_ALLOWED";
165  return "GRN_TOO_SMALL_OFFSET";
167  return "GRN_TOO_LARGE_OFFSET";
168  case GRN_TOO_SMALL_LIMIT:
169  return "GRN_TOO_SMALL_LIMIT";
170  case GRN_CAS_ERROR:
171  return "GRN_CAS_ERROR";
173  return "GRN_UNSUPPORTED_COMMAND_VERSION";
174  default:
175  return cut_take_printf("GRN_UNKNOWN_STATUS (%d)", rc);
176  }
177 }
178 
179 static gchar *base_dir = NULL;
180 const gchar *
182 {
183  const gchar *dir;
184 
185  if (base_dir)
186  return base_dir;
187 
188  dir = g_getenv("BASE_DIR");
189  if (!dir)
190  dir = ".";
191 
192  if (g_path_is_absolute(dir)) {
193  base_dir = g_strdup(dir);
194  } else {
195  gchar *current_dir;
196 
197  current_dir = g_get_current_dir();
198  base_dir = g_build_filename(current_dir, dir, NULL);
199  g_free(current_dir);
200  }
201 
202  return base_dir;
203 }
204 
205 static gchar *build_dir = NULL;
206 const gchar *
208 {
209  const gchar *dir;
210 
211  if (build_dir)
212  return build_dir;
213 
214  dir = g_getenv("BUILD_DIR");
215  if (!dir) {
216  return grn_test_get_base_dir();
217  }
218 
219  if (g_path_is_absolute(dir)) {
220  build_dir = g_strdup(dir);
221  } else {
222  gchar *current_dir;
223 
224  current_dir = g_get_current_dir();
225  build_dir = g_build_filename(current_dir, dir, NULL);
226  g_free(current_dir);
227  }
228 
229  return build_dir;
230 }
231 
232 static gchar *tmp_dir = NULL;
233 const gchar *
235 {
236  if (!tmp_dir) {
237  tmp_dir = g_build_filename(grn_test_get_build_dir(), "tmp", NULL);
238  }
239 
240  return tmp_dir;
241 }
242 
243 typedef struct _grn_log
244 {
245  gint level;
246  gchar *time;
247  gchar *title;
248  gchar *message;
249  gchar *location;
250 } grn_log;
251 
252 static grn_log *
253 grn_log_new(gint level, const gchar *time, const gchar *title,
254  const gchar *message, const gchar *location)
255 {
256  grn_log *log;
257 
258  log = g_new0(grn_log, 1);
259  log->level = level;
260  log->time = g_strdup(time);
261  log->title = g_strdup(title);
262  log->message = g_strdup(message);
263  log->location = g_strdup(location);
264 
265  return log;
266 }
267 
268 static void
269 grn_log_free(grn_log *log)
270 {
271  if (!log) {
272  return;
273  }
274 
275  g_free(log->time);
276  g_free(log->title);
277  g_free(log->message);
278  g_free(log->location);
279 
280  g_free(log);
281 }
282 
283 typedef struct _grn_logger_context
284 {
286  GList *logs;
287  GList *messages;
290 
291 static grn_logger_context *
292 grn_logger_context_new(grn_logger_info *logger)
293 {
295 
296  context = g_new0(grn_logger_context, 1);
297  context->logger = logger;
298  context->logs = NULL;
299  context->messages = NULL;
300  context->collected_message = NULL;
301 
302  return context;
303 }
304 
305 static void
306 grn_logger_context_clear_messages(grn_logger_context *context)
307 {
308  g_list_foreach(context->messages, (GFunc)g_free, NULL);
309  g_list_free(context->messages);
310  context->messages = NULL;
311  if (context->collected_message) {
312  g_string_free(context->collected_message, TRUE);
313  context->collected_message = NULL;
314  }
315 }
316 
317 static void
318 grn_logger_context_free(grn_logger_context *context)
319 {
320  if (!context) {
321  return;
322  }
323 
324  g_list_foreach(context->logs, (GFunc)grn_log_free, NULL);
325  g_list_free(context->logs);
326 
327  grn_logger_context_clear_messages(context);
328 
329  g_free(context);
330 }
331 
332 static void
333 grn_collect_logger_log_func(int level, const char *time, const char *title,
334  const char *message, const char *location,
335  void *func_arg)
336 {
337  grn_logger_context *context = func_arg;
338  grn_log *log;
339 
340  log = grn_log_new(level, time, title, message, location);
341  context->logs = g_list_append(context->logs, log);
342  context->messages = g_list_append(context->messages, g_strdup(message));
343  if (context->collected_message) {
344  g_string_free(context->collected_message, TRUE);
345  context->collected_message = NULL;
346  }
347 }
348 
351 {
352  grn_logger_info *logger;
353 
354  logger = g_new(grn_logger_info, 1);
355  logger->max_level = GRN_LOG_DUMP;
357  logger->func = grn_collect_logger_log_func;
358  logger->func_arg = grn_logger_context_new(logger);
359 
360  return logger;
361 }
362 
363 void
365 {
366  grn_logger_context *context = logger->func_arg;
367 
368  grn_logger_context_clear_messages(context);
369 }
370 
371 const GList *
373 {
374  grn_logger_context *context = logger->func_arg;
375 
376  return context->messages;
377 }
378 
379 const gchar *
381 {
382  grn_logger_context *context = logger->func_arg;
383  const GList *messages;
384 
385  if (context->collected_message) {
386  return context->collected_message->str;
387  }
388 
389  context->collected_message = g_string_new(NULL);
390  for (messages = grn_collect_logger_get_messages(logger);
391  messages;
392  messages = g_list_next(messages)) {
393  const gchar *message = messages->data;
394  g_string_append_printf(context->collected_message, "%s\n", message);
395  }
396 
397  return context->collected_message->str;
398 }
399 
400 void
402 {
403  const GList *messages;
404 
405  for (messages = grn_collect_logger_get_messages(logger);
406  messages;
407  messages = g_list_next(messages)) {
408  const gchar *message = messages->data;
409  g_print("%s\n", message);
410  }
411 }
412 
413 void
415 {
416  if (!logger) {
417  return;
418  }
419 
420  grn_logger_context_free(logger->func_arg);
421  g_free(logger);
422 }
423 
424 
427 {
428  grn_logger_info *logger;
429 
430  logger = grn_collect_logger_new();
431  grn_logger_info_set(NULL, logger);
432  return logger;
433 }
434 
435 void
437 {
438  grn_logger_info_set(NULL, NULL);
439  if (logger) {
440  grn_collect_logger_free(logger);
441  }
442 }
443 
444 GString *
445 grn_long_path_new(const gchar *base_path, gssize max_size)
446 {
447  GString *long_path;
448 
449  long_path = g_string_new(base_path);
450  while (long_path->len < max_size) {
451  g_string_append(long_path, G_DIR_SEPARATOR_S "XXXXXXXXXX");
452  }
453  g_string_set_size(long_path, max_size);
454 
455  return long_path;
456 }
457 
458 GString *
459 grn_long_name_new(gssize max_size)
460 {
461  GString *long_name;
462 
463  long_name = g_string_new(NULL);
464  while (long_name->len < max_size) {
465  g_string_append(long_name, "aaaaaaaaaa");
466  g_string_append(long_name, "bbbbbbbbbb");
467  g_string_append(long_name, "cccccccccc");
468  g_string_append(long_name, "dddddddddd");
469  g_string_append(long_name, "eeeeeeeeee");
470  }
471  g_string_set_size(long_name, max_size);
472 
473  return long_name;
474 }
475 
476 GList *
478 {
479  GList *keys = NULL;
480  grn_id id;
481 
482  id = grn_table_cursor_next(context, cursor);
483  while (id != GRN_ID_NIL) {
484  void *key;
485  GString *null_terminated_key;
486  int size;
487 
488  size = grn_table_cursor_get_key(context, cursor, &key);
489  null_terminated_key = g_string_new_len(key, size);
490  keys = g_list_append(keys, g_string_free(null_terminated_key, FALSE));
491  id = grn_table_cursor_next(context, cursor);
492  }
493 
494  return keys;
495 }
496 
497 GList *
498 grn_test_pat_get_keys(grn_ctx *context, grn_obj *patricia_trie)
499 {
500  GList *keys;
501  grn_table_cursor *cursor;
502 
503  cursor = grn_table_cursor_open(context, patricia_trie,
504  NULL, 0, NULL, 0, 0, -1, GRN_CURSOR_ASCENDING);
505  keys = grn_test_pat_cursor_get_keys(context, cursor);
506  grn_table_cursor_close(context, cursor);
507 
508  return keys;
509 }
510 
511 GList *
513 {
514  grn_id id;
515  GList *pairs = NULL;
516 
517  id = grn_table_cursor_next(context, cursor);
518  while (id != GRN_ID_NIL) {
519  int length;
520  void *key, *value;
521  GString *null_terminated_key, *null_terminated_value;
522 
523  length = grn_table_cursor_get_key(context, cursor, &key);
524  null_terminated_key = g_string_new_len(key, length);
525  pairs = g_list_append(pairs,
526  g_string_free(null_terminated_key, FALSE));
527 
528  length = grn_table_cursor_get_value(context, cursor, &value);
529  null_terminated_value = g_string_new_len(value, length);
530  pairs = g_list_append(pairs,
531  g_string_free(null_terminated_value, FALSE));
532 
533  id = grn_table_cursor_next(context, cursor);
534  }
535 
536  return pairs;
537 }
538 
539 GHashTable *
540 grn_test_pat_get_pairs(grn_ctx *context, grn_obj *patricia_trie)
541 {
542  GList *node, *ordered_pairs;
543  GHashTable *pairs;
544  grn_table_cursor *cursor;
545 
546  cursor = grn_table_cursor_open(context, patricia_trie,
547  NULL, 0, NULL, 0, 0, -1, GRN_CURSOR_ASCENDING);
548  ordered_pairs = grn_test_pat_cursor_get_pairs(context, cursor);
549  grn_table_cursor_close(context, cursor);
550 
551  pairs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
552  for (node = ordered_pairs; node; node = g_list_next(node)) {
553  gchar *key, *value;
554 
555  key = node->data;
556  node = g_list_next(node);
557  if (!node)
558  break;
559  value = node->data;
560 
561  g_hash_table_insert(pairs, key, value);
562  }
563  g_list_free(ordered_pairs);
564 
565  return pairs;
566 }
567 
568 const gchar *
569 grn_test_type_inspect (grn_ctx *context, unsigned char type)
570 {
571  switch (type) {
572  case GRN_VOID:
573  return "void";
574  case GRN_BULK:
575  return "bulk";
576  case GRN_PTR:
577  return "ptr";
578  case GRN_UVECTOR:
579  return "uvector";
580  case GRN_PVECTOR:
581  return "pvector";
582  case GRN_MSG:
583  return "msg";
584  case GRN_QUERY:
585  return "query";
586  case GRN_ACCESSOR:
587  return "accessor";
588  case GRN_SNIP:
589  return "snip";
590  case GRN_PATSNIP:
591  return "patsnip";
593  return "cursor-table-hash-key";
595  return "cursor-table-pat-key";
597  return "cursor-table-no-key";
599  return "cursor-column-index";
600  case GRN_TYPE:
601  return "type";
602  case GRN_PROC:
603  return "proc";
604  case GRN_EXPR:
605  return "expr";
606  case GRN_TABLE_HASH_KEY:
607  return "table-hash-key";
608  case GRN_TABLE_PAT_KEY:
609  return "table-pat-key";
610  case GRN_TABLE_NO_KEY:
611  return "table-no-key";
612  case GRN_DB:
613  return "db";
614  case GRN_COLUMN_FIX_SIZE:
615  return "column-fix-size";
616  case GRN_COLUMN_VAR_SIZE:
617  return "column-var-size";
618  case GRN_COLUMN_INDEX:
619  return "column-index";
620  default:
621  return "unknown";
622  }
623 }
624 
625 void
626 grn_test_object_inspect (GString *output, grn_ctx *context, grn_obj *object)
627 {
628  grn_id domain;
629 
630  if (!object) {
631  g_string_append(output, "<NULL>");
632  return;
633  }
634 
635  g_string_append(output, "#<");
636  g_string_append_printf(output, "%s",
637  grn_test_type_inspect(context, object->header.type));
638  g_string_append_printf(output, ":%p ", object);
639  g_string_append_printf(output, "flags: 0x%x, ", object->header.flags);
640 
641  g_string_append(output, "domain: ");
642  domain = object->header.domain;
643  if (domain == GRN_ID_NIL) {
644  g_string_append(output, "<nil>");
645  } else {
646  grn_obj *domain_object = NULL;
647 
648  if (context)
649  domain_object = grn_ctx_at(context, domain);
650  if (domain_object)
651  grn_test_object_inspect(output, context, domain_object);
652  else
653  g_string_append_printf(output, "%u", domain);
654  }
655 
656  g_string_append(output, ">");
657 }
658 
659 const gchar *
660 grn_test_send_command(grn_ctx *context, const gchar *command)
661 {
662  unsigned int send_id, receive_id;
663  GString *result;
664  const gchar **lines;
665  const gchar *taken_result;
666 
667  result = g_string_new(NULL);
668  lines = cut_take_string_array(g_strsplit(command, "\n", 0));
669  for (; *lines; lines++) {
670  gchar *command_result;
671  unsigned int command_result_length;
672  int flags = 0;
673 
674  send_id = grn_ctx_send(context, *lines, strlen(*lines), 0);
675  grn_test_assert_context(context,
676  cut_message("<%s>:<%s>:<%s>",
677  *lines, command, result->str));
678  receive_id = grn_ctx_recv(context, &command_result, &command_result_length,
679  &flags);
680  cut_assert_equal_uint(send_id, receive_id);
681  g_string_append_len(result, command_result, command_result_length);
682  grn_test_assert_context(context,
683  cut_message("<%s>:<%s>", command, result->str));
684  }
685 
686  taken_result = cut_take_strdup(result->str);
687  g_string_free(result, TRUE);
688  return taken_result;
689 }
690 
691 void
692 grn_test_send_commands(grn_ctx *context, const gchar *line_separated_commands)
693 {
694  const gchar **commands;
695 
696  commands = cut_take_string_array(g_strsplit(line_separated_commands, "\n", 0));
697  for (; *commands; commands++) {
698  if (*commands[0] != '\0') {
699  grn_test_send_command(context, *commands);
700  }
701  }
702 }
703 
704 const GList *
706  grn_obj *table,
707  const gchar *text_column_name)
708 {
709  GList *records = NULL;
710  grn_table_cursor *cursor;
711  grn_id id;
712  grn_obj *text_column;
713  grn_obj value;
714 
715  cursor = grn_table_cursor_open(context, table, NULL, 0, NULL, 0,
716  0, -1, GRN_CURSOR_ASCENDING);
717  grn_test_assert_context(context);
718  text_column = grn_obj_column(context, table,
719  text_column_name, strlen(text_column_name));
720  GRN_TEXT_INIT(&value, 0);
721  while ((id = grn_table_cursor_next(context, cursor)) != GRN_ID_NIL) {
722  GRN_BULK_REWIND(&value);
723  grn_obj_get_value(context, text_column, id, &value);
724  records = g_list_append(records, g_strndup(GRN_TEXT_VALUE(&value),
725  GRN_TEXT_LEN(&value)));
726  }
727  grn_obj_unlink(context, &value);
728  grn_obj_unlink(context, text_column);
729  gcut_take_list(records, g_free);
730  grn_test_assert(grn_table_cursor_close(context, cursor));
731  grn_test_assert_context(context);
732 
733  return records;
734 }
735 
736 gint
737 grn_test_coordinate_in_milliseconds(gdouble coordinate_in_degree)
738 {
739  gint coordinate_in_milliseconds = 0;
740  gint accuracy = 10000000;
741  glong decimal_number;
742 
743  coordinate_in_milliseconds += (gint)coordinate_in_degree * 60 * 60 * 1000;
744  decimal_number = ((glong)(coordinate_in_degree * accuracy) % accuracy) * 60;
745  coordinate_in_milliseconds += decimal_number / accuracy * 60 * 1000;
746  coordinate_in_milliseconds += decimal_number % accuracy * 60 / 10000;
747 
748  return coordinate_in_milliseconds;
749 }
750 
751 gdouble
752 grn_test_coordinate_in_degree(gint coordinate_in_milliseconds)
753 {
754  return (coordinate_in_milliseconds / 3600.0) * 0.001;
755 }
756 
757 const gchar *
758 grn_test_location_string(gdouble latitude_in_degree,
759  gdouble longitude_in_degree)
760 {
761  gint latitude_in_milliseconds, longitude_in_milliseconds;
762 
763  latitude_in_milliseconds =
764  grn_test_coordinate_in_milliseconds(latitude_in_degree);
765  longitude_in_milliseconds =
766  grn_test_coordinate_in_milliseconds(longitude_in_degree);
767 
768  return cut_take_printf("%dx%d",
769  latitude_in_milliseconds, longitude_in_milliseconds);
770 }