1 #include <stdarg.h>
2 #include <stdlib.h>
3 #include <wchar.h>
4 #include <check.h>
5
6 #include "../hangul/hangul.h"
7
8 #define countof(x) ((sizeof(x)) / (sizeof(x[0])))
9
10 static bool
check_preedit(const char * keyboard,const char * input,const wchar_t * output)11 check_preedit(const char* keyboard, const char* input, const wchar_t* output)
12 {
13 HangulInputContext* ic;
14 const char* p;
15 const ucschar* preedit;
16 int res;
17
18 ic = hangul_ic_new(keyboard);
19
20 p = input;
21 while (*p != '\0') {
22 hangul_ic_process(ic, *p);
23 p++;
24 }
25
26 preedit = hangul_ic_get_preedit_string(ic);
27
28 res = wcscmp((const wchar_t*)preedit, output);
29
30 hangul_ic_delete(ic);
31
32 return res == 0;
33 }
34
35 static bool
check_commit(const char * keyboard,const char * input,const wchar_t * output)36 check_commit(const char* keyboard, const char* input, const wchar_t* output)
37 {
38 HangulInputContext* ic;
39 const char* p;
40 const ucschar* commit;
41 int res;
42
43 ic = hangul_ic_new(keyboard);
44
45 p = input;
46 while (*p != '\0') {
47 hangul_ic_process(ic, *p);
48 p++;
49 }
50
51 commit = hangul_ic_get_commit_string(ic);
52
53 res = wcscmp((const wchar_t*)commit, output);
54
55 hangul_ic_delete(ic);
56
57 return res == 0;
58 }
59
START_TEST(test_hangul_ic_process_2)60 START_TEST(test_hangul_ic_process_2)
61 {
62 /* ㄱㅏㅉ */
63 fail_unless(check_commit("2", "rkW", L"가"));
64 fail_unless(check_preedit("2", "rkW", L"ㅉ"));
65 /* ㅂㅓㅅㅅㅡ */
66 fail_unless(check_commit("2", "qjttm", L"벗"));
67 fail_unless(check_preedit("2", "qjttm", L"스"));
68 /* ㅂㅓㅆㅡ */
69 fail_unless(check_commit("2", "qjTm", L"버"));
70 fail_unless(check_preedit("2", "qjTm", L"쓰"));
71 /* ㅁㅏㄹㄱㅗ */
72 fail_unless(check_preedit("2", "akfr", L"맑"));
73 fail_unless(check_commit("2", "akfrh", L"말"));
74 fail_unless(check_preedit("2", "akfrh", L"고"));
75 }
76 END_TEST
77
START_TEST(test_hangul_ic_process_2y)78 START_TEST(test_hangul_ic_process_2y)
79 {
80 /* ㅎ */
81 fail_unless(check_preedit("2y", "g", L"ㅎ"));
82 /* ㅗ */
83 fail_unless(check_preedit("2y", "h", L"ㅗ"));
84 /* ㅌ */
85 fail_unless(check_preedit("2y", "x", L"ㅌ"));
86 /* ㅂㅇ */
87 fail_unless(check_preedit("2y", "qd", L"\x3178"));
88 /* ᄼ */
89 fail_unless(check_preedit("2y", "Z", L"\x113c\x1160"));
90 /* ᅐ */
91 fail_unless(check_preedit("2y", "V", L"\x1150\x1160"));
92 /* ᅝ */
93 fail_unless(check_preedit("2y", "sg", L"\x115d\x1160"));
94
95 /* ㄱㅏㅇ */
96 fail_unless(check_preedit("2y", "rkd", L"강"));
97 /* ㄹㅐ */
98 fail_unless(check_preedit("2y", "fo", L"래"));
99 /* ㅎ. ㄴ */
100 fail_unless(check_preedit("2y", "gKs", L"\x1112\x119e\x11ab"));
101 /* ㅂㅂㅇㅏㅁㅅㅅ */
102 fail_unless(check_preedit("2y", "qqdhatt", L"\x112c\x1169\x11de"));
103 /* ㅂㅂㅇㅏㅁㅅㅅㅛ */
104 fail_unless(check_commit("2y", "qqdhatty", L"\x112c\x1169\x11dd"));
105 fail_unless(check_preedit("2y", "qqdhatty", L"쇼"));
106 /* ㅂㅂㅇㅏㅁㅆㅛ */
107 fail_unless(check_commit("2y", "qqdhaTy", L"\x112c\x1169\x11b7"));
108 fail_unless(check_preedit("2y", "qqdhaTy", L"쑈"));
109 /* 옛이응 처리 */
110 /* ㅇㅇㅏㅇㅇㅏ */
111 fail_unless(check_commit("2y", "ddkdd", L"\x1147\x1161\x11bc"));
112 fail_unless(check_preedit("2y", "ddkdd", L"ㅇ"));
113 /* ㄱㅏㆁㆁ */
114 fail_unless(check_preedit("2y", "rkDD", L"\x1100\x1161\x11ee"));
115 /* ㄱㅏㆁㆁㅏ */
116 fail_unless(check_commit("2y", "rkDDk", L"\x1100\x1161\x11f0"));
117 fail_unless(check_preedit("2y", "rkDDk", L"\x114c\x1161"));
118 /* ㅏㅏㅏㅏ */
119 fail_unless(check_preedit("2y", "kkkk", L"\x115f\x11a2"));
120 }
121 END_TEST
122
START_TEST(test_hangul_ic_process_3f)123 START_TEST(test_hangul_ic_process_3f)
124 {
125 /* L V T */
126 /* ㅎ */
127 fail_unless(check_preedit("3f", "m", L"ㅎ"));
128 /* ㅗ */
129 fail_unless(check_preedit("3f", "v", L"ㅗ"));
130 /* ㅌ */
131 fail_unless(check_preedit("3f", "W", L"ㅌ"));
132
133 /* ㄱㅏㅇ */
134 fail_unless(check_preedit("3f", "kfa", L"강"));
135 /* ㄹㅐ */
136 fail_unless(check_preedit("3f", "yr", L"래"));
137 /* ㄴ ㅁ */
138 fail_unless(check_preedit("3f", "hz", L"\x1102\x1160\x11b7"));
139 /* ㅜㅅ */
140 fail_unless(check_preedit("3f", "tq", L"\x115f\x1165\x11ba"));
141 }
142 END_TEST
143
START_TEST(test_hangul_ic_process_romaja)144 START_TEST(test_hangul_ic_process_romaja)
145 {
146 HangulInputContext* ic;
147 const ucschar* preedit;
148 const ucschar* commit;
149
150 // romaja keyboard test
151 ic = hangul_ic_new("ro");
152
153 // basic test: han produces 한
154 hangul_ic_process(ic, 'h');
155 hangul_ic_process(ic, 'a');
156 hangul_ic_process(ic, 'n');
157
158 preedit = hangul_ic_get_preedit_string(ic);
159 commit = hangul_ic_get_commit_string(ic);
160 fail_unless(preedit[0] == L'한');
161 fail_unless(commit[0] == 0);
162
163 hangul_ic_reset(ic);
164
165 // insert ㅇ when a syllable is not started with consonant
166 hangul_ic_process(ic, 'a');
167
168 preedit = hangul_ic_get_preedit_string(ic);
169 commit = hangul_ic_get_commit_string(ic);
170 fail_unless(preedit[0] == L'아');
171 fail_unless(commit[0] == 0);
172
173 // remove correctly when automatically ㅇ was inserted
174 hangul_ic_backspace(ic);
175
176 preedit = hangul_ic_get_preedit_string(ic);
177 commit = hangul_ic_get_commit_string(ic);
178 fail_unless(preedit[0] == 0);
179 fail_unless(commit[0] == 0);
180
181 // append ㅡ when a syllable is not ended with vowel
182 hangul_ic_process(ic, 't');
183 hangul_ic_process(ic, 't');
184
185 preedit = hangul_ic_get_preedit_string(ic);
186 commit = hangul_ic_get_commit_string(ic);
187 fail_unless(preedit[0] == 0x314c); // ㅌ
188 fail_unless(commit[0] == L'트');
189
190 // ng makes trailing ㅇ
191 hangul_ic_reset(ic);
192 hangul_ic_process(ic, 'g');
193 hangul_ic_process(ic, 'a');
194 hangul_ic_process(ic, 'n');
195 hangul_ic_process(ic, 'g');
196
197 preedit = hangul_ic_get_preedit_string(ic);
198 commit = hangul_ic_get_commit_string(ic);
199 fail_unless(preedit[0] == L'강'); // 강
200 fail_unless(commit[0] == 0);
201
202 // gangi makes 강이
203 hangul_ic_process(ic, 'i');
204
205 preedit = hangul_ic_get_preedit_string(ic);
206 commit = hangul_ic_get_commit_string(ic);
207 fail_unless(preedit[0] == L'이');
208 fail_unless(commit[0] == L'강'); // 강
209
210 // nanG makes 난ㄱ
211 // uppercase makes new syllable
212 hangul_ic_process(ic, 'n');
213 hangul_ic_process(ic, 'a');
214 hangul_ic_process(ic, 'n');
215 hangul_ic_process(ic, 'G');
216
217 preedit = hangul_ic_get_preedit_string(ic);
218 commit = hangul_ic_get_commit_string(ic);
219 fail_unless(preedit[0] == 0x3131); // ㄱ
220 fail_unless(commit[0] == L'난'); // 난
221
222 // special operation for x
223 // x generate ㅈ for leading consonant
224 hangul_ic_reset(ic);
225 hangul_ic_process(ic, 'x');
226 hangul_ic_process(ic, 'x');
227
228 preedit = hangul_ic_get_preedit_string(ic);
229 commit = hangul_ic_get_commit_string(ic);
230 fail_unless(preedit[0] == 0x3148); // 지
231 fail_unless(commit[0] == L'즈');
232
233 hangul_ic_reset(ic);
234 hangul_ic_process(ic, 'x');
235 hangul_ic_process(ic, 'y');
236
237 preedit = hangul_ic_get_preedit_string(ic);
238 commit = hangul_ic_get_commit_string(ic);
239 fail_unless(preedit[0] == L'지'); // 지
240 fail_unless(commit[0] == 0x0);
241
242 // x generate ㄱㅅ for trailing consonant
243 // and ㅅ will be transferred to next syllable when next input
244 // character is vowel.
245 hangul_ic_reset(ic);
246 hangul_ic_process(ic, 's');
247 hangul_ic_process(ic, 'e');
248 hangul_ic_process(ic, 'x');
249 hangul_ic_process(ic, 'y');
250
251 preedit = hangul_ic_get_preedit_string(ic);
252 commit = hangul_ic_get_commit_string(ic);
253 fail_unless(preedit[0] == L'시'); // 시
254 fail_unless(commit[0] == L'섹'); // 섹
255
256 hangul_ic_delete(ic);
257 }
258 END_TEST
259
START_TEST(test_syllable_iterator)260 START_TEST(test_syllable_iterator)
261 {
262 ucschar str[] = {
263 // L L V V T T
264 0x1107, 0x1107, 0x116e, 0x1166, 0x11af, 0x11a8, // 0
265 // L V T
266 0x1108, 0x1170, 0x11b0, // 6
267 // L L V V T T M
268 0x1107, 0x1107, 0x116e, 0x1166, 0x11af, 0x11a8, 0x302E, // 9
269 // L V T M
270 0x1108, 0x1170, 0x11b0, 0x302F, // 16
271 // Lf V
272 0x115f, 0x1161, // 20
273 // L Vf
274 0x110c, 0x1160, // 22
275 // L LVT T
276 0x1107, 0xbc14, 0x11a8, // 24
277 // L LV T
278 0x1100, 0xac00, 0x11a8, // 27
279 // LVT
280 0xc00d, // 30
281 // other
282 'a', // 31
283 0 // 32
284 };
285
286 const ucschar* begin = str;
287 const ucschar* end = str + countof(str) - 1;
288 const ucschar* s = str;
289
290 s = hangul_syllable_iterator_next(s, end);
291 fail_unless(s - str == 6,
292 "error: next syllable: L L V V T T");
293
294 s = hangul_syllable_iterator_next(s, end);
295 fail_unless(s - str == 9,
296 "error: next syllable: L V T");
297
298 s = hangul_syllable_iterator_next(s, end);
299 fail_unless(s - str == 16,
300 "error: next syllable: L L V V T T M");
301
302 s = hangul_syllable_iterator_next(s, end);
303 fail_unless(s - str == 20,
304 "error: next syllable: L V T M");
305
306 s = hangul_syllable_iterator_next(s, end);
307 fail_unless(s - str == 22,
308 "error: next syllable: Lf V");
309
310 s = hangul_syllable_iterator_next(s, end);
311 fail_unless(s - str == 24,
312 "error: next syllable: L Vf");
313
314 s = hangul_syllable_iterator_next(s, end);
315 fail_unless(s - str == 27,
316 "error: next syllable: L LVT T");
317
318 s = hangul_syllable_iterator_next(s, end);
319 fail_unless(s - str == 30,
320 "error: next syllable: L LV T");
321
322 s = hangul_syllable_iterator_next(s, end);
323 fail_unless(s - str == 31,
324 "error: next syllable: LVT");
325
326 s = hangul_syllable_iterator_next(s, end);
327 fail_unless(s - str == 32,
328 "error: next syllable: other");
329
330 s = end;
331 s = hangul_syllable_iterator_prev(s, begin);
332 fail_unless(s - str == 31,
333 "error: prev syllable: other");
334
335 s = hangul_syllable_iterator_prev(s, begin);
336 fail_unless(s - str == 30,
337 "error: prev syllable: LVT");
338
339 s = hangul_syllable_iterator_prev(s, begin);
340 fail_unless(s - str == 27,
341 "error: prev syllable: L LV T");
342
343 s = hangul_syllable_iterator_prev(s, begin);
344 fail_unless(s - str == 24,
345 "error: prev syllable: L LVT T");
346
347 s = hangul_syllable_iterator_prev(s, begin);
348 fail_unless(s - str == 22,
349 "error: prev syllable: L Vf");
350
351 s = hangul_syllable_iterator_prev(s, begin);
352 fail_unless(s - str == 20,
353 "error: prev syllable: Lf V");
354
355 s = hangul_syllable_iterator_prev(s, begin);
356 fail_unless(s - str == 16,
357 "error: prev syllable: L V T M");
358
359 s = hangul_syllable_iterator_prev(s, begin);
360 fail_unless(s - str == 9,
361 "error: prev syllable: L L V V T T M");
362
363 s = hangul_syllable_iterator_prev(s, begin);
364 fail_unless(s - str == 6,
365 "error: prev syllable: L V T");
366
367 s = hangul_syllable_iterator_prev(s, begin);
368 fail_unless(s - str == 0,
369 "error: prev syllable: L L V V T T");
370 }
371 END_TEST
372
START_TEST(test_hangul_keyboard)373 START_TEST(test_hangul_keyboard)
374 {
375 const char* id;
376 const char* name;
377 unsigned int n;
378 unsigned int i;
379
380 n = hangul_ic_get_n_keyboards();
381 fail_unless(n != 0,
382 "error: there is no builtin hangul keyboard");
383
384 for (i = 0; i < n; ++i) {
385 id = hangul_ic_get_keyboard_id(i);
386 fail_unless(id != NULL,
387 "error: keyboard id == NULL");
388 }
389
390 for (i = 0; i < n; ++i) {
391 name = hangul_ic_get_keyboard_name(i);
392 fail_unless(name != NULL,
393 "error: keyboard id == NULL");
394 }
395 }
396 END_TEST
397
libhangul_suite()398 Suite* libhangul_suite()
399 {
400 Suite* s = suite_create("libhangul");
401
402 TCase* hangul = tcase_create("hangul");
403 tcase_add_test(hangul, test_hangul_ic_process_2);
404 tcase_add_test(hangul, test_hangul_ic_process_2y);
405 tcase_add_test(hangul, test_hangul_ic_process_3f);
406 tcase_add_test(hangul, test_hangul_ic_process_romaja);
407 tcase_add_test(hangul, test_syllable_iterator);
408 tcase_add_test(hangul, test_hangul_keyboard);
409 suite_add_tcase(s, hangul);
410
411 return s;
412 }
413
main()414 int main()
415 {
416 int number_failed;
417 Suite* s = libhangul_suite();
418 SRunner* sr = srunner_create(s);
419
420 srunner_set_fork_status(sr, CK_NOFORK);
421 srunner_run_all(sr, CK_NORMAL);
422
423 number_failed = srunner_ntests_failed(sr);
424 srunner_free(sr);
425
426 return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
427 }
428