1 /* Copyright (c) 2007 Eric Scott Albright
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 * THE SOFTWARE.
20 */
21
22 #include <UnitTest++/UnitTest++.h>
23 #include <enchant.h>
24 #include <vector>
25 #include <algorithm>
26
27 #include "EnchantDictionaryTestFixture.h"
28
29 static bool dictSuggestCalled;
30 std::string suggestWord;
31
32 static enum SuggestBehavior{
33 returnNull,
34 returnZero,
35 returnFour,
36 returnFourOneInvalidUtf8,
37 returnFianceNfc
38 } suggestBehavior;
39
40 struct EnchantDictionarySuggestTestFixtureBase : EnchantDictionaryTestFixture
41 {
42 //Setup
EnchantDictionarySuggestTestFixtureBaseEnchantDictionarySuggestTestFixtureBase43 EnchantDictionarySuggestTestFixtureBase(ConfigureHook userConfiguration):
44 EnchantDictionaryTestFixture(userConfiguration)
45 {
46 dictSuggestCalled = false;
47 _suggestions = NULL;
48 _pwl_suggestions = NULL;
49 suggestWord = std::string();
50 suggestBehavior = returnFour;
51 }
52 //Teardown
~EnchantDictionarySuggestTestFixtureBaseEnchantDictionarySuggestTestFixtureBase53 ~EnchantDictionarySuggestTestFixtureBase()
54 {
55 FreeStringList(_suggestions);
56 FreePwlStringList(_pwl_suggestions);
57 }
58
59 char** _suggestions;
60 char** _pwl_suggestions;
61 };
62
63 static char **
MyMockDictionarySuggest(EnchantDict * dict,const char * const word,size_t len,size_t * out_n_suggs)64 MyMockDictionarySuggest (EnchantDict * dict, const char *const word, size_t len, size_t * out_n_suggs)
65 {
66 dictSuggestCalled = true;
67 suggestWord = std::string(word,len);
68 *out_n_suggs = 0;
69 char **sugg_arr = NULL;
70
71 switch(suggestBehavior)
72 {
73 case returnNull:
74 sugg_arr = NULL;
75 break;
76 case returnZero:
77 sugg_arr = g_new0 (char *, *out_n_suggs + 1);
78 break;
79 case returnFianceNfc:
80 *out_n_suggs = 1;
81 sugg_arr = g_new0 (char *, *out_n_suggs + 1);
82 sugg_arr[0] = g_strdup ("fianc\xc3\xa9"); // c3 a9 = utf8 for u00e9 = Latin small letter e with acute
83 break;
84 case returnFour:
85 sugg_arr = MockDictionarySuggest(dict, word, len, out_n_suggs);
86 break;
87 case returnFourOneInvalidUtf8:
88 sugg_arr = MockDictionarySuggest(dict, word, len, out_n_suggs);
89 g_free(sugg_arr[0]);
90 sugg_arr[0] = g_strdup ("\xa5\xf1\x08");
91 break;
92 }
93
94 return sugg_arr;
95 }
96
MockProviderRequestSuggestMockDictionary(EnchantProvider * me,const char * tag)97 static EnchantDict* MockProviderRequestSuggestMockDictionary(EnchantProvider * me, const char *tag)
98 {
99
100 EnchantDict* dict = MockProviderRequestEmptyMockDictionary(me, tag);
101 dict->suggest = MyMockDictionarySuggest;
102 return dict;
103 }
104
DictionarySuggest_ProviderConfiguration(EnchantProvider * me,const char *)105 static void DictionarySuggest_ProviderConfiguration (EnchantProvider * me, const char *)
106 {
107 me->request_dict = MockProviderRequestSuggestMockDictionary;
108 me->dispose_dict = MockProviderDisposeDictionary;
109 }
110
111
112
113
114 struct EnchantDictionarySuggest_TestFixture : EnchantDictionarySuggestTestFixtureBase
115 {
116 //Setup
EnchantDictionarySuggest_TestFixtureEnchantDictionarySuggest_TestFixture117 EnchantDictionarySuggest_TestFixture():
118 EnchantDictionarySuggestTestFixtureBase(DictionarySuggest_ProviderConfiguration)
119 { }
120 };
121
122
123
124
MockProviderRequestNoSuggestMockDictionary(EnchantProvider * me,const char * tag)125 static EnchantDict* MockProviderRequestNoSuggestMockDictionary(EnchantProvider * me, const char *tag)
126 {
127
128 EnchantDict* dict = MockProviderRequestEmptyMockDictionary(me, tag);
129 dict->suggest = NULL;
130 return dict;
131 }
132
DictionaryNoSuggest_ProviderConfiguration(EnchantProvider * me,const char *)133 static void DictionaryNoSuggest_ProviderConfiguration (EnchantProvider * me, const char *)
134 {
135 me->request_dict = MockProviderRequestNoSuggestMockDictionary;
136 me->dispose_dict = MockProviderDisposeDictionary;
137 }
138
139 struct EnchantDictionarySuggestNotImplemented_TestFixture : EnchantDictionarySuggestTestFixtureBase
140 {
141 //Setup
EnchantDictionarySuggestNotImplemented_TestFixtureEnchantDictionarySuggestNotImplemented_TestFixture142 EnchantDictionarySuggestNotImplemented_TestFixture():
143 EnchantDictionarySuggestTestFixtureBase(DictionaryNoSuggest_ProviderConfiguration)
144 { }
145 };
146
147
148 /**
149 * enchant_dict_suggest
150 * @dict: A non-null #EnchantDict
151 * @word: The non-null word you wish to find suggestions for, in UTF-8 encoding
152 * @len: The byte length of @word, or -1 for strlen (@word)
153 * @out_n_suggs: The location to store the # of suggestions returned, or %null
154 *
155 * Will return an %null value if any of those pre-conditions
156 * are not met.
157 *
158 * Returns: A %null terminated list of UTF-8 encoded suggestions, or %null
159 */
160 /////////////////////////////////////////////////////////////////////////////
161 // Test Normal Operation
TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,EnchantDictionarySuggest_LenComputed)162 TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,
163 EnchantDictionarySuggest_LenComputed)
164 {
165 size_t cSuggestions;
166 _suggestions = enchant_dict_suggest(_dict, "helo", -1, &cSuggestions);
167 CHECK(_suggestions);
168 CHECK_EQUAL(std::string("helo"), suggestWord);
169 CHECK_EQUAL(4, cSuggestions);
170
171 std::vector<std::string> suggestions;
172 if(_suggestions != NULL){
173 suggestions.insert(suggestions.begin(), _suggestions, _suggestions+cSuggestions);
174 }
175
176 CHECK_ARRAY_EQUAL(GetExpectedSuggestions("helo"), suggestions, std::min((size_t)4,cSuggestions));
177 }
178
TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,EnchantDictionarySuggest_LenSpecified)179 TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,
180 EnchantDictionarySuggest_LenSpecified)
181 {
182 size_t cSuggestions;
183 _suggestions = enchant_dict_suggest(_dict, "helodisregard me", 4, &cSuggestions);
184 CHECK(_suggestions);
185 CHECK_EQUAL(std::string("helo"), suggestWord);
186 CHECK_EQUAL(4, cSuggestions);
187
188 std::vector<std::string> suggestions;
189 if(_suggestions != NULL){
190 suggestions.insert(suggestions.begin(), _suggestions, _suggestions+cSuggestions);
191 }
192
193 CHECK_ARRAY_EQUAL(GetExpectedSuggestions("helo"), suggestions, std::min((size_t)4,cSuggestions));
194 }
195
TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,EnchantDictionarySuggest_StringListFreed)196 TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,
197 EnchantDictionarySuggest_StringListFreed)
198 {
199 size_t cSuggs;
200 _suggestions = enchant_dict_suggest(_dict, "helo", -1, &cSuggs);
201 CHECK(dictSuggestCalled);
202 }
203
TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,EnchantDictionarySuggest_NullOutputSuggestionCount)204 TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,
205 EnchantDictionarySuggest_NullOutputSuggestionCount)
206 {
207 _suggestions = enchant_dict_suggest(_dict, "helo", -1, NULL);
208 CHECK(_suggestions);
209 CHECK(dictSuggestCalled);
210 }
211
TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,EnchantDictionarySuggest_InBrokerPwlSession)212 TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,
213 EnchantDictionarySuggest_InBrokerPwlSession)
214 {
215 enchant_dict_add(_pwl, "hello", -1);
216 _pwl_suggestions = enchant_dict_suggest(_pwl, "helo", -1, NULL);
217 CHECK(_pwl_suggestions);
218 CHECK(!dictSuggestCalled);
219 }
220
TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,EnchantDictionarySuggest_SuggestionsFromPersonal_addedToEnd)221 TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,
222 EnchantDictionarySuggest_SuggestionsFromPersonal_addedToEnd)
223 {
224 size_t cSuggestions;
225 enchant_dict_add(_dict, "hello", -1);
226 _suggestions = enchant_dict_suggest(_dict, "helo", -1, &cSuggestions);
227 CHECK(_suggestions);
228 CHECK_EQUAL(5, cSuggestions);
229
230 std::vector<std::string> suggestions;
231 if(_suggestions != NULL){
232 suggestions.insert(suggestions.begin(), _suggestions, _suggestions+cSuggestions);
233 }
234
235 std::vector<std::string> expected = GetExpectedSuggestions("helo");
236 expected.push_back("hello");
237
238 CHECK_ARRAY_EQUAL(expected, suggestions, std::min((size_t)5,cSuggestions));
239 }
240
241
TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,EnchantDictionarySuggest_DuplicateSuggestionsFromPersonal_notIncluded)242 TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,
243 EnchantDictionarySuggest_DuplicateSuggestionsFromPersonal_notIncluded)
244 {
245 size_t cSuggestions;
246
247 enchant_dict_add(_dict, "aelo", -1);
248 _suggestions = enchant_dict_suggest(_dict, "helo", -1, &cSuggestions);
249 CHECK(_suggestions);
250 CHECK_EQUAL(4, cSuggestions);
251
252 std::vector<std::string> suggestions;
253 if(_suggestions != NULL){
254 suggestions.insert(suggestions.begin(), _suggestions, _suggestions+cSuggestions);
255 }
256
257 CHECK_ARRAY_EQUAL(GetExpectedSuggestions("helo"), suggestions, std::min((size_t)4,cSuggestions));
258 }
259
TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,EnchantDictionarySuggest_SuggestionExcluded_Null)260 TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,
261 EnchantDictionarySuggest_SuggestionExcluded_Null)
262 {
263 suggestBehavior = returnFianceNfc;
264 RemoveWordFromDictionary(Convert(L"fianc\xe9")); // u00e9 = Latin small letter e with acute
265
266 _suggestions = enchant_dict_suggest(_dict, "fiance", -1, NULL);
267 CHECK(!_suggestions);
268 }
269
TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,EnchantDictionarySuggest_HasPreviousError_ErrorCleared)270 TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,
271 EnchantDictionarySuggest_HasPreviousError_ErrorCleared)
272 {
273 SetErrorOnMockDictionary("something bad happened");
274
275 _suggestions = enchant_dict_suggest(_dict, "helo", -1, NULL);
276 CHECK_EQUAL((void*)NULL, (void*)enchant_dict_get_error(_dict));
277 }
278
279 /////////////////////////////////////////////////////////////////////////////
280 // Test Error Conditions
TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,EnchantDictionarySuggest_NullDictionary_NullSuggestions)281 TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,
282 EnchantDictionarySuggest_NullDictionary_NullSuggestions)
283 {
284 _suggestions = enchant_dict_suggest(NULL, "helo", -1, NULL);
285
286 CHECK(!_suggestions);
287 CHECK(!dictSuggestCalled);
288 }
289
TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,EnchantDictionarySuggest_NullWord_NullSuggestions)290 TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,
291 EnchantDictionarySuggest_NullWord_NullSuggestions)
292 {
293 _suggestions = enchant_dict_suggest(_dict, NULL, -1, NULL);
294
295 CHECK(!_suggestions);
296 CHECK(!dictSuggestCalled);
297 }
298
TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,EnchantDictionarySuggest_EmptyWord_NullSuggestions)299 TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,
300 EnchantDictionarySuggest_EmptyWord_NullSuggestions)
301 {
302 _suggestions = enchant_dict_suggest(_dict, "", -1, NULL);
303
304 CHECK(!_suggestions);
305 CHECK(!dictSuggestCalled);
306 }
307
TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,EnchantDictionarySuggest_WordSize0_NullSuggestions)308 TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,
309 EnchantDictionarySuggest_WordSize0_NullSuggestions)
310 {
311 _suggestions = enchant_dict_suggest(_dict, "helo", 0, NULL);
312
313 CHECK(!_suggestions);
314 CHECK(!dictSuggestCalled);
315 }
316
TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,EnchantDictionarySuggest_InvalidUtf8Correction_DoNothing)317 TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,
318 EnchantDictionarySuggest_InvalidUtf8Correction_DoNothing)
319 {
320 _suggestions = enchant_dict_suggest(_dict, "\xa5\xf1\x08", -1, NULL);
321
322 CHECK(!_suggestions);
323 CHECK(!dictSuggestCalled);
324 }
325
326
TEST_FIXTURE(EnchantDictionarySuggestNotImplemented_TestFixture,EnchantDictionarySuggestNotImplemented_NullSuggestions)327 TEST_FIXTURE(EnchantDictionarySuggestNotImplemented_TestFixture,
328 EnchantDictionarySuggestNotImplemented_NullSuggestions)
329 {
330 _suggestions = enchant_dict_suggest(_dict, "helo", -1, NULL);
331
332 CHECK(!_suggestions);
333 CHECK(!dictSuggestCalled);
334 }
335
TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,EnchantDictionarySuggest_SuggestionListWithInvalidUtf8_InvalidSuggestionIgnored_FreeCalled)336 TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,
337 EnchantDictionarySuggest_SuggestionListWithInvalidUtf8_InvalidSuggestionIgnored_FreeCalled)
338 {
339 suggestBehavior = returnFourOneInvalidUtf8;
340 size_t cSuggestions;
341 _suggestions = enchant_dict_suggest(_dict, "helo", -1, &cSuggestions);
342 CHECK(_suggestions);
343 CHECK(dictSuggestCalled);
344
345 CHECK_EQUAL(3, cSuggestions);
346
347 std::vector<std::string> suggestions;
348 if(_suggestions != NULL){
349 suggestions.insert(suggestions.begin(), _suggestions, _suggestions+cSuggestions);
350 }
351
352 CHECK_ARRAY_EQUAL(GetExpectedSuggestions("helo",1), suggestions, std::min((size_t)3,cSuggestions));
353 }
354
TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,EnchantDictionarySuggest_WordNfcInDictionaryNfdInPwl_ReturnsFromDict)355 TEST_FIXTURE(EnchantDictionarySuggest_TestFixture,
356 EnchantDictionarySuggest_WordNfcInDictionaryNfdInPwl_ReturnsFromDict)
357 {
358 suggestBehavior = returnFianceNfc;
359
360 ExternalAddWordToDictionary(Convert(L"fiance\x301")); // NFD u0301 = Combining acute accent
361
362 ReloadTestDictionary();
363
364 size_t cSuggestions;
365 _suggestions = enchant_dict_suggest(_dict, "fiance", -1, &cSuggestions);
366 CHECK(_suggestions);
367
368 CHECK_EQUAL(1, cSuggestions);
369 CHECK_EQUAL(Convert(L"fianc\xe9"), _suggestions[0]);
370 }
371
TEST_FIXTURE(EnchantDictionarySuggestNotImplemented_TestFixture,EnchantDictionarySuggest_WordInDictionaryAndExclude_NotInSuggestions)372 TEST_FIXTURE(EnchantDictionarySuggestNotImplemented_TestFixture,
373 EnchantDictionarySuggest_WordInDictionaryAndExclude_NotInSuggestions)
374 {
375 ExternalAddWordToExclude("hello");
376 ExternalAddWordToDictionary("hello");
377
378 ReloadTestDictionary();
379
380 size_t cSuggestions;
381 _suggestions = enchant_dict_suggest(_dict, "helo", -1, &cSuggestions);
382 CHECK(!_suggestions);
383
384 CHECK_EQUAL(0, cSuggestions);
385 }
386
387