/* Copyright (c) 2008 Eric Scott Albright
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <UnitTest++.h>
#include "../unittest_enchant_providers.h"
#include <vector>
#include <map>
#include <assert.h>
#include <string.h>
struct DictionaryCheck_TestFixture : Provider_TestFixture
{
typedef std::multimap<EnchantDict*, std::string> AddedWordsByDict;
EnchantDict* _dict;
const char *_provider_name;
AddedWordsByDict _addedWordsByDict;
//Setup
DictionaryCheck_TestFixture():_dict(NULL)
{
_dict = GetFirstAvailableDictionary();
/* FIXME: hspell does not consider non-Hebrew letters to be valid letters */
if (_dict) {
_provider_name = _provider->identify(_provider);
if (strcmp(_provider_name, "hspell") == 0)
_dict = NULL;
}
}
//Teardown
~DictionaryCheck_TestFixture()
{
ReleaseDictionary(_dict);
}
virtual void ReleaseDictionary(EnchantDict* dict){
std::pair<AddedWordsByDict::const_iterator,
AddedWordsByDict::const_iterator>
addedWords = _addedWordsByDict.equal_range(dict);
AddedWordsByDict::const_iterator it;
for(it = addedWords.first; it != addedWords.second; ++it)
{
if(dict->add_to_exclude)
{
(*dict->add_to_exclude)(dict, it->second.c_str(), it->second.length());
}
}
_addedWordsByDict.erase(dict);
Provider_TestFixture::ReleaseDictionary(dict);
}
bool IsWordInDictionary(const std::string& word)
{
return IsWordInDictionary(_dict, word);
}
static bool IsWordInDictionary(EnchantDict* dict, const std::string& word)
{
assert(dict && dict->check); // tests must check this before calling
return (*dict->check)(dict, word.c_str(), word.length()) == 0; //check returns 0 when successful and 1 when not successful
}
bool AddWordToDictionary(const std::string& word)
{
return AddWordToDictionary(_dict, word);
}
bool AddWordToDictionary(EnchantDict* dict, const std::string& word)
{
if(dict == NULL)
{
return false;
}
if(IsWordInDictionary(word))
{
return true;
}
// prefer adding it to the session so it will get automatically removed
if(dict->add_to_session)
{
(*dict->add_to_session) (dict, word.c_str(), word.length());
if(IsWordInDictionary(word))
{
return true;
}
}
if(dict->add_to_personal)
{
_addedWordsByDict.insert(std::pair<EnchantDict*, std::string>(dict,word));
(*dict->add_to_personal) (dict, word.c_str(), word.length());
if(IsWordInDictionary(word))
{
return true;
}
}
return false;
}
};
/////////////////////////////////////////////////////////////////////////////////////////////////
// Unicode normalization
TEST_FIXTURE(DictionaryCheck_TestFixture,
IsWordInDictionary_AddedComposed_SuccessfulCheckWithComposedAndDecomposed)
{
if(_dict && _dict->check)
{
if(AddWordToDictionary(Convert(L"fianc\x00e9" L"deleteme"))) // u00e9 = Latin small letter e with acute
{
// FIXME: These tests time out on macOS >= 10.12 with "findMisspelledWordInString timed out"
#if !(defined(__APPLE__) && defined(__MACH__))
CHECK( IsWordInDictionary(Convert(L"fianc\x00e9" L"deleteme")) ); //NFC
CHECK( IsWordInDictionary(Convert(L"fiance\x0301" L"deleteme")) ); //NFD u0301 = Combining acute accent
#endif
}
}
}
TEST_FIXTURE(DictionaryCheck_TestFixture,
IsWordInDictionary_AddedDecomposed_SuccessfulCheckWithComposedAndDecomposed)
{
if(_dict && _dict->check)
{
if(AddWordToDictionary(Convert(L"fiance\x0301" L"deletethis"))) // u0301 = Combining acute accent
{
CHECK( IsWordInDictionary(Convert(L"fianc\x00e9" L"deletethis")) ); //NFC
CHECK( IsWordInDictionary(Convert(L"fiance\x0301" L"deletethis")) ); //NFD
}
}
}
TEST_FIXTURE(DictionaryCheck_TestFixture,
IsWordInDictionary_SuccessfulCheckWithComposedAndDecomposed)
{
EnchantDict* dict = GetDictionary("fr_FR");
if(dict && dict->check)
{
CHECK( IsWordInDictionary(dict, Convert(L"Fran\x00e7" L"ais")) ); //NFC latin small letter c with cedilla
CHECK( IsWordInDictionary(dict, Convert(L"Franc\x0327" L"ais")) ); //NFD combining cedilla
}
ReleaseDictionary(dict);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Capitalization
TEST_FIXTURE(DictionaryCheck_TestFixture,
IsWordInDictionary_AddedAllCaps_OnlyAllCapsSuccessful)
{
if(_dict && _dict->check)
{
if(AddWordToDictionary("ZYX"))
{
CHECK( IsWordInDictionary("ZYX") );
CHECK(!IsWordInDictionary("ZYx") );
CHECK(!IsWordInDictionary("Zyx") );
CHECK(!IsWordInDictionary("zyx") );
if (strcmp(_provider_name, "AppleSpell") != 0) /* FIXME: This fails on AppleSpell */
CHECK(!IsWordInDictionary("zYx") );
}
}
}
TEST_FIXTURE(DictionaryCheck_TestFixture,
IsWordInDictionary_AddedTitle_lowerCaseAndMixedCaseNotSuccessful)
{
if(_dict && _dict->check)
{
if(AddWordToDictionary("Zxyz"))
{
CHECK( IsWordInDictionary("ZXYZ") );
CHECK(!IsWordInDictionary("ZXyz") );
CHECK( IsWordInDictionary("Zxyz") );
CHECK(!IsWordInDictionary("zxyz") );
CHECK(!IsWordInDictionary("zXyz") );
}
}
}
TEST_FIXTURE(DictionaryCheck_TestFixture,
IsWordInDictionary_Addedlower_MixedCaseNotSuccessful)
{
if(_dict && _dict->check)
{
if(AddWordToDictionary("zyxz"))
{
CHECK( IsWordInDictionary("ZYXZ") );
CHECK(!IsWordInDictionary("ZYxz") );
CHECK( IsWordInDictionary("Zyxz") );
CHECK( IsWordInDictionary("zyxz") );
CHECK(!IsWordInDictionary("zYxz") );
}
}
}