/* ライブラリの関数呼び出しのテスト
*
* デフォルトでは、test.txtから1行ずつ読み込んで変換を行う。
* 変換前の文字列と変換を行った結果をtest.expから探し、
* 変換結果が合っているかをカウントして最後に出力する。
*
* ./anthy --from 1 --to 10 のように実行するとtest.txtの最初の10個の
* 行の変換テストが行われます。
*
* --askオプションを付けて実行すると、結果が合っているかの判断を
* 設定するモードになるので、表示された結果に対する判断を
* 標準入力から'y', 'n', 'd', 'q'で入力してください。
* 'd' dont care, 'q' quit
* 判断できない場合はその他の文字を入力してください。
*
* Copyright (C) 2000-2006 TABATA Yusuke
* Copyright (C) 2004-2006 YOSHIDA Yuichi
* Copyright (C) 2001-2002 TAKAI Kosuke
*
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <anthy/anthy.h>
#include <anthy/convdb.h>
#include <config.h>
/* Makefile の $(srcdir) (静的データファイルの基準ディレクトリ) */
#ifndef SRCDIR
# define SRCDIR "."
#endif
/* ビルド時のカレントディレクトリ (ここに .anthy を作る) */
#ifndef TEST_HOME
# define TEST_HOME "." /* FIXME: 実際は相対パスだと誤動作する */
#endif
/* テストデータとなる変換前の文字列 */
#define TESTDATA "test.txt"
const char *testdata = SRCDIR "/" TESTDATA;
/* 変換後の文字列が妥当かどうかをチェックするためのデータ */
#define EXPDATA "test.exp"
const char *expdata = SRCDIR "/" EXPDATA;
struct input {
char *str;
int serial;
};
/* テストを行う条件 */
struct condition {
/* conversion condition */
int serial;
int from;
int to;
/* operation */
int ask;
int quiet;
int miss_only;
int use_utf8;
};
static int
read_file(FILE *fp, struct input *in)
{
char buf[256];
while(fgets(buf, 256, fp)) {
switch(buf[0]){
case '#':
case ':':
case '-':
break;
case '*':
if (in->str) {
free(in->str);
in->str = 0;
}
buf[strlen(buf)-1] = 0;
in->str = strdup(&buf[1]);
in->serial ++;
return 0;
break;
}
}
return -1;
}
static int
check_cond(struct condition *cond, struct input *in)
{
if (in->serial == cond->serial) {
return 1;
}
if (in->serial <= cond->to && in->serial >= cond->from) {
return 1;
}
return 0;
}
static void
log_print(int lv, const char *msg)
{
printf("log:%d:%s\n", lv, msg);
}
static anthy_context_t
init_lib(int use_utf8)
{
anthy_context_t ac;
/* 既にインストールされているファイルの影響を受けないようにする */
anthy_conf_override("CONFFILE", "../anthy-conf");
anthy_conf_override("HOME", TEST_HOME);
anthy_conf_override("DIC_FILE", "../mkanthydic/anthy.dic");
anthy_set_logger(log_print, 0);
if (anthy_init()) {
printf("failed to init anthy\n");
exit(0);
}
anthy_set_personality("");
ac = anthy_create_context();
if (use_utf8) {
anthy_context_set_encoding(ac, ANTHY_UTF8_ENCODING);
} else {
anthy_context_set_encoding(ac, ANTHY_EUC_JP_ENCODING);
}
return ac;
}
static void
print_usage(void)
{
printf("Anthy "VERSION"\n"
"./anthy [test-id]\n"
" For example.\n"
" ./anthy 1\n"
" ./anthy --to 100\n"
" ./anthy --from 10 --to 100\n"
" ./anthy --all --print-miss-only --ask\n"
" ./anthy --ll 1\n\n");
exit(0);
}
static void
parse_args(struct condition *cond, int argc, char **argv)
{
int i;
char *arg;
for (i = 1; i < argc; i++) {
arg = argv[i];
if (!strncmp(arg, "--", 2)) {
arg = &arg[2];
if (!strcmp(arg, "help") || !strcmp(arg, "version")) {
print_usage();
}
if (!strcmp(arg, "all")) {
cond->from = 0;
cond->to = 100000000;
} else if (!strcmp(arg, "quiet")) {
cond->quiet = 1;
} else if (!strcmp(arg, "ask") ||
!strcmp(arg, "query")) {
cond->ask = 1;
} else if (!strcmp(arg, "print-miss-only")) {
cond->miss_only = 1;
} else if (!strcmp(arg, "utf8")) {
cond->use_utf8 = 1;
}
if (i + 1 < argc) {
if (!strcmp(arg, "from")){
cond->from = atoi(argv[i+1]);
i++;
}else if (!strcmp(arg, "to")){
cond->to = atoi(argv[i+1]);
i++;
}else if (!strcmp(arg, "ll")) {
anthy_set_logger(NULL, atoi(argv[i+1]));
i++;
}
}
} else {
int num = atoi(arg);
if (num) {
cond->serial = num;
} else {
char *buf = alloca(strlen(SRCDIR)+strlen(arg) + 10);
sprintf(buf, SRCDIR "/%s.txt", arg);
testdata = strdup(buf);
}
}
}
}
static void
print_run_env(void)
{
time_t t;
const char *env;
env = getenv("ANTHY_ENABLE_DEBUG_PRINT");
if (!env) {
env = "";
}
printf("ANTHY_ENABLE_DEBUG_PRINT=(%s)\n", env);
env = getenv("ANTHY_SPLITTER_PRINT");
if (!env) {
env = "";
}
printf("ANTHY_SPLITTER_PRINT=(%s)\n", env);
printf("SRCDIR=(%s)\n", SRCDIR);
t = time(&t);
printf(PACKAGE "-" VERSION " %s", ctime(&t));
}
static void
sum_up(struct res_db *db, struct conv_res *cr)
{
int is_split;
struct res_stat *rs;
cr->used = 1;
db->total ++;
if (cr->res_str[0] == '|') {
rs = &db->split;
is_split = 1;
} else {
rs = &db->res;
is_split = 0;
}
if (cr->check == CHK_OK) {
rs->ok ++;
} else if (cr->check == CHK_MISS) {
rs->miss ++;
} else if (cr->check == CHK_DONTCARE) {
rs->dontcare ++;
} else {
rs->unknown ++;
}
}
static void
set_string(struct condition *cond, struct res_db *db,
struct input *in, anthy_context_t ac)
{
struct conv_res *cr1, *cr2;
int pr;
anthy_set_string(ac, in->str);
/* result */
cr1 = find_conv_res(db, ac, in->str, 1);
sum_up(db, cr1);
/* split */
cr2 = find_conv_res(db, ac, in->str, 0);
sum_up(db, cr2);
/**/
pr = 0;
if (cond->miss_only) {
if (cr1->check == CHK_MISS ||
cr2->check == CHK_MISS) {
pr = 1;
}
} else if (!cond->quiet) {
pr = 1;
}
if (pr) {
printf("%d:(%s)\n", in->serial, in->str);
anthy_print_context(ac);
}
anthy_reset_context(ac);
}
static void
dump_res(FILE *fp, struct conv_res *r)
{
fprintf(fp, "%s %s ", r->src_str, r->res_str);
if (r->check == CHK_MISS) {
fprintf(fp, "X");
} else if (r->check == CHK_OK) {
fprintf(fp, "OK");
} else if (r->check == CHK_DONTCARE) {
fprintf(fp, "*");
} else {
fprintf(fp, "?");
}
fprintf(fp, "\n");
}
static void
save_db(const char *fn, struct res_db *db)
{
FILE *fp = fopen(fn, "w");
struct conv_res *cr;
if (!fp) {
printf("failed to open (%s) to write\n", fn);
return ;
}
for (cr = db->res_list.next; cr; cr = cr->next) {
dump_res(fp, cr);
}
}
static void
ask_results(struct res_db *db)
{
struct conv_res *cr;
for (cr = db->res_list.next; cr; cr = cr->next) {
if (cr->check == CHK_UNKNOWN && cr->used == 1) {
char buf[256];
printf("%s -> %s (y/n/d/q)\n", cr->src_str, cr->res_str);
fgets(buf, 256, stdin);
if (buf[0] == 'y') {
cr->check = CHK_OK;
} else if (buf[0] == 'n') {
cr->check = CHK_MISS;
} else if (buf[0] == 'd') {
cr->check = CHK_DONTCARE;
} else if (buf[0] == 'q') {
return ;
}
}
}
}
static void
show_stat(struct res_db *db)
{
struct res_stat *rs;
int i;
/**/
printf("%d items\n", db->total);
for (i = 0; i < 2; i++) {
if (i == 0) {
printf("conversion result\n");
rs = &db->res;
} else {
printf("split result\n");
rs = &db->split;
}
printf("ok : %d\n", rs->ok);
printf("miss : %d\n", rs->miss);
printf("unknown : %d\n", rs->unknown);
printf("\n");
}
}
static void
init_condition(struct condition *cond)
{
cond->serial = 0;
cond->from = 0;
cond->to = 0;
/**/
cond->quiet = 0;
cond->ask = 0;
cond->miss_only = 0;
cond->use_utf8 = 0;
}
int
main(int argc,char **argv)
{
anthy_context_t ac;
FILE *fp;
struct input cur_input;
struct res_db *db;
struct condition cond;
cur_input.serial = 0;
cur_input.str = 0;
init_condition(&cond);
parse_args(&cond, argc, argv);
db = create_db();
read_db(db, expdata);
printf("./test_anthy --help to print usage.\n");
print_run_env();
fp = fopen(testdata, "r");
if (!fp) {
printf("failed to open %s.\n", testdata);
return 0;
}
ac = init_lib(cond.use_utf8);
/* ファイルを読んでいくループ */
while (!read_file(fp, &cur_input)) {
if (check_cond(&cond, &cur_input)) {
set_string(&cond, db, &cur_input, ac);
}
}
anthy_release_context(ac);
anthy_quit();
if (cond.ask) {
/* ユーザに聞く */
ask_results(db);
}
show_stat(db);
save_db(expdata, db);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1