blob: 91dd7aa964c0e867be342cb90b5a4e2d8178cf7f [file] [log] [blame]
// Copyright 2010-2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "composer/composer.h"
#include <string>
#include <utility>
#include <vector>
#include "base/logging.h"
#include "base/singleton.h"
#include "base/system_util.h"
#include "base/util.h"
#include "composer/internal/typing_model.h"
#include "composer/table.h"
#include "config/character_form_manager.h"
#include "config/config.pb.h"
#include "config/config_handler.h"
#include "session/commands.pb.h"
#include "session/key_parser.h"
#include "testing/base/public/gunit.h"
DECLARE_string(test_tmpdir);
namespace mozc {
namespace composer {
using ::mozc::config::CharacterFormManager;
using ::mozc::config::Config;
using ::mozc::config::ConfigHandler;
using ::mozc::commands::Request;
namespace {
bool InsertKey(const string &key_string, Composer *composer) {
commands::KeyEvent key;
if (!KeyParser::ParseKey(key_string, &key)) {
return false;
}
return composer->InsertCharacterKeyEvent(key);
}
bool InsertKeyWithMode(const string &key_string,
const commands::CompositionMode mode,
Composer *composer) {
commands::KeyEvent key;
if (!KeyParser::ParseKey(key_string, &key)) {
return false;
}
key.set_mode(mode);
return composer->InsertCharacterKeyEvent(key);
}
string GetPreedit(const Composer *composer) {
string preedit;
composer->GetStringForPreedit(&preedit);
return preedit;
}
void ExpectSameComposer(const Composer &lhs, const Composer &rhs) {
EXPECT_EQ(lhs.GetCursor(), rhs.GetCursor());
EXPECT_EQ(lhs.is_new_input(), rhs.is_new_input());
EXPECT_EQ(lhs.GetInputMode(), rhs.GetInputMode());
EXPECT_EQ(lhs.GetOutputMode(), rhs.GetOutputMode());
EXPECT_EQ(lhs.GetComebackInputMode(), rhs.GetComebackInputMode());
EXPECT_EQ(lhs.shifted_sequence_count(), rhs.shifted_sequence_count());
EXPECT_EQ(lhs.source_text(), rhs.source_text());
EXPECT_EQ(lhs.max_length(), rhs.max_length());
EXPECT_EQ(lhs.GetInputFieldType(), rhs.GetInputFieldType());
{
string left_text, right_text;
lhs.GetStringForPreedit(&left_text);
rhs.GetStringForPreedit(&right_text);
EXPECT_EQ(left_text, right_text);
}
{
string left_text, right_text;
lhs.GetStringForSubmission(&left_text);
rhs.GetStringForSubmission(&right_text);
EXPECT_EQ(left_text, right_text);
}
{
string left_text, right_text;
lhs.GetQueryForConversion(&left_text);
rhs.GetQueryForConversion(&right_text);
EXPECT_EQ(left_text, right_text);
}
{
string left_text, right_text;
lhs.GetQueryForPrediction(&left_text);
rhs.GetQueryForPrediction(&right_text);
EXPECT_EQ(left_text, right_text);
}
}
} // namespace
class ComposerTest : public testing::Test {
protected:
ComposerTest() {}
virtual void SetUp() {
SystemUtil::SetUserProfileDirectory(FLAGS_test_tmpdir);
Config config;
ConfigHandler::GetDefaultConfig(&config);
ConfigHandler::SetConfig(config);
table_.reset(new Table);
default_request_.reset(new Request);
composer_.reset(new Composer(table_.get(), default_request_.get()));
CharacterFormManager::GetCharacterFormManager()->SetDefaultRule();
}
virtual void TearDown() {
CharacterFormManager::GetCharacterFormManager()->SetDefaultRule();
composer_.reset();
default_request_.reset();
table_.reset();
// just in case, reset config in test_tmpdir
Config config;
ConfigHandler::GetDefaultConfig(&config);
ConfigHandler::SetConfig(config);
}
scoped_ptr<Composer> composer_;
scoped_ptr<Table> table_;
scoped_ptr<Request> default_request_;
private:
DISALLOW_COPY_AND_ASSIGN(ComposerTest);
};
TEST_F(ComposerTest, Reset) {
composer_->InsertCharacter("mozuku");
composer_->SetInputMode(transliteration::HALF_ASCII);
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetOutputMode());
composer_->SetOutputMode(transliteration::HALF_ASCII);
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetOutputMode());
composer_->SetInputFieldType(commands::Context::PASSWORD);
composer_->Reset();
EXPECT_TRUE(composer_->Empty());
// The input mode ramains as the previous mode.
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
EXPECT_EQ(commands::Context::PASSWORD,
composer_->GetInputFieldType());
// The output mode should be reset.
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetOutputMode());
}
TEST_F(ComposerTest, ResetInputMode) {
composer_->InsertCharacter("mozuku");
composer_->SetInputMode(transliteration::FULL_KATAKANA);
composer_->SetTemporaryInputMode(transliteration::HALF_ASCII);
composer_->ResetInputMode();
EXPECT_FALSE(composer_->Empty());
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
}
TEST_F(ComposerTest, Empty) {
composer_->InsertCharacter("mozuku");
EXPECT_FALSE(composer_->Empty());
composer_->EditErase();
EXPECT_TRUE(composer_->Empty());
}
TEST_F(ComposerTest, EnableInsert) {
composer_->set_max_length(6);
composer_->InsertCharacter("mozuk");
EXPECT_EQ(5, composer_->GetLength());
EXPECT_TRUE(composer_->EnableInsert());
composer_->InsertCharacter("u");
EXPECT_EQ(6, composer_->GetLength());
EXPECT_FALSE(composer_->EnableInsert());
composer_->InsertCharacter("!");
EXPECT_EQ(6, composer_->GetLength());
string result;
composer_->GetQueryForConversion(&result);
EXPECT_EQ("mozuku", result);
composer_->Backspace();
EXPECT_EQ(5, composer_->GetLength());
EXPECT_TRUE(composer_->EnableInsert());
}
TEST_F(ComposerTest, BackSpace) {
composer_->InsertCharacter("abc");
composer_->Backspace();
EXPECT_EQ(2, composer_->GetLength());
EXPECT_EQ(2, composer_->GetCursor());
string result;
composer_->GetQueryForConversion(&result);
EXPECT_EQ("ab", result);
result.clear();
composer_->GetQueryForConversion(&result);
EXPECT_EQ("ab", result);
composer_->MoveCursorToBeginning();
EXPECT_EQ(0, composer_->GetCursor());
composer_->Backspace();
EXPECT_EQ(2, composer_->GetLength());
EXPECT_EQ(0, composer_->GetCursor());
result.clear();
composer_->GetQueryForConversion(&result);
EXPECT_EQ("ab", result);
composer_->Backspace();
EXPECT_EQ(2, composer_->GetLength());
EXPECT_EQ(0, composer_->GetCursor());
result.clear();
composer_->GetQueryForConversion(&result);
EXPECT_EQ("ab", result);
}
TEST_F(ComposerTest, OutputMode) {
// This behaviour is based on Kotoeri
// "あ"
table_->AddRule("a", "\xe3\x81\x82", "");
// "い"
table_->AddRule("i", "\xe3\x81\x84", "");
// "う"
table_->AddRule("u", "\xe3\x81\x86", "");
composer_->SetOutputMode(transliteration::HIRAGANA);
composer_->InsertCharacter("a");
composer_->InsertCharacter("i");
composer_->InsertCharacter("u");
string output;
composer_->GetStringForPreedit(&output);
// "あいう"
EXPECT_EQ("\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86", output);
composer_->SetOutputMode(transliteration::FULL_ASCII);
composer_->GetStringForPreedit(&output);
// "aiu"
EXPECT_EQ("\xEF\xBD\x81\xEF\xBD\x89\xEF\xBD\x95", output);
composer_->InsertCharacter("a");
composer_->InsertCharacter("i");
composer_->InsertCharacter("u");
composer_->GetStringForPreedit(&output);
// "aiuあいう"
EXPECT_EQ("\xEF\xBD\x81\xEF\xBD\x89\xEF\xBD\x95"
"\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86",
output);
}
TEST_F(ComposerTest, OutputMode_2) {
// This behaviour is based on Kotoeri
// "あ"
table_->AddRule("a", "\xe3\x81\x82", "");
// "い"
table_->AddRule("i", "\xe3\x81\x84", "");
// "う"
table_->AddRule("u", "\xe3\x81\x86", "");
composer_->InsertCharacter("a");
composer_->InsertCharacter("i");
composer_->InsertCharacter("u");
string output;
composer_->GetStringForPreedit(&output);
// "あいう"
EXPECT_EQ("\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86", output);
composer_->MoveCursorLeft();
composer_->SetOutputMode(transliteration::FULL_ASCII);
composer_->GetStringForPreedit(&output);
// "aiu"
EXPECT_EQ("\xEF\xBD\x81\xEF\xBD\x89\xEF\xBD\x95", output);
composer_->InsertCharacter("a");
composer_->InsertCharacter("i");
composer_->InsertCharacter("u");
composer_->GetStringForPreedit(&output);
// "aiuあいう"
EXPECT_EQ("\xEF\xBD\x81\xEF\xBD\x89\xEF\xBD\x95"
"\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86",
output);
}
TEST_F(ComposerTest, GetTransliterations) {
// "あ"
table_->AddRule("a", "\xe3\x81\x82", "");
// "い"
table_->AddRule("i", "\xe3\x81\x84", "");
// "う"
table_->AddRule("u", "\xe3\x81\x86", "");
// "あ"
table_->AddRule("A", "\xe3\x81\x82", "");
// "い"
table_->AddRule("I", "\xe3\x81\x84", "");
// "う"
table_->AddRule("U", "\xe3\x81\x86", "");
composer_->InsertCharacter("a");
transliteration::Transliterations transliterations;
composer_->GetTransliterations(&transliterations);
EXPECT_EQ(transliteration::NUM_T13N_TYPES, transliterations.size());
// "あ"
EXPECT_EQ("\xe3\x81\x82", transliterations[transliteration::HIRAGANA]);
// "ア"
EXPECT_EQ("\xe3\x82\xa2", transliterations[transliteration::FULL_KATAKANA]);
EXPECT_EQ("a", transliterations[transliteration::HALF_ASCII]);
// "a"
EXPECT_EQ("\xef\xbd\x81", transliterations[transliteration::FULL_ASCII]);
// "ア"
EXPECT_EQ("\xef\xbd\xb1", transliterations[transliteration::HALF_KATAKANA]);
composer_->Reset();
ASSERT_TRUE(composer_->Empty());
transliterations.clear();
composer_->InsertCharacter("!");
composer_->GetTransliterations(&transliterations);
EXPECT_EQ(transliteration::NUM_T13N_TYPES, transliterations.size());
// NOTE(komatsu): The duplication will be handled by the session layer.
// "!"
EXPECT_EQ("\xef\xbc\x81", transliterations[transliteration::HIRAGANA]);
// "!"
EXPECT_EQ("\xef\xbc\x81", transliterations[transliteration::FULL_KATAKANA]);
EXPECT_EQ("!", transliterations[transliteration::HALF_ASCII]);
// "!"
EXPECT_EQ("\xef\xbc\x81", transliterations[transliteration::FULL_ASCII]);
EXPECT_EQ("!", transliterations[transliteration::HALF_KATAKANA]);
composer_->Reset();
ASSERT_TRUE(composer_->Empty());
transliterations.clear();
composer_->InsertCharacter("aIu");
composer_->GetTransliterations(&transliterations);
EXPECT_EQ(transliteration::NUM_T13N_TYPES, transliterations.size());
// "あいう"
EXPECT_EQ("\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86",
transliterations[transliteration::HIRAGANA]);
// "アイウ"
EXPECT_EQ("\xe3\x82\xa2\xe3\x82\xa4\xe3\x82\xa6",
transliterations[transliteration::FULL_KATAKANA]);
EXPECT_EQ("aIu", transliterations[transliteration::HALF_ASCII]);
EXPECT_EQ("AIU", transliterations[transliteration::HALF_ASCII_UPPER]);
EXPECT_EQ("aiu", transliterations[transliteration::HALF_ASCII_LOWER]);
EXPECT_EQ("Aiu", transliterations[transliteration::HALF_ASCII_CAPITALIZED]);
// "aIu"
EXPECT_EQ("\xef\xbd\x81\xef\xbc\xa9\xef\xbd\x95",
transliterations[transliteration::FULL_ASCII]);
// "AIU"
EXPECT_EQ("\xef\xbc\xa1\xef\xbc\xa9\xef\xbc\xb5",
transliterations[transliteration::FULL_ASCII_UPPER]);
// "aiu"
EXPECT_EQ("\xef\xbd\x81\xef\xbd\x89\xef\xbd\x95",
transliterations[transliteration::FULL_ASCII_LOWER]);
// "Aiu"
EXPECT_EQ("\xef\xbc\xa1\xef\xbd\x89\xef\xbd\x95",
transliterations[transliteration::FULL_ASCII_CAPITALIZED]);
// "アイウ"
EXPECT_EQ("\xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3",
transliterations[transliteration::HALF_KATAKANA]);
// Transliterations for quote marks. This is a test against
// http://b/1581367
composer_->Reset();
ASSERT_TRUE(composer_->Empty());
transliterations.clear();
composer_->InsertCharacter("'\"`");
composer_->GetTransliterations(&transliterations);
// "'" -> \u2019
// """ -> \u201d
// "`" -> \uff40
EXPECT_EQ("'\"`", transliterations[transliteration::HALF_ASCII]);
// "’”`"
EXPECT_EQ("\xe2\x80\x99\xe2\x80\x9d\xef\xbd\x80",
transliterations[transliteration::FULL_ASCII]);
}
TEST_F(ComposerTest, GetSubTransliterations) {
// "か"
table_->AddRule("ka", "\xe3\x81\x8b", "");
// "ん"
table_->AddRule("n", "\xe3\x82\x93", "");
// "な"
table_->AddRule("na", "\xe3\x81\xaa", "");
// "だ"
table_->AddRule("da", "\xe3\x81\xa0", "");
composer_->InsertCharacter("kanna");
transliteration::Transliterations transliterations;
composer_->GetSubTransliterations(0, 2, &transliterations);
// "かん"
EXPECT_EQ("\xe3\x81\x8b\xe3\x82\x93",
transliterations[transliteration::HIRAGANA]);
// "カン"
EXPECT_EQ("\xe3\x82\xab\xe3\x83\xb3",
transliterations[transliteration::FULL_KATAKANA]);
EXPECT_EQ("kan", transliterations[transliteration::HALF_ASCII]);
// "kan"
EXPECT_EQ("\xef\xbd\x8b\xef\xbd\x81\xef\xbd\x8e",
transliterations[transliteration::FULL_ASCII]);
// "カン"
EXPECT_EQ("\xef\xbd\xb6\xef\xbe\x9d",
transliterations[transliteration::HALF_KATAKANA]);
transliterations.clear();
composer_->GetSubTransliterations(1, 1, &transliterations);
// "ん"
EXPECT_EQ("\xe3\x82\x93", transliterations[transliteration::HIRAGANA]);
// "ン"
EXPECT_EQ("\xe3\x83\xb3", transliterations[transliteration::FULL_KATAKANA]);
EXPECT_EQ("n", transliterations[transliteration::HALF_ASCII]);
// "n"
EXPECT_EQ("\xef\xbd\x8e", transliterations[transliteration::FULL_ASCII]);
// "ン"
EXPECT_EQ("\xef\xbe\x9d", transliterations[transliteration::HALF_KATAKANA]);
transliterations.clear();
composer_->GetSubTransliterations(2, 1, &transliterations);
// "な"
EXPECT_EQ("\xe3\x81\xaa", transliterations[transliteration::HIRAGANA]);
// "ナ"
EXPECT_EQ("\xe3\x83\x8a", transliterations[transliteration::FULL_KATAKANA]);
EXPECT_EQ("na", transliterations[transliteration::HALF_ASCII]);
// "na"
EXPECT_EQ("\xef\xbd\x8e\xef\xbd\x81",
transliterations[transliteration::FULL_ASCII]);
// "ナ"
EXPECT_EQ("\xef\xbe\x85", transliterations[transliteration::HALF_KATAKANA]);
// Invalid position
transliterations.clear();
composer_->GetSubTransliterations(5, 3, &transliterations);
EXPECT_EQ("", transliterations[transliteration::HIRAGANA]);
EXPECT_EQ("", transliterations[transliteration::FULL_KATAKANA]);
EXPECT_EQ("", transliterations[transliteration::HALF_ASCII]);
EXPECT_EQ("", transliterations[transliteration::FULL_ASCII]);
EXPECT_EQ("", transliterations[transliteration::HALF_KATAKANA]);
// Invalid size
transliterations.clear();
composer_->GetSubTransliterations(0, 999, &transliterations);
// "かんな"
EXPECT_EQ("\xe3\x81\x8b\xe3\x82\x93\xe3\x81\xaa",
transliterations[transliteration::HIRAGANA]);
// "カンナ"
EXPECT_EQ("\xe3\x82\xab\xe3\x83\xb3\xe3\x83\x8a",
transliterations[transliteration::FULL_KATAKANA]);
EXPECT_EQ("kanna", transliterations[transliteration::HALF_ASCII]);
// "kanna"
EXPECT_EQ("\xef\xbd\x8b\xef\xbd\x81\xef\xbd\x8e\xef\xbd\x8e\xef\xbd\x81",
transliterations[transliteration::FULL_ASCII]);
// "カンナ"
EXPECT_EQ("\xef\xbd\xb6\xef\xbe\x9d\xef\xbe\x85",
transliterations[transliteration::HALF_KATAKANA]);
// Dakuon case
transliterations.clear();
composer_->EditErase();
composer_->InsertCharacter("dankann");
composer_->GetSubTransliterations(0, 3, &transliterations);
// "だんか"
EXPECT_EQ("\xe3\x81\xa0\xe3\x82\x93\xe3\x81\x8b",
transliterations[transliteration::HIRAGANA]);
// "ダンカ"
EXPECT_EQ("\xe3\x83\x80\xe3\x83\xb3\xe3\x82\xab",
transliterations[transliteration::FULL_KATAKANA]);
EXPECT_EQ("danka", transliterations[transliteration::HALF_ASCII]);
// "danka"
EXPECT_EQ("\xef\xbd\x84\xef\xbd\x81\xef\xbd\x8e\xef\xbd\x8b\xef\xbd\x81",
transliterations[transliteration::FULL_ASCII]);
// "ダンカ"
EXPECT_EQ("\xef\xbe\x80\xef\xbe\x9e\xef\xbe\x9d\xef\xbd\xb6",
transliterations[transliteration::HALF_KATAKANA]);
}
TEST_F(ComposerTest, GetStringFunctions) {
// "か"
table_->AddRule("ka", "\xe3\x81\x8b", "");
// "ん"
table_->AddRule("n", "\xe3\x82\x93", "");
// "な"
table_->AddRule("na", "\xe3\x81\xaa", "");
// "さ"
table_->AddRule("sa", "\xe3\x81\x95", "");
// Query: "!kan"
composer_->InsertCharacter("!kan");
string preedit;
composer_->GetStringForPreedit(&preedit);
// "!かn"
EXPECT_EQ("\xef\xbc\x81\xe3\x81\x8b\xef\xbd\x8e", preedit);
string submission;
composer_->GetStringForSubmission(&submission);
// "!かn"
EXPECT_EQ("\xef\xbc\x81\xe3\x81\x8b\xef\xbd\x8e", submission);
string conversion;
composer_->GetQueryForConversion(&conversion);
// "!かん"
EXPECT_EQ("\x21\xe3\x81\x8b\xe3\x82\x93", conversion);
string prediction;
composer_->GetQueryForPrediction(&prediction);
// "!か"
EXPECT_EQ("\x21\xe3\x81\x8b", prediction);
// Query: "kas"
composer_->EditErase();
composer_->InsertCharacter("kas");
preedit.clear();
composer_->GetStringForPreedit(&preedit);
// "かs"
EXPECT_EQ("\xe3\x81\x8b\xef\xbd\x93", preedit);
submission.clear();
composer_->GetStringForSubmission(&submission);
// "かs"
EXPECT_EQ("\xe3\x81\x8b\xef\xbd\x93", submission);
// Pending chars should remain. This is a test against
// http://b/1799399
conversion.clear();
composer_->GetQueryForConversion(&conversion);
// "かs"
EXPECT_EQ("\xe3\x81\x8b\x73", conversion);
prediction.clear();
composer_->GetQueryForPrediction(&prediction);
// "か"
EXPECT_EQ("\xe3\x81\x8b", prediction);
// Query: "s"
composer_->EditErase();
composer_->InsertCharacter("s");
preedit.clear();
composer_->GetStringForPreedit(&preedit);
// "s"
EXPECT_EQ("\xef\xbd\x93", preedit);
submission.clear();
composer_->GetStringForSubmission(&submission);
// "s"
EXPECT_EQ("\xef\xbd\x93", submission);
conversion.clear();
composer_->GetQueryForConversion(&conversion);
// "s"
EXPECT_EQ("s", conversion);
prediction.clear();
composer_->GetQueryForPrediction(&prediction);
EXPECT_EQ("s", prediction);
// Query: "sk"
composer_->EditErase();
composer_->InsertCharacter("sk");
preedit.clear();
composer_->GetStringForPreedit(&preedit);
// "sk"
EXPECT_EQ("\xef\xbd\x93\xEF\xBD\x8B", preedit);
submission.clear();
composer_->GetStringForSubmission(&submission);
// "sk"
EXPECT_EQ("\xef\xbd\x93\xEF\xBD\x8B", submission);
conversion.clear();
composer_->GetQueryForConversion(&conversion);
// "sk"
EXPECT_EQ("sk", conversion);
prediction.clear();
composer_->GetQueryForPrediction(&prediction);
// "sk"
EXPECT_EQ("sk", prediction);
}
TEST_F(ComposerTest, GetQueryForPredictionHalfAscii) {
// Dummy setup of romanji table.
table_->AddRule("he", "\xe3\x81\xb8", ""); // "へ"
table_->AddRule("ll", "\xe3\x81\xa3\xef\xbd\x8c", ""); // "っl"
table_->AddRule("lo", "\xe3\x82\x8d", ""); // "ろ"
// Switch to Half-Latin input mode.
composer_->SetInputMode(transliteration::HALF_ASCII);
string prediction;
{
const char kInput[] = "hello";
composer_->InsertCharacter(kInput);
composer_->GetQueryForPrediction(&prediction);
EXPECT_EQ(kInput, prediction);
}
prediction.clear();
composer_->EditErase();
{
const char kInput[] = "hello!";
composer_->InsertCharacter(kInput);
composer_->GetQueryForPrediction(&prediction);
EXPECT_EQ(kInput, prediction);
}
}
TEST_F(ComposerTest, GetQueryForPredictionFullAscii) {
// Dummy setup of romanji table.
table_->AddRule("he", "\xe3\x81\xb8", ""); // "へ"
table_->AddRule("ll", "\xe3\x81\xa3\xef\xbd\x8c", ""); // "っl"
table_->AddRule("lo", "\xe3\x82\x8d", ""); // "ろ"
// Switch to Full-Latin input mode.
composer_->SetInputMode(transliteration::FULL_ASCII);
string prediction;
{
// "hello"
composer_->InsertCharacter(
"\xef\xbd\x88\xef\xbd\x85\xef\xbd\x8c\xef\xbd\x8c\xef\xbd\x8f");
composer_->GetQueryForPrediction(&prediction);
EXPECT_EQ("hello", prediction);
}
prediction.clear();
composer_->EditErase();
{
// "hello!"
composer_->InsertCharacter(
"\xef\xbd\x88\xef\xbd\x85\xef\xbd\x8c\xef\xbd\x8c"
"\xef\xbd\x8f\xef\xbc\x81");
composer_->GetQueryForPrediction(&prediction);
EXPECT_EQ("hello!", prediction);
}
}
TEST_F(ComposerTest, GetQueriesForPredictionRoman) {
// "う"
table_->AddRule("u", "\xe3\x81\x86", "");
// "っ"
table_->AddRule("ss", "\xe3\x81\xa3", "s");
// "さ"
table_->AddRule("sa", "\xe3\x81\x95", "");
// "し"
table_->AddRule("si", "\xe3\x81\x97", "");
// "す"
table_->AddRule("su", "\xe3\x81\x99", "");
// "せ"
table_->AddRule("se", "\xe3\x81\x9b", "");
// "そ"
table_->AddRule("so", "\xe3\x81\x9d", "");
{
string base, preedit;
set<string> expanded;
composer_->EditErase();
composer_->InsertCharacter("us");
composer_->GetQueriesForPrediction(&base, &expanded);
composer_->GetStringForPreedit(&preedit);
// "う"
EXPECT_EQ("\xe3\x81\x86", base);
EXPECT_EQ(7, expanded.size());
// We can't use EXPECT_NE for iterator
EXPECT_TRUE(expanded.end() != expanded.find("s"));
// "っ"
EXPECT_TRUE(expanded.end() != expanded.find("\xe3\x81\xa3"));
// "さ"
EXPECT_TRUE(expanded.end() != expanded.find("\xe3\x81\x95"));
// "し"
EXPECT_TRUE(expanded.end() != expanded.find("\xe3\x81\x97"));
// "す"
EXPECT_TRUE(expanded.end() != expanded.find("\xe3\x81\x99"));
// "せ"
EXPECT_TRUE(expanded.end() != expanded.find("\xe3\x81\x9b"));
// "そ"
EXPECT_TRUE(expanded.end() != expanded.find("\xe3\x81\x9d"));
}
}
TEST_F(ComposerTest, GetQueriesForPredictionMobile) {
// "い"
table_->AddRule("_", "", "\xe3\x81\x84");
// "い*", "ぃ"
table_->AddRule("\xe3\x81\x84\x2a", "", "\xe3\x81\x83");
// "ぃ*", "い"
table_->AddRule("\xe3\x81\x83\x2a", "", "\xe3\x81\x84");
// "と"
table_->AddRule("$", "", "\xe3\x81\xa8");
// "と*", "ど"
table_->AddRule("\xe3\x81\xa8\x2a", "", "\xe3\x81\xa9");
// "ど*", "と"
table_->AddRule("\xe3\x81\xa9\x2a", "", "\xe3\x81\xa8");
{
string base, preedit;
set<string> expanded;
composer_->EditErase();
composer_->InsertCharacter("_$");
composer_->GetQueriesForPrediction(&base, &expanded);
composer_->GetStringForPreedit(&preedit);
// "い"
EXPECT_EQ("\xe3\x81\x84", base);
EXPECT_EQ(2, expanded.size());
// "と"
EXPECT_TRUE(expanded.end() != expanded.find("\xe3\x81\xa8"));
// "ど"
EXPECT_TRUE(expanded.end() != expanded.find("\xe3\x81\xa9"));
}
}
TEST_F(ComposerTest, GetStringFunctions_ForN) {
table_->AddRule("a", "[A]", "");
table_->AddRule("n", "[N]", "");
table_->AddRule("nn", "[N]", "");
table_->AddRule("na", "[NA]", "");
table_->AddRule("nya", "[NYA]", "");
table_->AddRule("ya", "[YA]", "");
table_->AddRule("ka", "[KA]", "");
composer_->InsertCharacter("nynyan");
string preedit;
composer_->GetStringForPreedit(&preedit);
// "ny[NYA]n"
EXPECT_EQ("\xEF\xBD\x8E\xEF\xBD\x99\xEF\xBC\xBB\xEF\xBC\xAE\xEF\xBC\xB9"
"\xEF\xBC\xA1\xEF\xBC\xBD\xEF\xBD\x8E", preedit);
string submission;
composer_->GetStringForSubmission(&submission);
// "ny[NYA]n"
EXPECT_EQ("\xEF\xBD\x8E\xEF\xBD\x99\xEF\xBC\xBB\xEF\xBC\xAE\xEF\xBC\xB9"
"\xEF\xBC\xA1\xEF\xBC\xBD\xEF\xBD\x8E", submission);
string conversion;
composer_->GetQueryForConversion(&conversion);
EXPECT_EQ("ny[NYA][N]", conversion);
string prediction;
composer_->GetQueryForPrediction(&prediction);
EXPECT_EQ("ny[NYA]", prediction);
composer_->InsertCharacter("ka");
string conversion2;
composer_->GetQueryForConversion(&conversion2);
EXPECT_EQ("ny[NYA][N][KA]", conversion2);
string prediction2;
composer_->GetQueryForPrediction(&prediction2);
EXPECT_EQ("ny[NYA][N][KA]", prediction2);
}
TEST_F(ComposerTest, GetStringFunctions_InputFieldType) {
const struct TestData {
const commands::Context::InputFieldType field_type_;
const bool ascii_expected_;
} test_data_list[] = {
{commands::Context::NORMAL, false},
{commands::Context::NUMBER, true},
{commands::Context::PASSWORD, true},
{commands::Context::TEL, true},
};
composer_->SetInputMode(transliteration::HIRAGANA);
for (size_t test_data_index = 0;
test_data_index < arraysize(test_data_list);
++test_data_index) {
const TestData &test_data = test_data_list[test_data_index];
composer_->SetInputFieldType(test_data.field_type_);
string key, converted;
for (char c = 0x20; c <= 0x7E; ++c) {
key.assign(1, c);
composer_->EditErase();
composer_->InsertCharacter(key);
if (test_data.ascii_expected_) {
composer_->GetStringForPreedit(&converted);
EXPECT_EQ(key, converted);
composer_->GetStringForSubmission(&converted);
EXPECT_EQ(key, converted);
} else {
// Expected result is FULL_WIDTH form.
// Typically the result is a full-width form of the key,
// but some characters are not.
// So here we checks only the character form.
composer_->GetStringForPreedit(&converted);
EXPECT_EQ(Util::FULL_WIDTH, Util::GetFormType(converted));
composer_->GetStringForSubmission(&converted);
EXPECT_EQ(Util::FULL_WIDTH, Util::GetFormType(converted));
}
}
}
}
TEST_F(ComposerTest, InsertCommandCharacter) {
composer_->SetInputMode(transliteration::HALF_ASCII);
composer_->InsertCommandCharacter(Composer::REWIND);
EXPECT_EQ("\x0F<\x0E", GetPreedit(composer_.get()));
}
TEST_F(ComposerTest, InsertCharacterKeyEvent) {
commands::KeyEvent key;
// "あ"
table_->AddRule("a", "\xe3\x81\x82", "");
key.set_key_code('a');
composer_->InsertCharacterKeyEvent(key);
string preedit;
composer_->GetStringForPreedit(&preedit);
// "あ"
EXPECT_EQ("\xe3\x81\x82", preedit);
// Half width "A" will be inserted.
key.set_key_code('A');
composer_->InsertCharacterKeyEvent(key);
composer_->GetStringForPreedit(&preedit);
// "あA"
EXPECT_EQ("\xe3\x81\x82\x41", preedit);
// Half width "a" will be inserted.
key.set_key_code('a');
composer_->InsertCharacterKeyEvent(key);
composer_->GetStringForPreedit(&preedit);
// "あAa"
EXPECT_EQ("\xe3\x81\x82\x41\x61", preedit);
// Reset() should revert the previous input mode (Hiragana).
composer_->Reset();
key.set_key_code('a');
composer_->InsertCharacterKeyEvent(key);
composer_->GetStringForPreedit(&preedit);
// "あ"
EXPECT_EQ("\xE3\x81\x82", preedit);
// Typing "A" temporarily switch the input mode. The input mode
// should be reverted back after reset.
composer_->SetInputMode(transliteration::FULL_KATAKANA);
key.set_key_code('a');
composer_->InsertCharacterKeyEvent(key);
composer_->GetStringForPreedit(&preedit);
// "あア"
EXPECT_EQ("\xE3\x81\x82\xE3\x82\xA2", preedit);
key.set_key_code('A');
composer_->InsertCharacterKeyEvent(key);
composer_->GetStringForPreedit(&preedit);
// "あアA"
EXPECT_EQ("\xE3\x81\x82\xE3\x82\xA2\x41", preedit);
// Reset() should revert the previous input mode (Katakana).
composer_->Reset();
key.set_key_code('a');
composer_->InsertCharacterKeyEvent(key);
composer_->GetStringForPreedit(&preedit);
// "ア"
EXPECT_EQ("\xE3\x82\xA2", preedit);
}
namespace {
// "山"
const char kYama[] = "\xE5\xB1\xB1";
// "川"
const char kKawa[] = "\xE5\xB7\x9D";
// "空"
const char kSora[] = "\xE7\xA9\xBA";
} // namespace
TEST_F(ComposerTest, InsertCharacterKeyEventWithUcs4KeyCode) {
commands::KeyEvent key;
// Input "山" as key_code.
key.set_key_code(0x5C71); // U+5C71 = "山"
composer_->InsertCharacterKeyEvent(key);
string preedit;
composer_->GetStringForPreedit(&preedit);
EXPECT_EQ(kYama, preedit);
// Input "山" as key_code which is converted to "川".
table_->AddRule(kYama, kKawa, "");
composer_->Reset();
composer_->InsertCharacterKeyEvent(key);
composer_->GetStringForPreedit(&preedit);
EXPECT_EQ(kKawa, preedit);
// Input ("山", "空") as (key_code, key_string) which is treated as "空".
key.set_key_string(kSora);
composer_->Reset();
composer_->InsertCharacterKeyEvent(key);
composer_->GetStringForPreedit(&preedit);
EXPECT_EQ(kSora, preedit);
}
TEST_F(ComposerTest, InsertCharacterKeyEventWithoutKeyCode) {
commands::KeyEvent key;
// Input "山" as key_string. key_code is empty.
key.set_key_string(kYama);
composer_->InsertCharacterKeyEvent(key);
EXPECT_FALSE(key.has_key_code());
string preedit;
composer_->GetStringForPreedit(&preedit);
EXPECT_EQ(kYama, preedit);
transliteration::Transliterations transliterations;
composer_->GetTransliterations(&transliterations);
EXPECT_EQ(kYama, transliterations[transliteration::HIRAGANA]);
EXPECT_EQ(kYama, transliterations[transliteration::HALF_ASCII]);
}
TEST_F(ComposerTest, InsertCharacterKeyEventWithAsIs) {
commands::KeyEvent key;
// "あ"
table_->AddRule("a", "\xe3\x81\x82", "");
// "ー"
table_->AddRule("-", "\xE3\x83\xBC", "");
key.set_key_code('a');
composer_->InsertCharacterKeyEvent(key);
string preedit;
composer_->GetStringForPreedit(&preedit);
// "あ"
EXPECT_EQ("\xe3\x81\x82", preedit);
// Full width "0" will be inserted.
key.set_key_code('0');
key.set_key_string("0");
composer_->InsertCharacterKeyEvent(key);
composer_->GetStringForPreedit(&preedit);
// "あ0"
EXPECT_EQ("\xE3\x81\x82\xEF\xBC\x90", preedit);
// Half width "0" will be inserted.
key.set_key_code('0');
key.set_key_string("0");
key.set_input_style(commands::KeyEvent::AS_IS);
composer_->InsertCharacterKeyEvent(key);
composer_->GetStringForPreedit(&preedit);
// "あ00"
EXPECT_EQ("\xE3\x81\x82\xEF\xBC\x90\x30", preedit);
// Full width "0" will be inserted.
key.set_key_code('0');
key.set_key_string("0");
key.set_input_style(commands::KeyEvent::FOLLOW_MODE);
composer_->InsertCharacterKeyEvent(key);
composer_->GetStringForPreedit(&preedit);
// "あ000"
EXPECT_EQ("\xE3\x81\x82\xEF\xBC\x90\x30\xEF\xBC\x90", preedit);
// Half width "-" will be inserted.
key.set_key_code('-');
key.set_key_string("-");
key.set_input_style(commands::KeyEvent::AS_IS);
composer_->InsertCharacterKeyEvent(key);
composer_->GetStringForPreedit(&preedit);
// "あ000-"
EXPECT_EQ("\xE3\x81\x82\xEF\xBC\x90\x30\xEF\xBC\x90\x2D", preedit);
// Full width "−" will be inserted.
key.set_key_code('-');
// "−"
key.set_key_string("\xE2\x88\x92");
key.set_input_style(commands::KeyEvent::FOLLOW_MODE);
composer_->InsertCharacterKeyEvent(key);
composer_->GetStringForPreedit(&preedit);
// "あ000-−"
EXPECT_EQ("\xE3\x81\x82\xEF\xBC\x90\x30\xEF\xBC\x90\x2D\xE2\x88\x92",
preedit);
}
TEST_F(ComposerTest, InsertCharacterKeyEventWithInputMode) {
// "あ"
table_->AddRule("a", "\xE3\x81\x82", "");
// "い"
table_->AddRule("i", "\xE3\x81\x84", "");
// "う"
table_->AddRule("u", "\xE3\x81\x86", "");
{
// "a" → "あ" (Hiragana)
EXPECT_TRUE(InsertKeyWithMode("a", commands::HIRAGANA, composer_.get()));
// "あ"
EXPECT_EQ("\xE3\x81\x82", GetPreedit(composer_.get()));
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
// "aI" → "あI" (Alphanumeric)
EXPECT_TRUE(InsertKeyWithMode("I", commands::HIRAGANA, composer_.get()));
// "あI"
EXPECT_EQ("\xE3\x81\x82\x49", GetPreedit(composer_.get()));
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
// "u" → "あIu" (Alphanumeric)
EXPECT_TRUE(InsertKeyWithMode("u", commands::HALF_ASCII, composer_.get()));
// "あIu"
EXPECT_EQ("\xE3\x81\x82\x49\x75", GetPreedit(composer_.get()));
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
// [shift] → "あIu" (Hiragana)
EXPECT_TRUE(InsertKeyWithMode("Shift", commands::HALF_ASCII,
composer_.get()));
// "あIu"
EXPECT_EQ("\xE3\x81\x82\x49\x75", GetPreedit(composer_.get()));
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
// "u" → "あIuう" (Hiragana)
EXPECT_TRUE(InsertKeyWithMode("u", commands::HIRAGANA, composer_.get()));
// "あIuう"
EXPECT_EQ("\xE3\x81\x82\x49\x75\xE3\x81\x86", GetPreedit(composer_.get()));
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
}
composer_.reset(new Composer(table_.get(), default_request_.get()));
{
// "a" → "あ" (Hiragana)
EXPECT_TRUE(InsertKeyWithMode("a", commands::HIRAGANA, composer_.get()));
// "あ"
EXPECT_EQ("\xE3\x81\x82", GetPreedit(composer_.get()));
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
// "i" (Katakana) → "あイ" (Katakana)
EXPECT_TRUE(InsertKeyWithMode("i", commands::FULL_KATAKANA,
composer_.get()));
// "あイ"
EXPECT_EQ("\xE3\x81\x82\xE3\x82\xA4", GetPreedit(composer_.get()));
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// SetInputMode(Alphanumeric) → "あイ" (Alphanumeric)
composer_->SetInputMode(transliteration::HALF_ASCII);
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
// [shift] → "あイ" (Alphanumeric) - Nothing happens.
EXPECT_TRUE(InsertKeyWithMode("Shift", commands::HALF_ASCII,
composer_.get()));
// "あイ"
EXPECT_EQ("\xE3\x81\x82\xE3\x82\xA4", GetPreedit(composer_.get()));
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
// "U" → "あイ" (Alphanumeric)
EXPECT_TRUE(InsertKeyWithMode("U", commands::HALF_ASCII,
composer_.get()));
// "あイU"
EXPECT_EQ("\xE3\x81\x82\xE3\x82\xA4\x55", GetPreedit(composer_.get()));
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
// [shift] → "あイU" (Alphanumeric) - Nothing happens.
EXPECT_TRUE(InsertKeyWithMode("Shift", commands::HALF_ASCII,
composer_.get()));
// "あイU"
EXPECT_EQ("\xE3\x81\x82\xE3\x82\xA4\x55", GetPreedit(composer_.get()));
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
}
}
TEST_F(ComposerTest, ApplyTemporaryInputMode) {
const bool kCapsLocked = true;
const bool kCapsUnlocked = false;
// "あ"
table_->AddRule("a", "\xE3\x81\x82", "");
composer_->SetInputMode(transliteration::HIRAGANA);
// Since handlings of continuous shifted input differ,
// test cases differ between ASCII_INPUT_MODE and KATAKANA_INPUT_MODE
{ // ASCII_INPUT_MODE (w/o CapsLock)
Config config;
ConfigHandler::GetConfig(&config);
config.set_shift_key_mode_switch(Config::ASCII_INPUT_MODE);
ConfigHandler::SetConfig(config);
// pair<input, use_temporary_input_mode>
pair<string, bool> kTestDataAscii[] = {
make_pair("a", false),
make_pair("A", true),
make_pair("a", true),
make_pair("a", true),
make_pair("A", true),
make_pair("A", true),
make_pair("a", false),
make_pair("A", true),
make_pair("A", true),
make_pair("A", true),
make_pair("a", false),
make_pair("A", true),
make_pair(".", true),
make_pair("a", true),
make_pair("A", true),
make_pair("A", true),
make_pair(".", true),
make_pair("a", true),
// "あ"
make_pair("\xE3\x81\x82", false),
make_pair("a", false),
};
for (int i = 0; i < arraysize(kTestDataAscii); ++i) {
composer_->ApplyTemporaryInputMode(kTestDataAscii[i].first,
kCapsUnlocked);
const transliteration::TransliterationType expected =
kTestDataAscii[i].second
? transliteration::HALF_ASCII
: transliteration::HIRAGANA;
EXPECT_EQ(expected, composer_->GetInputMode()) << "index=" << i;
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetComebackInputMode())
<< "index=" << i;
}
}
{ // ASCII_INPUT_MODE (w/ CapsLock)
Config config;
ConfigHandler::GetConfig(&config);
config.set_shift_key_mode_switch(Config::ASCII_INPUT_MODE);
ConfigHandler::SetConfig(config);
// pair<input, use_temporary_input_mode>
pair<string, bool> kTestDataAscii[] = {
make_pair("A", false),
make_pair("a", true),
make_pair("A", true),
make_pair("A", true),
make_pair("a", true),
make_pair("a", true),
make_pair("A", false),
make_pair("a", true),
make_pair("a", true),
make_pair("a", true),
make_pair("A", false),
make_pair("a", true),
make_pair(".", true),
make_pair("A", true),
make_pair("a", true),
make_pair("a", true),
make_pair(".", true),
make_pair("A", true),
// "あ"
make_pair("\xE3\x81\x82", false),
make_pair("A", false),
};
for (int i = 0; i < arraysize(kTestDataAscii); ++i) {
composer_->ApplyTemporaryInputMode(kTestDataAscii[i].first,
kCapsLocked);
const transliteration::TransliterationType expected =
kTestDataAscii[i].second
? transliteration::HALF_ASCII
: transliteration::HIRAGANA;
EXPECT_EQ(expected, composer_->GetInputMode()) << "index=" << i;
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetComebackInputMode())
<< "index=" << i;
}
}
{ // KATAKANA_INPUT_MODE (w/o CapsLock)
Config config;
ConfigHandler::GetConfig(&config);
config.set_shift_key_mode_switch(Config::KATAKANA_INPUT_MODE);
ConfigHandler::SetConfig(config);
// pair<input, use_temporary_input_mode>
pair<string, bool> kTestDataKatakana[] = {
make_pair("a", false),
make_pair("A", true),
make_pair("a", false),
make_pair("a", false),
make_pair("A", true),
make_pair("A", true),
make_pair("a", false),
make_pair("A", true),
make_pair("A", true),
make_pair("A", true),
make_pair("a", false),
make_pair("A", true),
make_pair(".", true),
make_pair("a", false),
make_pair("A", true),
make_pair("A", true),
make_pair(".", true),
make_pair("a", false),
// "あ"
make_pair("\xE3\x81\x82", false),
make_pair("a", false),
};
for (int i = 0; i < arraysize(kTestDataKatakana); ++i) {
composer_->ApplyTemporaryInputMode(kTestDataKatakana[i].first,
kCapsUnlocked);
const transliteration::TransliterationType expected =
kTestDataKatakana[i].second
? transliteration::FULL_KATAKANA
: transliteration::HIRAGANA;
EXPECT_EQ(expected, composer_->GetInputMode()) << "index=" << i;
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetComebackInputMode())
<< "index=" << i;
}
}
{ // KATAKANA_INPUT_MODE (w/ CapsLock)
Config config;
ConfigHandler::GetConfig(&config);
config.set_shift_key_mode_switch(Config::KATAKANA_INPUT_MODE);
ConfigHandler::SetConfig(config);
// pair<input, use_temporary_input_mode>
pair<string, bool> kTestDataKatakana[] = {
make_pair("A", false),
make_pair("a", true),
make_pair("A", false),
make_pair("A", false),
make_pair("a", true),
make_pair("a", true),
make_pair("A", false),
make_pair("a", true),
make_pair("a", true),
make_pair("a", true),
make_pair("A", false),
make_pair("a", true),
make_pair(".", true),
make_pair("A", false),
make_pair("a", true),
make_pair("a", true),
make_pair(".", true),
make_pair("A", false),
// "あ"
make_pair("\xE3\x81\x82", false),
make_pair("A", false),
};
for (int i = 0; i < arraysize(kTestDataKatakana); ++i) {
composer_->ApplyTemporaryInputMode(kTestDataKatakana[i].first,
kCapsLocked);
const transliteration::TransliterationType expected =
kTestDataKatakana[i].second
? transliteration::FULL_KATAKANA
: transliteration::HIRAGANA;
EXPECT_EQ(expected, composer_->GetInputMode()) << "index=" << i;
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetComebackInputMode())
<< "index=" << i;
}
}
}
TEST_F(ComposerTest, CopyFrom) {
// "あ"
table_->AddRule("a", "\xE3\x81\x82", "");
// "ん"
table_->AddRule("n", "\xE3\x82\x93", "");
// "な"
table_->AddRule("na", "\xE3\x81\xAA", "");
{
SCOPED_TRACE("Precomposition");
string src_composition;
composer_->GetStringForSubmission(&src_composition);
EXPECT_EQ("", src_composition);
Composer dest(NULL, default_request_.get());
dest.CopyFrom(*composer_);
ExpectSameComposer(*composer_, dest);
}
{
SCOPED_TRACE("Composition");
composer_->InsertCharacter("a");
composer_->InsertCharacter("n");
string src_composition;
composer_->GetStringForSubmission(&src_composition);
// "あn"
EXPECT_EQ("\xE3\x81\x82\xEF\xBD\x8E", src_composition);
Composer dest(NULL, default_request_.get());
dest.CopyFrom(*composer_);
ExpectSameComposer(*composer_, dest);
}
{
SCOPED_TRACE("Conversion");
string src_composition;
composer_->GetQueryForConversion(&src_composition);
// "あん"
EXPECT_EQ("\xE3\x81\x82\xE3\x82\x93", src_composition);
Composer dest(NULL, default_request_.get());
dest.CopyFrom(*composer_);
ExpectSameComposer(*composer_, dest);
}
{
SCOPED_TRACE("Composition with temporary input mode");
composer_->Reset();
InsertKey("A", composer_.get());
InsertKey("a", composer_.get());
InsertKey("A", composer_.get());
InsertKey("A", composer_.get());
InsertKey("a", composer_.get());
string src_composition;
composer_->GetStringForSubmission(&src_composition);
// "AaAAあ"
EXPECT_EQ("AaAA\xE3\x81\x82", src_composition);
Composer dest(NULL, default_request_.get());
dest.CopyFrom(*composer_);
ExpectSameComposer(*composer_, dest);
}
{
SCOPED_TRACE("Composition with password mode");
composer_->Reset();
composer_->SetInputFieldType(commands::Context::PASSWORD);
composer_->SetInputMode(transliteration::HALF_ASCII);
composer_->SetOutputMode(transliteration::HALF_ASCII);
composer_->InsertCharacter("M");
string src_composition;
composer_->GetStringForSubmission(&src_composition);
EXPECT_EQ("M", src_composition);
Composer dest(NULL, default_request_.get());
dest.CopyFrom(*composer_);
ExpectSameComposer(*composer_, dest);
}
}
TEST_F(ComposerTest, ShiftKeyOperation) {
commands::KeyEvent key;
// "あ"
table_->AddRule("a", "\xe3\x81\x82", "");
{ // Basic feature.
composer_->Reset();
InsertKey("a", composer_.get()); // "あ"
InsertKey("A", composer_.get()); // "あA"
InsertKey("a", composer_.get()); // "あAa"
// Shift reverts the input mode to Hiragana.
InsertKey("Shift", composer_.get());
InsertKey("a", composer_.get()); // "あAaあ"
// Shift does nothing because the input mode has already been reverted.
InsertKey("Shift", composer_.get());
InsertKey("a", composer_.get()); // "あAaああ"
string preedit;
composer_->GetStringForPreedit(&preedit);
// "あAaああ"
EXPECT_EQ("\xE3\x81\x82\x41\x61\xE3\x81\x82\xE3\x81\x82", preedit);
}
{ // Revert back to the previous input mode.
composer_->SetInputMode(transliteration::FULL_KATAKANA);
composer_->Reset();
InsertKey("a", composer_.get()); // "ア"
InsertKey("A", composer_.get()); // "アA"
InsertKey("a", composer_.get()); // "アAa"
// Shift reverts the input mode to Hiragana.
InsertKey("Shift", composer_.get());
InsertKey("a", composer_.get()); // "アAaア"
// Shift does nothing because the input mode has already been reverted.
InsertKey("Shift", composer_.get());
InsertKey("a", composer_.get()); // "アAaアア"
string preedit;
composer_->GetStringForPreedit(&preedit);
// "アAaアア"
EXPECT_EQ("\xE3\x82\xA2\x41\x61\xE3\x82\xA2\xE3\x82\xA2", preedit);
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
}
{ // Multiple shifted characters
composer_->SetInputMode(transliteration::HIRAGANA);
composer_->Reset();
// Sequential shfited keys change the behavior of the next
// non-shifted key. "AAaa" Should become "AAああ", "Aaa" should
// become "Aaa".
InsertKey("A", composer_.get()); // "A"
InsertKey("A", composer_.get()); // "AA"
InsertKey("a", composer_.get()); // "AAあ"
InsertKey("A", composer_.get()); // "AAあA"
InsertKey("a", composer_.get()); // "AAあAa"
string preedit;
composer_->GetStringForPreedit(&preedit);
// "AAあAa"
EXPECT_EQ("\x41\x41\xE3\x81\x82\x41\x61", preedit);
}
{ // Multiple shifted characters #2
composer_->SetInputMode(transliteration::HIRAGANA);
composer_->Reset();
InsertKey("D", composer_.get()); // "D"
InsertKey("&", composer_.get()); // "D&"
InsertKey("D", composer_.get()); // "D&D"
InsertKey("2", composer_.get()); // "D&D2"
InsertKey("a", composer_.get()); // "D&D2a"
string preedit;
composer_->GetStringForPreedit(&preedit);
// "D&D2a"
EXPECT_EQ("\x44\x26\x44\x32\x61", preedit);
}
{ // Full-witdh alphanumeric
composer_->SetInputMode(transliteration::FULL_ASCII);
composer_->Reset();
InsertKey("A", composer_.get()); // "A"
InsertKey("a", composer_.get()); // "Aa"
string preedit;
composer_->GetStringForPreedit(&preedit);
// "Aa"
EXPECT_EQ("\xEF\xBC\xA1\xEF\xBD\x81", preedit);
}
{ // Half-witdh alphanumeric
composer_->SetInputMode(transliteration::HALF_ASCII);
composer_->Reset();
InsertKey("A", composer_.get()); // "A"
InsertKey("a", composer_.get()); // "Aa"
string preedit;
composer_->GetStringForPreedit(&preedit);
EXPECT_EQ("Aa", preedit);
}
}
TEST_F(ComposerTest, ShiftKeyOperationForKatakana) {
Config config;
ConfigHandler::GetConfig(&config);
config.set_shift_key_mode_switch(Config::KATAKANA_INPUT_MODE);
ConfigHandler::SetConfig(config);
table_->InitializeWithRequestAndConfig(*default_request_, config);
composer_->Reset();
composer_->SetInputMode(transliteration::HIRAGANA);
InsertKey("K", composer_.get());
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
InsertKey("A", composer_.get());
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
InsertKey("T", composer_.get());
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
InsertKey("a", composer_.get());
// See the below comment.
// EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
InsertKey("k", composer_.get());
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
InsertKey("A", composer_.get());
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
InsertKey("n", composer_.get());
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
InsertKey("a", composer_.get());
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
string preedit;
composer_->GetStringForPreedit(&preedit);
// NOTE(komatsu): "KATakAna" is converted to "カTあkアな" rather
// than "カタカな". This is a different behavior from Kotoeri due
// to avoid complecated implementation. Unless this is a problem
// for users, this difference probably remains.
//
// "カタカな"
// EXPECT_EQ("\xE3\x82\xAB\xE3\x82\xBF\xE3\x82\xAB\xE3\x81\xAA", preedit);
// "カTあkアな"
EXPECT_EQ("\xE3\x82\xAB\xEF\xBC\xB4\xE3\x81\x82"
"\xEF\xBD\x8B\xE3\x82\xA2\xE3\x81\xAA",
preedit);
config.set_shift_key_mode_switch(Config::ASCII_INPUT_MODE);
ConfigHandler::SetConfig(config);
}
TEST_F(ComposerTest, AutoIMETurnOffEnabled) {
Config config;
ConfigHandler::GetConfig(&config);
config.set_preedit_method(Config::ROMAN);
config.set_use_auto_ime_turn_off(true);
ConfigHandler::SetConfig(config);
table_->InitializeWithRequestAndConfig(*default_request_, config);
commands::KeyEvent key;
{ // http
InsertKey("h", composer_.get());
InsertKey("t", composer_.get());
InsertKey("t", composer_.get());
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
InsertKey("p", composer_.get());
string preedit;
composer_->GetStringForPreedit(&preedit);
EXPECT_EQ("http", preedit);
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
composer_->Reset();
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
}
composer_.reset(new Composer(table_.get(), default_request_.get()));
{ // google
InsertKey("g", composer_.get());
InsertKey("o", composer_.get());
InsertKey("o", composer_.get());
InsertKey("g", composer_.get());
InsertKey("l", composer_.get());
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
InsertKey("e", composer_.get());
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
EXPECT_EQ("google", GetPreedit(composer_.get()));
InsertKey("a", composer_.get());
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
// "googleあ"
EXPECT_EQ("google\xE3\x81\x82", GetPreedit(composer_.get()));
composer_->Reset();
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
}
{ // google in full-width alphanumeric mode.
composer_->SetInputMode(transliteration::FULL_ASCII);
InsertKey("g", composer_.get());
InsertKey("o", composer_.get());
InsertKey("o", composer_.get());
InsertKey("g", composer_.get());
InsertKey("l", composer_.get());
EXPECT_EQ(transliteration::FULL_ASCII, composer_->GetInputMode());
InsertKey("e", composer_.get());
EXPECT_EQ(transliteration::FULL_ASCII, composer_->GetInputMode());
// "google"
EXPECT_EQ("\xEF\xBD\x87\xEF\xBD\x8F\xEF\xBD\x8F"
"\xEF\xBD\x87\xEF\xBD\x8C\xEF\xBD\x85",
GetPreedit(composer_.get()));
InsertKey("a", composer_.get());
EXPECT_EQ(transliteration::FULL_ASCII, composer_->GetInputMode());
// "googlea"
EXPECT_EQ("\xEF\xBD\x87\xEF\xBD\x8F\xEF\xBD\x8F"
"\xEF\xBD\x87\xEF\xBD\x8C\xEF\xBD\x85\xEF\xBD\x81",
GetPreedit(composer_.get()));
composer_->Reset();
EXPECT_EQ(transliteration::FULL_ASCII, composer_->GetInputMode());
// Reset to Hiragana mode
composer_->SetInputMode(transliteration::HIRAGANA);
}
{ // Google
InsertKey("G", composer_.get());
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
InsertKey("o", composer_.get());
InsertKey("o", composer_.get());
InsertKey("g", composer_.get());
InsertKey("l", composer_.get());
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
InsertKey("e", composer_.get());
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
EXPECT_EQ("Google", GetPreedit(composer_.get()));
InsertKey("a", composer_.get());
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
EXPECT_EQ("Googlea", GetPreedit(composer_.get()));
composer_->Reset();
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
}
config.set_shift_key_mode_switch(Config::OFF);
ConfigHandler::SetConfig(config);
composer_.reset(new Composer(table_.get(), default_request_.get()));
{ // Google
InsertKey("G", composer_.get());
InsertKey("o", composer_.get());
InsertKey("o", composer_.get());
InsertKey("g", composer_.get());
InsertKey("l", composer_.get());
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
InsertKey("e", composer_.get());
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
EXPECT_EQ("Google", GetPreedit(composer_.get()));
InsertKey("a", composer_.get());
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
// "Googleあ"
EXPECT_EQ("Google\xE3\x81\x82", GetPreedit(composer_.get()));
composer_->Reset();
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
}
}
TEST_F(ComposerTest, AutoIMETurnOffDisabled) {
Config config;
ConfigHandler::GetConfig(&config);
config.set_preedit_method(Config::ROMAN);
config.set_use_auto_ime_turn_off(false);
ConfigHandler::SetConfig(config);
table_->InitializeWithRequestAndConfig(*default_request_, config);
commands::KeyEvent key;
// Roman
key.set_key_code('h');
composer_->InsertCharacterKeyEvent(key);
key.set_key_code('t');
composer_->InsertCharacterKeyEvent(key);
key.set_key_code('t');
composer_->InsertCharacterKeyEvent(key);
key.set_key_code('p');
composer_->InsertCharacterKeyEvent(key);
key.set_key_code(':');
composer_->InsertCharacterKeyEvent(key);
key.set_key_code('/');
composer_->InsertCharacterKeyEvent(key);
key.set_key_code('/');
composer_->InsertCharacterKeyEvent(key);
string preedit;
composer_->GetStringForPreedit(&preedit);
// "hっtp:・・"
EXPECT_EQ("\xEF\xBD\x88\xE3\x81\xA3\xEF\xBD\x94"
"\xEF\xBD\x90\xEF\xBC\x9A\xE3\x83\xBB\xE3\x83\xBB", preedit);
}
TEST_F(ComposerTest, AutoIMETurnOffKana) {
Config config;
ConfigHandler::GetConfig(&config);
config.set_preedit_method(Config::KANA);
config.set_use_auto_ime_turn_off(true);
ConfigHandler::SetConfig(config);
table_->InitializeWithRequestAndConfig(*default_request_, config);
commands::KeyEvent key;
// Kana
key.set_key_code('h');
composer_->InsertCharacterKeyEvent(key);
key.set_key_code('t');
composer_->InsertCharacterKeyEvent(key);
key.set_key_code('t');
composer_->InsertCharacterKeyEvent(key);
key.set_key_code('p');
composer_->InsertCharacterKeyEvent(key);
key.set_key_code(':');
composer_->InsertCharacterKeyEvent(key);
key.set_key_code('/');
composer_->InsertCharacterKeyEvent(key);
key.set_key_code('/');
composer_->InsertCharacterKeyEvent(key);
string preedit;
composer_->GetStringForPreedit(&preedit);
// "hっtp:・・"
EXPECT_EQ("\xEF\xBD\x88\xE3\x81\xA3\xEF\xBD\x94\xEF\xBD\x90\xEF\xBC\x9A"
"\xE3\x83\xBB\xE3\x83\xBB", preedit);
}
TEST_F(ComposerTest, KanaPrediction) {
// "か゛", "か"
// table_->AddRule("\xE3\x81\x8B", "\xE3\x81\x8B", "");
// "か゛", "が"
// table_->AddRule("\xE3\x81\x8B\xE3\x82\x9B", "\xE3\x81\x8C", "");
// "ー", "ー"
// table_->AddRule("\xE3\x83\xBC", "\xE3\x83\xBC", "");
// "か"
composer_->InsertCharacterKeyAndPreedit("t", "\xE3\x81\x8B");
{
string preedit;
composer_->GetQueryForPrediction(&preedit);
// "か"
EXPECT_EQ("\xE3\x81\x8B", preedit);
}
// "ー"
composer_->InsertCharacterKeyAndPreedit("\\", "\xE3\x83\xBC");
{
string preedit;
composer_->GetQueryForPrediction(&preedit);
// "かー"
EXPECT_EQ("\xE3\x81\x8B\xE3\x83\xBC", preedit);
}
// "、"
composer_->InsertCharacterKeyAndPreedit(",", "\xE3\x80\x81");
{
string preedit;
composer_->GetQueryForPrediction(&preedit);
// "かー、"
EXPECT_EQ("\xE3\x81\x8B\xE3\x83\xBC\xE3\x80\x81", preedit);
}
}
TEST_F(ComposerTest, KanaTransliteration) {
// "く゛", "ぐ"
table_->AddRule("\xE3\x81\x8F\xE3\x82\x9B", "\xE3\x81\x90", "");
// "く"
composer_->InsertCharacterKeyAndPreedit("h", "\xE3\x81\x8F");
// "い"
composer_->InsertCharacterKeyAndPreedit("e", "\xE3\x81\x84");
// "り"
composer_->InsertCharacterKeyAndPreedit("l", "\xE3\x82\x8A");
// "り"
composer_->InsertCharacterKeyAndPreedit("l", "\xE3\x82\x8A");
// "ら"
composer_->InsertCharacterKeyAndPreedit("o", "\xE3\x82\x89");
string preedit;
composer_->GetStringForPreedit(&preedit);
// "くいりりら"
EXPECT_EQ("\xE3\x81\x8F\xE3\x81\x84\xE3\x82\x8A\xE3\x82\x8A\xE3\x82\x89",
preedit);
transliteration::Transliterations transliterations;
composer_->GetTransliterations(&transliterations);
EXPECT_EQ(transliteration::NUM_T13N_TYPES, transliterations.size());
EXPECT_EQ("hello", transliterations[transliteration::HALF_ASCII]);
}
TEST_F(ComposerTest, SetOutputMode) {
// "も"
table_->AddRule("mo", "\xE3\x82\x82", "");
// "ず"
table_->AddRule("zu", "\xE3\x81\x9A", "");
composer_->InsertCharacter("m");
composer_->InsertCharacter("o");
composer_->InsertCharacter("z");
composer_->InsertCharacter("u");
string output;
composer_->GetStringForPreedit(&output);
// "もず"
EXPECT_EQ("\xE3\x82\x82\xE3\x81\x9A", output);
EXPECT_EQ(2, composer_->GetCursor());
composer_->SetOutputMode(transliteration::HALF_ASCII);
composer_->GetStringForPreedit(&output);
EXPECT_EQ("mozu", output);
EXPECT_EQ(4, composer_->GetCursor());
composer_->SetOutputMode(transliteration::HALF_KATAKANA);
composer_->GetStringForPreedit(&output);
// "モズ"
EXPECT_EQ("\xEF\xBE\x93\xEF\xBD\xBD\xEF\xBE\x9E", output);
EXPECT_EQ(3, composer_->GetCursor());
}
TEST_F(ComposerTest, UpdateInputMode) {
// "あ"
table_->AddRule("a", "\xE3\x81\x82", "");
// "い"
table_->AddRule("i", "\xE3\x81\x84", "");
InsertKey("A", composer_.get());
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
InsertKey("I", composer_.get());
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
InsertKey("a", composer_.get());
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
InsertKey("i", composer_.get());
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
composer_->SetInputMode(transliteration::FULL_ASCII);
InsertKey("a", composer_.get());
EXPECT_EQ(transliteration::FULL_ASCII, composer_->GetInputMode());
InsertKey("i", composer_.get());
EXPECT_EQ(transliteration::FULL_ASCII, composer_->GetInputMode());
string output;
composer_->GetStringForPreedit(&output);
// "AIあいai"
EXPECT_EQ("\x41\x49\xE3\x81\x82\xE3\x81\x84\xEF\xBD\x81\xEF\xBD\x89",
output);
composer_->SetInputMode(transliteration::FULL_KATAKANA);
// "|AIあいai"
composer_->MoveCursorToBeginning();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "A|Iあいai"
composer_->MoveCursorRight();
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
// "AI|あいai"
composer_->MoveCursorRight();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "AIあ|いai"
composer_->MoveCursorRight();
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
// "AIあい|ai"
composer_->MoveCursorRight();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "AIあいa|i"
composer_->MoveCursorRight();
EXPECT_EQ(transliteration::FULL_ASCII, composer_->GetInputMode());
// "AIあいai|"
composer_->MoveCursorRight();
EXPECT_EQ(transliteration::FULL_ASCII, composer_->GetInputMode());
// "AIあいa|i"
composer_->MoveCursorLeft();
EXPECT_EQ(transliteration::FULL_ASCII, composer_->GetInputMode());
// "|AIあいai"
composer_->MoveCursorToBeginning();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "A|Iあいai"
composer_->MoveCursorRight();
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
// "A|あいai"
composer_->Delete();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "Aあ|いai"
composer_->MoveCursorRight();
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
// "A|いai"
composer_->Backspace();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "Aいai|"
composer_->MoveCursorToEnd();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "Aいa|i"
composer_->MoveCursorLeft();
EXPECT_EQ(transliteration::FULL_ASCII, composer_->GetInputMode());
// "Aいai|"
composer_->MoveCursorToEnd();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
}
TEST_F(ComposerTest, DisabledUpdateInputMode) {
// Set the flag disable.
commands::Request request;
request.set_update_input_mode_from_surrounding_text(false);
composer_->SetRequest(&request);
// "あ"
table_->AddRule("a", "\xE3\x81\x82", "");
// "い"
table_->AddRule("i", "\xE3\x81\x84", "");
InsertKey("A", composer_.get());
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
InsertKey("I", composer_.get());
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
InsertKey("a", composer_.get());
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
InsertKey("i", composer_.get());
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
composer_->SetInputMode(transliteration::FULL_ASCII);
InsertKey("a", composer_.get());
EXPECT_EQ(transliteration::FULL_ASCII, composer_->GetInputMode());
InsertKey("i", composer_.get());
EXPECT_EQ(transliteration::FULL_ASCII, composer_->GetInputMode());
string output;
composer_->GetStringForPreedit(&output);
// "AIあいai"
EXPECT_EQ("\x41\x49\xE3\x81\x82\xE3\x81\x84\xEF\xBD\x81\xEF\xBD\x89",
output);
composer_->SetInputMode(transliteration::FULL_KATAKANA);
// Use same scenario as above test case, but the result of GetInputMode
// should be always FULL_KATAKANA regardless of the surrounding text.
// "|AIあいai"
composer_->MoveCursorToBeginning();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "A|Iあいai"
composer_->MoveCursorRight();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "AI|あいai"
composer_->MoveCursorRight();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "AIあ|いai"
composer_->MoveCursorRight();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "AIあい|ai"
composer_->MoveCursorRight();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "AIあいa|i"
composer_->MoveCursorRight();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "AIあいai|"
composer_->MoveCursorRight();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "AIあいa|i"
composer_->MoveCursorLeft();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "|AIあいai"
composer_->MoveCursorToBeginning();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "A|Iあいai"
composer_->MoveCursorRight();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "A|あいai"
composer_->Delete();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "Aあ|いai"
composer_->MoveCursorRight();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "A|いai"
composer_->Backspace();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "Aいai|"
composer_->MoveCursorToEnd();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "Aいa|i"
composer_->MoveCursorLeft();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
// "Aいai|"
composer_->MoveCursorToEnd();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
}
TEST_F(ComposerTest, TransformCharactersForNumbers) {
string query;
query = "";
EXPECT_FALSE(Composer::TransformCharactersForNumbers(&query));
query = "R2D2";
EXPECT_FALSE(Composer::TransformCharactersForNumbers(&query));
// "ー1"
query = "\xE3\x83\xBC\xEF\xBC\x91";
EXPECT_TRUE(Composer::TransformCharactersForNumbers(&query));
// "−1"
EXPECT_EQ("\xE2\x88\x92\xEF\xBC\x91", query);
// "ーー1"
query = "\xE3\x83\xBC\xE3\x83\xBC\xEF\xBC\x91";
EXPECT_FALSE(Composer::TransformCharactersForNumbers(&query));
// "ー"
query = "\xE3\x83\xBC";
EXPECT_FALSE(Composer::TransformCharactersForNumbers(&query));
// "ーー"
query = "\xE3\x83\xBC\xE3\x83\xBC";
EXPECT_FALSE(Composer::TransformCharactersForNumbers(&query));
// "ーーーーー"
query = "\xE3\x83\xBC\xE3\x83\xBC\xE3\x83\xBC\xE3\x83\xBC\xE3\x83\xBC";
EXPECT_FALSE(Composer::TransformCharactersForNumbers(&query));
// "w"
query = "\xEF\xBD\x97";
EXPECT_FALSE(Composer::TransformCharactersForNumbers(&query));
// "ーw"
query = "\xE3\x83\xBC\xEF\xBD\x97";
EXPECT_FALSE(Composer::TransformCharactersForNumbers(&query));
// "ーーw"
query = "\xE3\x83\xBC\xE3\x83\xBC\xEF\xBD\x97";
EXPECT_FALSE(Composer::TransformCharactersForNumbers(&query));
// "@" (half-width @)
query = "@";
EXPECT_FALSE(Composer::TransformCharactersForNumbers(&query));
// "ー@" (half-width @)
query = "\xE3\x83\xBC@";
EXPECT_FALSE(Composer::TransformCharactersForNumbers(&query));
// "ーー@" (half-width @)
query = "\xE3\x83\xBC\xE3\x83\xBC@";
EXPECT_FALSE(Composer::TransformCharactersForNumbers(&query));
// "@" (full-width @)
query = "\xEF\xBC\xA0";
EXPECT_FALSE(Composer::TransformCharactersForNumbers(&query));
// "ー@" (full-width @)
query = "\xE3\x83\xBC\xEF\xBC\xA0";
EXPECT_FALSE(Composer::TransformCharactersForNumbers(&query));
// "ーー@" (full-width @)
query = "\xE3\x83\xBC\xE3\x83\xBC\xEF\xBC\xA0";
EXPECT_FALSE(Composer::TransformCharactersForNumbers(&query));
// "まじかー1"
query = "\xE3\x81\xBE\xE3\x81\x98\xE3\x81\x8B\xE3\x83\xBC\xEF\xBC\x91";
EXPECT_FALSE(Composer::TransformCharactersForNumbers(&query));
// "まじかーw"
query = "\xE3\x81\xBE\xE3\x81\x98\xE3\x81\x8B\xE3\x83\xBC\xEF\xBD\x97";
EXPECT_FALSE(Composer::TransformCharactersForNumbers(&query));
// "1、0"
query = "\xEF\xBC\x91\xE3\x80\x81\xEF\xBC\x90";
EXPECT_TRUE(Composer::TransformCharactersForNumbers(&query));
// "1,0"
EXPECT_EQ("\xEF\xBC\x91\xEF\xBC\x8C\xEF\xBC\x90", query);
// "0。5"
query = "\xEF\xBC\x90\xE3\x80\x82\xEF\xBC\x95";
EXPECT_TRUE(Composer::TransformCharactersForNumbers(&query));
// "0.5"
EXPECT_EQ("\xEF\xBC\x90\xEF\xBC\x8E\xEF\xBC\x95", query);
// "ー1、000。5"
query = "\xE3\x83\xBC\xEF\xBC\x91\xE3\x80\x81\xEF\xBC\x90\xEF\xBC\x90"
"\xEF\xBC\x90\xE3\x80\x82\xEF\xBC\x95";
EXPECT_TRUE(Composer::TransformCharactersForNumbers(&query));
// "−1,000.5"
EXPECT_EQ("\xE2\x88\x92\xEF\xBC\x91\xEF\xBC\x8C\xEF\xBC\x90\xEF\xBC\x90"
"\xEF\xBC\x90\xEF\xBC\x8E\xEF\xBC\x95",
query);
// "03ー"
query = "\xEF\xBC\x90\xEF\xBC\x93\xE3\x83\xBC";
EXPECT_TRUE(Composer::TransformCharactersForNumbers(&query));
// "03−"
EXPECT_EQ("\xEF\xBC\x90\xEF\xBC\x93\xE2\x88\x92", query);
// "03ーーーーー"
query = "\xEF\xBC\x90\xEF\xBC\x93"
"\xE3\x83\xBC\xE3\x83\xBC\xE3\x83\xBC\xE3\x83\xBC\xE3\x83\xBC";
EXPECT_TRUE(Composer::TransformCharactersForNumbers(&query));
// "03−−−−−"
EXPECT_EQ("\xEF\xBC\x90\xEF\xBC\x93"
"\xE2\x88\x92\xE2\x88\x92\xE2\x88\x92\xE2\x88\x92\xE2\x88\x92",
query);
// "xー(ー1)>ーx"
query = "\xEF\xBD\x98\xE3\x83\xBC\xEF\xBC\x88\xE3\x83\xBC\xEF\xBC\x91"
"\xEF\xBC\x89\xEF\xBC\x9E\xE3\x83\xBC\xEF\xBD\x98";
EXPECT_TRUE(Composer::TransformCharactersForNumbers(&query));
// "x−(−1)>−x"
EXPECT_EQ("\xEF\xBD\x98\xE2\x88\x92\xEF\xBC\x88\xE2\x88\x92\xEF\xBC\x91"
"\xEF\xBC\x89\xEF\xBC\x9E\xE2\x88\x92\xEF\xBD\x98",
query);
// "1*ー2/ー3ーー4"
query = "\xEF\xBC\x91\xEF\xBC\x8A\xE3\x83\xBC\xEF\xBC\x92\xEF\xBC\x8F"
"\xE3\x83\xBC\xEF\xBC\x93\xE3\x83\xBC\xE3\x83\xBC\xEF\xBC\x94";
EXPECT_TRUE(Composer::TransformCharactersForNumbers(&query));
// "1*−2/−3−−4"
EXPECT_EQ("\xEF\xBC\x91\xEF\xBC\x8A\xE2\x88\x92\xEF\xBC\x92\xEF\xBC\x8F"
"\xE2\x88\x92\xEF\xBC\x93\xE2\x88\x92\xE2\x88\x92\xEF\xBC\x94",
query);
// "AーZ"
query = "\xEF\xBC\xA1\xE3\x83\xBC\xEF\xBC\xBA";
EXPECT_TRUE(Composer::TransformCharactersForNumbers(&query));
// "A−Z"
EXPECT_EQ("\xEF\xBC\xA1\xE2\x88\x92\xEF\xBC\xBA", query);
// "もずく、うぉーきんぐ。"
query = "\xE3\x82\x82\xE3\x81\x9A\xE3\x81\x8F\xE3\x80\x81\xE3\x81\x86"
"\xE3\x81\x89\xE3\x83\xBC\xE3\x81\x8D\xE3\x82\x93\xE3\x81\x90"
"\xE3\x80\x82";
EXPECT_FALSE(Composer::TransformCharactersForNumbers(&query));
// "えー2、980円!月々たった、2、980円?"
query = "\xE3\x81\x88\xE3\x83\xBC\xEF\xBC\x92\xE3\x80\x81\xEF\xBC\x99"
"\xEF\xBC\x98\xEF\xBC\x90\xE5\x86\x86\xEF\xBC\x81\xE6\x9C\x88"
"\xE3\x80\x85\xE3\x81\x9F\xE3\x81\xA3\xE3\x81\x9F\xE3\x80\x81"
"\xEF\xBC\x92\xE3\x80\x81\xEF\xBC\x99\xEF\xBC\x98\xEF\xBC\x90"
"\xE5\x86\x86\xEF\xBC\x9F";
EXPECT_TRUE(Composer::TransformCharactersForNumbers(&query));
// "えー2,980円!月々たった、2,980円?"
EXPECT_EQ("\xE3\x81\x88\xE3\x83\xBC\xEF\xBC\x92\xEF\xBC\x8C\xEF\xBC\x99"
"\xEF\xBC\x98\xEF\xBC\x90\xE5\x86\x86\xEF\xBC\x81\xE6\x9C\x88"
"\xE3\x80\x85\xE3\x81\x9F\xE3\x81\xA3\xE3\x81\x9F\xE3\x80\x81"
"\xEF\xBC\x92\xEF\xBC\x8C\xEF\xBC\x99\xEF\xBC\x98\xEF\xBC\x90"
"\xE5\x86\x86\xEF\xBC\x9F",
query);
// "およそ、3。14159。"
query = "\xE3\x81\x8A\xE3\x82\x88\xE3\x81\x9D\xE3\x80\x81\xEF\xBC\x93"
"\xE3\x80\x82\xEF\xBC\x91\xEF\xBC\x94\xEF\xBC\x91\xEF\xBC\x95"
"\xEF\xBC\x99\xE3\x80\x82";
EXPECT_TRUE(Composer::TransformCharactersForNumbers(&query));
// "およそ、3.14159."
EXPECT_EQ("\xE3\x81\x8A\xE3\x82\x88\xE3\x81\x9D\xE3\x80\x81\xEF\xBC\x93"
"\xEF\xBC\x8E\xEF\xBC\x91\xEF\xBC\x94\xEF\xBC\x91\xEF\xBC\x95"
"\xEF\xBC\x99\xEF\xBC\x8E",
query);
// "100、" => "100,"
query = "\xEF\xBC\x91\xEF\xBC\x90\xEF\xBC\x90\xE3\x80\x81";
EXPECT_TRUE(Composer::TransformCharactersForNumbers(&query));
EXPECT_EQ("\xEF\xBC\x91\xEF\xBC\x90\xEF\xBC\x90\xEF\xBC\x8C",
query);
// "100。" => "100."
query = "\xEF\xBC\x91\xEF\xBC\x90\xEF\xBC\x90\xE3\x80\x82";
EXPECT_TRUE(Composer::TransformCharactersForNumbers(&query));
EXPECT_EQ("\xEF\xBC\x91\xEF\xBC\x90\xEF\xBC\x90\xEF\xBC\x8E",
query);
}
TEST_F(ComposerTest, PreeditFormAfterCharacterTransform) {
CharacterFormManager *manager =
CharacterFormManager::GetCharacterFormManager();
table_->AddRule("0", "\xEF\xBC\x90", ""); // "0"
table_->AddRule("1", "\xEF\xBC\x91", ""); // "1"
table_->AddRule("2", "\xEF\xBC\x92", ""); // "2"
table_->AddRule("3", "\xEF\xBC\x93", ""); // "3"
table_->AddRule("4", "\xEF\xBC\x94", ""); // "4"
table_->AddRule("5", "\xEF\xBC\x95", ""); // "5"
table_->AddRule("6", "\xEF\xBC\x96", ""); // "6"
table_->AddRule("7", "\xEF\xBC\x97", ""); // "7"
table_->AddRule("8", "\xEF\xBC\x98", ""); // "8"
table_->AddRule("9", "\xEF\xBC\x99", ""); // "9"
table_->AddRule("-", "\xE3\x83\xBC", ""); // "ー"
table_->AddRule(",", "\xE3\x80\x81", ""); // "、"
table_->AddRule(".", "\xE3\x80\x82", ""); // "。"
{
composer_->Reset();
manager->SetDefaultRule();
manager->AddPreeditRule("1", Config::HALF_WIDTH);
manager->AddPreeditRule(".,", Config::HALF_WIDTH);
composer_->InsertCharacter("3.14");
string result;
composer_->GetStringForPreedit(&result);
EXPECT_EQ("3.14",
result);
}
{
composer_->Reset();
manager->SetDefaultRule();
manager->AddPreeditRule("1", Config::FULL_WIDTH);
manager->AddPreeditRule(".,", Config::HALF_WIDTH);
composer_->InsertCharacter("3.14");
string result;
composer_->GetStringForPreedit(&result);
// "3.14"
EXPECT_EQ("\xef\xbc\x93\x2e\xef\xbc\x91\xef\xbc\x94",
result);
}
{
composer_->Reset();
manager->SetDefaultRule();
manager->AddPreeditRule("1", Config::HALF_WIDTH);
manager->AddPreeditRule(".,", Config::FULL_WIDTH);
composer_->InsertCharacter("3.14");
string result;
composer_->GetStringForPreedit(&result);
// "3.14"
EXPECT_EQ("\x33\xef\xbc\x8e\x31\x34",
result);
}
{
composer_->Reset();
manager->SetDefaultRule();
manager->AddPreeditRule("1", Config::FULL_WIDTH);
manager->AddPreeditRule(".,", Config::FULL_WIDTH);
composer_->InsertCharacter("3.14");
string result;
composer_->GetStringForPreedit(&result);
// "3.14"
EXPECT_EQ("\xef\xbc\x93\xef\xbc\x8e\xef\xbc\x91\xef\xbc\x94",
result);
}
}
TEST_F(ComposerTest, ComposingWithcharactertransform) {
table_->AddRule("0", "\xEF\xBC\x90", ""); // "0"
table_->AddRule("1", "\xEF\xBC\x91", ""); // "1"
table_->AddRule("2", "\xEF\xBC\x92", ""); // "2"
table_->AddRule("3", "\xEF\xBC\x93", ""); // "3"
table_->AddRule("4", "\xEF\xBC\x94", ""); // "4"
table_->AddRule("5", "\xEF\xBC\x95", ""); // "5"
table_->AddRule("6", "\xEF\xBC\x96", ""); // "6"
table_->AddRule("7", "\xEF\xBC\x97", ""); // "7"
table_->AddRule("8", "\xEF\xBC\x98", ""); // "8"
table_->AddRule("9", "\xEF\xBC\x99", ""); // "9"
table_->AddRule("-", "\xE3\x83\xBC", ""); // "ー"
table_->AddRule(",", "\xE3\x80\x81", ""); // "、"
table_->AddRule(".", "\xE3\x80\x82", ""); // "。"
composer_->InsertCharacter("-1,000.5");
{
string result;
composer_->GetStringForPreedit(&result);
// "−1,000.5"
EXPECT_EQ("\xE2\x88\x92\xEF\xBC\x91\xEF\xBC\x8C\xEF\xBC\x90\xEF\xBC\x90"
"\xEF\xBC\x90\xEF\xBC\x8E\xEF\xBC\x95",
result);
}
{
string result;
composer_->GetStringForSubmission(&result);
// "−1,000.5"
EXPECT_EQ("\xE2\x88\x92\xEF\xBC\x91\xEF\xBC\x8C\xEF\xBC\x90\xEF\xBC\x90"
"\xEF\xBC\x90\xEF\xBC\x8E\xEF\xBC\x95",
result);
}
{
string result;
composer_->GetQueryForConversion(&result);
EXPECT_EQ("-1,000.5", result);
}
{
string result;
composer_->GetQueryForPrediction(&result);
EXPECT_EQ("-1,000.5", result);
}
{
string left, focused, right;
// Right edge
composer_->GetPreedit(&left, &focused, &right);
// "−1,000.5"
EXPECT_EQ("\xE2\x88\x92\xEF\xBC\x91\xEF\xBC\x8C\xEF\xBC\x90\xEF\xBC\x90"
"\xEF\xBC\x90\xEF\xBC\x8E\xEF\xBC\x95",
left);
EXPECT_TRUE(focused.empty());
EXPECT_TRUE(right.empty());
composer_->MoveCursorLeft();
composer_->GetPreedit(&left, &focused, &right);
// "−1,000."
EXPECT_EQ("\xE2\x88\x92\xEF\xBC\x91\xEF\xBC\x8C\xEF\xBC\x90\xEF\xBC\x90"
"\xEF\xBC\x90\xEF\xBC\x8E",
left);
// "5"
EXPECT_EQ("\xEF\xBC\x95", focused);
EXPECT_TRUE(right.empty());
composer_->MoveCursorLeft();
composer_->GetPreedit(&left, &focused, &right);
// "−1,000"
EXPECT_EQ("\xE2\x88\x92\xEF\xBC\x91\xEF\xBC\x8C\xEF\xBC\x90\xEF\xBC\x90"
"\xEF\xBC\x90",
left);
// "."
EXPECT_EQ("\xEF\xBC\x8E", focused);
// "5"
EXPECT_EQ("\xEF\xBC\x95", right);
composer_->MoveCursorLeft();
composer_->GetPreedit(&left, &focused, &right);
// "−1,00"
EXPECT_EQ("\xE2\x88\x92\xEF\xBC\x91\xEF\xBC\x8C\xEF\xBC\x90\xEF\xBC\x90",
left);
// "0"
EXPECT_EQ("\xEF\xBC\x90", focused);
// ".5"
EXPECT_EQ("\xEF\xBC\x8E\xEF\xBC\x95", right);
composer_->MoveCursorLeft();
composer_->GetPreedit(&left, &focused, &right);
// "−1,0"
EXPECT_EQ("\xE2\x88\x92\xEF\xBC\x91\xEF\xBC\x8C\xEF\xBC\x90", left);
// "0"
EXPECT_EQ("\xEF\xBC\x90", focused);
// "0.5"
EXPECT_EQ("\xEF\xBC\x90\xEF\xBC\x8E\xEF\xBC\x95", right);
composer_->MoveCursorLeft();
composer_->GetPreedit(&left, &focused, &right);
// "−1,"
EXPECT_EQ("\xE2\x88\x92\xEF\xBC\x91\xEF\xBC\x8C", left);
// "0"
EXPECT_EQ("\xEF\xBC\x90", focused);
// "00.5"
EXPECT_EQ("\xEF\xBC\x90\xEF\xBC\x90\xEF\xBC\x8E\xEF\xBC\x95", right);
composer_->MoveCursorLeft();
composer_->GetPreedit(&left, &focused, &right);
// "−1"
EXPECT_EQ("\xE2\x88\x92\xEF\xBC\x91", left);
// ","
EXPECT_EQ("\xEF\xBC\x8C", focused);
// "000.5"
EXPECT_EQ("\xEF\xBC\x90\xEF\xBC\x90\xEF\xBC\x90\xEF\xBC\x8E\xEF\xBC\x95",
right);
composer_->MoveCursorLeft();
composer_->GetPreedit(&left, &focused, &right);
// "−"
EXPECT_EQ("\xE2\x88\x92", left);
// "1"
EXPECT_EQ("\xEF\xBC\x91", focused);
// ",000.5"
EXPECT_EQ("\xEF\xBC\x8C\xEF\xBC\x90\xEF\xBC\x90\xEF\xBC\x90\xEF\xBC\x8E"
"\xEF\xBC\x95",
right);
// Left edge
composer_->MoveCursorLeft();
composer_->GetPreedit(&left, &focused, &right);
EXPECT_TRUE(left.empty());
// "−"
EXPECT_EQ("\xE2\x88\x92", focused);
// "1,000.5"
EXPECT_EQ("\xEF\xBC\x91\xEF\xBC\x8C\xEF\xBC\x90\xEF\xBC\x90\xEF\xBC\x90"
"\xEF\xBC\x8E\xEF\xBC\x95",
right);
}
}
TEST_F(ComposerTest, AlphanumericOfSSH) {
// This is a unittest against http://b/3199626
// 'ssh' (っsh) + F10 should be 'ssh'.
table_->AddRule("ss", "[X]", "s");
table_->AddRule("sha", "[SHA]", "");
composer_->InsertCharacter("ssh");
// "[X]sh"
EXPECT_EQ("\xEF\xBC\xBB\xEF\xBC\xB8\xEF\xBC\xBD\xEF\xBD\x93\xEF\xBD\x88",
GetPreedit(composer_.get()));
string query;
composer_->GetQueryForConversion(&query);
EXPECT_EQ("[X]sh", query);
transliteration::Transliterations t13ns;
composer_->GetTransliterations(&t13ns);
EXPECT_EQ("ssh", t13ns[transliteration::HALF_ASCII]);
}
TEST_F(ComposerTest, Issue2190364) {
// This is a unittest against http://b/2190364
commands::KeyEvent key;
key.set_key_code('a');
// "ち"
key.set_key_string("\xE3\x81\xA1");
// Toggle the input mode to HALF_ASCII
composer_->ToggleInputMode();
EXPECT_TRUE(composer_->InsertCharacterKeyEvent(key));
string output;
composer_->GetStringForPreedit(&output);
EXPECT_EQ("a", output);
// Insertion of a space and backspace it should not change the composition.
composer_->InsertCharacter(" ");
output.clear();
composer_->GetStringForPreedit(&output);
EXPECT_EQ("a ", output);
composer_->Backspace();
output.clear();
composer_->GetStringForPreedit(&output);
EXPECT_EQ("a", output);
// Toggle the input mode to HIRAGANA, the preedit should not be changed.
composer_->ToggleInputMode();
output.clear();
composer_->GetStringForPreedit(&output);
EXPECT_EQ("a", output);
// "a" should be converted to "ち" on Hiragana input mode.
EXPECT_TRUE(composer_->InsertCharacterKeyEvent(key));
output.clear();
composer_->GetStringForPreedit(&output);
// "aち"
EXPECT_EQ("a\xE3\x81\xA1", output);
}
TEST_F(ComposerTest, Issue1817410) {
// This is a unittest against http://b/2190364
// "っ"
table_->AddRule("ss", "\xE3\x81\xA3", "s");
InsertKey("s", composer_.get());
InsertKey("s", composer_.get());
string preedit;
composer_->GetStringForPreedit(&preedit);
// "っs"
EXPECT_EQ("\xE3\x81\xA3\xEF\xBD\x93", preedit);
string t13n;
composer_->GetSubTransliteration(transliteration::HALF_ASCII, 0, 2, &t13n);
EXPECT_EQ("ss", t13n);
t13n.clear();
composer_->GetSubTransliteration(transliteration::HALF_ASCII, 0, 1, &t13n);
EXPECT_EQ("s", t13n);
t13n.clear();
composer_->GetSubTransliteration(transliteration::HALF_ASCII, 1, 1, &t13n);
EXPECT_EQ("s", t13n);
}
TEST_F(ComposerTest, Issue2272745) {
// This is a unittest against http://b/2272745.
// A temporary input mode remains when a composition is canceled.
{
InsertKey("G", composer_.get());
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
composer_->Backspace();
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
}
composer_->Reset();
{
InsertKey("G", composer_.get());
EXPECT_EQ(transliteration::HALF_ASCII, composer_->GetInputMode());
composer_->EditErase();
EXPECT_EQ(transliteration::HIRAGANA, composer_->GetInputMode());
}
}
TEST_F(ComposerTest, Isue2555503) {
// This is a unittest against http://b/2555503.
// Mode respects the previous character too much.
InsertKey("a", composer_.get());
composer_->SetInputMode(transliteration::FULL_KATAKANA);
InsertKey("i", composer_.get());
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
composer_->Backspace();
EXPECT_EQ(transliteration::FULL_KATAKANA, composer_->GetInputMode());
}
TEST_F(ComposerTest, Issue2819580_1) {
// This is a unittest against http://b/2819580.
// 'y' after 'n' disappears.
// "ん"
table_->AddRule("n", "\xe3\x82\x93", "");
// "な"
table_->AddRule("na", "\xe3\x81\xaa", "");
// "や"
table_->AddRule("ya", "\xe3\x82\x84", "");
// "にゃ"
table_->AddRule("nya", "\xe3\x81\xab\xe3\x82\x83", "");
InsertKey("n", composer_.get());
InsertKey("y", composer_.get());
string result;
composer_->GetQueryForConversion(&result);
// "んy"
EXPECT_EQ("\xe3\x82\x93y", result);
}
TEST_F(ComposerTest, Issue2819580_2) {
// This is a unittest against http://b/2819580.
// 'y' after 'n' disappears.
// "ぽ"
table_->AddRule("po", "\xe3\x81\xbd", "");
// "ん"
table_->AddRule("n", "\xe3\x82\x93", "");
// "な"
table_->AddRule("na", "\xe3\x81\xaa", "");
// "や"
table_->AddRule("ya", "\xe3\x82\x84", "");
// "にゃ"
table_->AddRule("nya", "\xe3\x81\xab\xe3\x82\x83", "");
InsertKey("p", composer_.get());
InsertKey("o", composer_.get());
InsertKey("n", composer_.get());
InsertKey("y", composer_.get());
string result;
composer_->GetQueryForConversion(&result);
// "ぽんy"
EXPECT_EQ("\xe3\x81\xbd\xe3\x82\x93y", result);
}
TEST_F(ComposerTest, Issue2819580_3) {
// This is a unittest against http://b/2819580.
// 'y' after 'n' disappears.
// "ん"
table_->AddRule("n", "\xe3\x82\x93", "");
// "な"
table_->AddRule("na", "\xe3\x81\xaa", "");
// "や"
table_->AddRule("ya", "\xe3\x82\x84", "");
// "にゃ"
table_->AddRule("nya", "\xe3\x81\xab\xe3\x82\x83", "");
InsertKey("z", composer_.get());
InsertKey("n", composer_.get());
InsertKey("y", composer_.get());
string result;
composer_->GetQueryForConversion(&result);
// "zんy"
EXPECT_EQ("z\xe3\x82\x93y", result);
}
TEST_F(ComposerTest, Issue2797991_1) {
// This is a unittest against http://b/2797991.
// Half-width alphanumeric mode quits after [CAPITAL LETTER]:[CAPITAL LETTER]
// e.g. C:\Wi -> C:\Wい
// "い"
table_->AddRule("i", "\xe3\x81\x84", "");
InsertKey("C", composer_.get());
InsertKey(":", composer_.get());
InsertKey("\\", composer_.get());
InsertKey("W", composer_.get());
InsertKey("i", composer_.get());
string result;
composer_->GetStringForPreedit(&result);
EXPECT_EQ("C:\\Wi", result);
}
TEST_F(ComposerTest, Issue2797991_2) {
// This is a unittest against http://b/2797991.
// Half-width alphanumeric mode quits after [CAPITAL LETTER]:[CAPITAL LETTER]
// e.g. C:\Wi -> C:\Wい
// "い"
table_->AddRule("i", "\xe3\x81\x84", "");
InsertKey("C", composer_.get());
InsertKey(":", composer_.get());
InsertKey("W", composer_.get());
InsertKey("i", composer_.get());
string result;
composer_->GetStringForPreedit(&result);
EXPECT_EQ("C:Wi", result);
}
TEST_F(ComposerTest, Issue2797991_3) {
// This is a unittest against http://b/2797991.
// Half-width alphanumeric mode quits after [CAPITAL LETTER]:[CAPITAL LETTER]
// e.g. C:\Wi -> C:\Wい
// "い"
table_->AddRule("i", "\xe3\x81\x84", "");
InsertKey("C", composer_.get());
InsertKey(":", composer_.get());
InsertKey("\\", composer_.get());
InsertKey("W", composer_.get());
InsertKey("i", composer_.get());
InsertKeyWithMode("i", commands::HIRAGANA, composer_.get());
string result;
composer_->GetStringForPreedit(&result);
// "C:\Wiい"
EXPECT_EQ("C:\\Wi\xe3\x81\x84", result);
}
TEST_F(ComposerTest, Issue2797991_4) {
// This is a unittest against http://b/2797991.
// Half-width alphanumeric mode quits after [CAPITAL LETTER]:[CAPITAL LETTER]
// e.g. C:\Wi -> C:\Wい
// "い"
table_->AddRule("i", "\xe3\x81\x84", "");
InsertKey("c", composer_.get());
InsertKey(":", composer_.get());
InsertKey("\\", composer_.get());
InsertKey("W", composer_.get());
InsertKey("i", composer_.get());
string result;
composer_->GetStringForPreedit(&result);
EXPECT_EQ("c:\\Wi", result);
}
TEST_F(ComposerTest, CaseSensitiveByConfiguration) {
{
Config config;
ConfigHandler::GetDefaultConfig(&config);
config.set_shift_key_mode_switch(Config::OFF);
ConfigHandler::SetConfig(config);
EXPECT_TRUE(ConfigHandler::SetConfig(config));
table_->InitializeWithRequestAndConfig(*default_request_, config);
// i -> "い"
table_->AddRule("i", "\xe3\x81\x84", "");
// I -> "イ"
table_->AddRule("I", "\xe3\x82\xa4", "");
InsertKey("i", composer_.get());
InsertKey("I", composer_.get());
InsertKey("i", composer_.get());
InsertKey("I", composer_.get());
string result;
composer_->GetStringForPreedit(&result);
// "いイいイ"
EXPECT_EQ("\xe3\x81\x84\xe3\x82\xa4\xe3\x81\x84\xe3\x82\xa4", result);
}
composer_->Reset();
{
Config config;
ConfigHandler::GetDefaultConfig(&config);
config.set_shift_key_mode_switch(Config::ASCII_INPUT_MODE);
ConfigHandler::SetConfig(config);
EXPECT_TRUE(ConfigHandler::SetConfig(config));
table_->InitializeWithRequestAndConfig(*default_request_, config);
// i -> "い"
table_->AddRule("i", "\xe3\x81\x84", "");
// I -> "イ"
table_->AddRule("I", "\xe3\x82\xa4", "");
InsertKey("i", composer_.get());
InsertKey("I", composer_.get());
InsertKey("i", composer_.get());
InsertKey("I", composer_.get());
string result;
composer_->GetStringForPreedit(&result);
// "いIiI"
EXPECT_EQ("\xe3\x81\x84IiI", result);
}
}
TEST_F(ComposerTest,
InputUppercaseInAlphanumericModeWithShiftKeyModeSwitchIsKatakana) {
{
Config config;
ConfigHandler::GetDefaultConfig(&config);
config.set_shift_key_mode_switch(Config::KATAKANA_INPUT_MODE);
ConfigHandler::SetConfig(config);
EXPECT_TRUE(ConfigHandler::SetConfig(config));
table_->InitializeWithRequestAndConfig(*default_request_, config);
// i -> "い"
table_->AddRule("i", "\xe3\x81\x84", "");
// I -> "イ"
table_->AddRule("I", "\xe3\x82\xa4", "");
{
composer_->Reset();
composer_->SetInputMode(transliteration::FULL_ASCII);
InsertKey("I", composer_.get());
string result;
composer_->GetStringForPreedit(&result);
// "I"
EXPECT_EQ("\xef\xbc\xa9", result);
}
{
composer_->Reset();
composer_->SetInputMode(transliteration::HALF_ASCII);
InsertKey("I", composer_.get());
string result;
composer_->GetStringForPreedit(&result);
EXPECT_EQ("I", result);
}
{
composer_->Reset();
composer_->SetInputMode(transliteration::FULL_KATAKANA);
InsertKey("I", composer_.get());
string result;
composer_->GetStringForPreedit(&result);
// "イ"
EXPECT_EQ("\xe3\x82\xa4", result);
}
{
composer_->Reset();
composer_->SetInputMode(transliteration::HALF_KATAKANA);
InsertKey("I", composer_.get());
string result;
composer_->GetStringForPreedit(&result);
// "イ"
EXPECT_EQ("\xEF\xBD\xB2", result);
}
{
composer_->Reset();
composer_->SetInputMode(transliteration::HIRAGANA);
InsertKey("I", composer_.get());
string result;
composer_->GetStringForPreedit(&result);
// "イ"
EXPECT_EQ("\xe3\x82\xa4", result);
}
}
}
TEST_F(ComposerTest,
DeletingAlphanumericPartShouldQuitToggleAlphanumericMode) {
// http://b/2206560
// 1. Type "iGoogle" (preedit text turns to be "いGoogle")
// 2. Type Back-space 6 times ("い")
// 3. Type "i" (should be "いい")
config::Config config;
table_->InitializeWithRequestAndConfig(*default_request_, config);
// i -> "い"
table_->AddRule("i", "\xe3\x81\x84", "");
InsertKey("i", composer_.get());
InsertKey("G", composer_.get());
InsertKey("o", composer_.get());
InsertKey("o", composer_.get());
InsertKey("g", composer_.get());
InsertKey("l", composer_.get());
InsertKey("e", composer_.get());
{
string result;
composer_->GetStringForPreedit(&result);
// "いGoogle"
EXPECT_EQ("\xe3\x81\x84Google", result);
}
composer_->Backspace();
composer_->Backspace();
composer_->Backspace();
composer_->Backspace();
composer_->Backspace();
composer_->Backspace();
{
string result;
composer_->GetStringForPreedit(&result);
// "い"
EXPECT_EQ("\xe3\x81\x84", result);
}
InsertKey("i", composer_.get());
{
string result;
composer_->GetStringForPreedit(&result);
// "いい"
EXPECT_EQ("\xe3\x81\x84\xe3\x81\x84", result);
}
}
TEST_F(ComposerTest, InputModesChangeWhenCursorMoves) {
// The expectation of this test is the same as MS-IME's
config::Config config;
table_->InitializeWithRequestAndConfig(*default_request_, config);
// i -> "い"
table_->AddRule("i", "\xe3\x81\x84", "");
// gi -> "ぎ"
table_->AddRule("gi", "\xe3\x81\x8e", "");
InsertKey("i", composer_.get());
composer_->MoveCursorRight();
{
string result;
composer_->GetStringForPreedit(&result);
// "い"
EXPECT_EQ("\xe3\x81\x84", result);
}
composer_->MoveCursorLeft();
{
string result;
composer_->GetStringForPreedit(&result);
// "い"
EXPECT_EQ("\xe3\x81\x84", result);
}
InsertKey("G", composer_.get());
{
string result;
composer_->GetStringForPreedit(&result);
// "Gい"
EXPECT_EQ("G\xe3\x81\x84", result);
}
composer_->MoveCursorRight();
{
string result;
composer_->GetStringForPreedit(&result);
// "Gい"
EXPECT_EQ("G\xe3\x81\x84", result);
}
InsertKey("G", composer_.get());
{
string result;
composer_->GetStringForPreedit(&result);
// "GいG"
EXPECT_EQ("G\xe3\x81\x84G", result);
}
composer_->MoveCursorLeft();
InsertKey("i", composer_.get());
{
string result;
composer_->GetStringForPreedit(&result);
// "GいいG"
EXPECT_EQ("G\xe3\x81\x84\xe3\x81\x84G", result);
}
composer_->MoveCursorRight();
InsertKey("i", composer_.get());
{
string result;
composer_->GetStringForPreedit(&result);
// "GいいGi"
EXPECT_EQ("G\xe3\x81\x84\xe3\x81\x84Gi", result);
}
InsertKey("G", composer_.get());
InsertKey("i", composer_.get());
{
string result;
composer_->GetStringForPreedit(&result);
// "GいいGiGi"
EXPECT_EQ("G\xe3\x81\x84\xe3\x81\x84GiGi", result);
}
composer_->Backspace();
composer_->Backspace();
composer_->Backspace();
InsertKey("i", composer_.get());
{
string result;
composer_->GetStringForPreedit(&result);
// "GいいGi"
EXPECT_EQ("G\xe3\x81\x84\xe3\x81\x84Gi", result);
}
InsertKey("G", composer_.get());
InsertKey("G", composer_.get());
composer_->MoveCursorRight();
InsertKey("i", composer_.get());
{
string result;
composer_->GetStringForPreedit(&result);
// "GいいGiGGi"
EXPECT_EQ("G\xe3\x81\x84\xe3\x81\x84GiGGi", result);
}
composer_->Backspace();
composer_->Backspace();
composer_->Backspace();
composer_->Backspace();
composer_->Backspace();
composer_->Backspace();
composer_->Backspace();
InsertKey("i", composer_.get());
{
string result;
composer_->GetStringForPreedit(&result);
// "Gい"
EXPECT_EQ("G\xe3\x81\x84", result);
}
composer_->Backspace();
composer_->MoveCursorLeft();
composer_->MoveCursorRight();
InsertKey("i", composer_.get());
{
string result;
composer_->GetStringForPreedit(&result);
// "Gi"
EXPECT_EQ("Gi", result);
}
}
TEST_F(ComposerTest, ShuoldCommit) {
table_->AddRuleWithAttributes("ka", "[KA]", "", DIRECT_INPUT);
table_->AddRuleWithAttributes("tt", "[X]", "t", DIRECT_INPUT);
table_->AddRuleWithAttributes("ta", "[TA]", "", NO_TABLE_ATTRIBUTE);
// k
composer_->InsertCharacter("k");
EXPECT_FALSE(composer_->ShouldCommit());
// k + a
composer_->InsertCharacter("a");
EXPECT_TRUE(composer_->ShouldCommit());
// ka + t
composer_->InsertCharacter("t");
EXPECT_FALSE(composer_->ShouldCommit());
// kat + t
composer_->InsertCharacter("t");
EXPECT_FALSE(composer_->ShouldCommit());
// katt + a
composer_->InsertCharacter("a");
EXPECT_TRUE(composer_->ShouldCommit());
// katta + t
composer_->InsertCharacter("t");
EXPECT_FALSE(composer_->ShouldCommit());
// kattat + a
composer_->InsertCharacter("a");
EXPECT_FALSE(composer_->ShouldCommit());
}
TEST_F(ComposerTest, ShouldCommitHead) {
struct TestData {
const string input_text;
const commands::Context::InputFieldType field_type;
const bool expected_return;
const size_t expected_commit_length;
TestData(const string &input_text,
commands::Context::InputFieldType field_type,
bool expected_return,
size_t expected_commit_length)
: input_text(input_text),
field_type(field_type),
expected_return(expected_return),
expected_commit_length(expected_commit_length) {
}
};
const TestData test_data_list[] = {
// On NORMAL, never commit the head.
TestData("", commands::Context::NORMAL, false, 0),
TestData("A", commands::Context::NORMAL, false, 0),
TestData("AB", commands::Context::NORMAL, false, 0),
TestData("", commands::Context::PASSWORD, false, 0),
// On PASSWORD, commit (length - 1) characters.
TestData("A", commands::Context::PASSWORD, false, 0),
TestData("AB", commands::Context::PASSWORD, true, 1),
TestData("ABCDEFGHI", commands::Context::PASSWORD, true, 8),
// On NUMBER and TEL, commit (length) characters.
TestData("", commands::Context::NUMBER, false, 0),
TestData("A", commands::Context::NUMBER, true, 1),
TestData("AB", commands::Context::NUMBER, true, 2),
TestData("ABCDEFGHI", commands::Context::NUMBER, true, 9),
TestData("", commands::Context::TEL, false, 0),
TestData("A", commands::Context::TEL, true, 1),
TestData("AB", commands::Context::TEL, true, 2),
TestData("ABCDEFGHI", commands::Context::TEL, true, 9),
};
for (size_t i = 0; i < arraysize(test_data_list); ++i) {
const TestData &test_data = test_data_list[i];
SCOPED_TRACE(test_data.input_text);
SCOPED_TRACE(test_data.field_type);
SCOPED_TRACE(test_data.expected_return);
SCOPED_TRACE(test_data.expected_commit_length);
composer_->Reset();
composer_->SetInputFieldType(test_data.field_type);
composer_->InsertCharacter(test_data.input_text);
size_t length_to_commit;
const bool result = composer_->ShouldCommitHead(&length_to_commit);
if (test_data.expected_return) {
EXPECT_TRUE(result);
EXPECT_EQ(test_data.expected_commit_length, length_to_commit);
} else {
EXPECT_FALSE(result);
}
}
}
TEST_F(ComposerTest, CursorMovements) {
composer_->InsertCharacter("mozuku");
EXPECT_EQ(6, composer_->GetLength());
EXPECT_EQ(6, composer_->GetCursor());
composer_->MoveCursorRight();
EXPECT_EQ(6, composer_->GetCursor());
composer_->MoveCursorLeft();
EXPECT_EQ(5, composer_->GetCursor());
composer_->MoveCursorToBeginning();
EXPECT_EQ(0, composer_->GetCursor());
composer_->MoveCursorLeft();
EXPECT_EQ(0, composer_->GetCursor());
composer_->MoveCursorRight();
EXPECT_EQ(1, composer_->GetCursor());
composer_->MoveCursorTo(0);
EXPECT_EQ(0, composer_->GetCursor());
composer_->MoveCursorTo(6);
EXPECT_EQ(6, composer_->GetCursor());
composer_->MoveCursorTo(3);
EXPECT_EQ(3, composer_->GetCursor());
composer_->MoveCursorTo(10);
EXPECT_EQ(3, composer_->GetCursor());
composer_->MoveCursorTo(-1);
EXPECT_EQ(3, composer_->GetCursor());
}
TEST_F(ComposerTest, SourceText) {
composer_->SetInputMode(transliteration::HALF_ASCII);
composer_->InsertCharacterPreedit("mozc");
composer_->mutable_source_text()->assign("MOZC");
EXPECT_FALSE(composer_->Empty());
EXPECT_EQ("mozc", GetPreedit(composer_.get()));
EXPECT_EQ("MOZC", composer_->source_text());
composer_->Backspace();
composer_->Backspace();
EXPECT_FALSE(composer_->Empty());
EXPECT_EQ("mo", GetPreedit(composer_.get()));
EXPECT_EQ("MOZC", composer_->source_text());
composer_->Reset();
EXPECT_TRUE(composer_->Empty());
EXPECT_TRUE(composer_->source_text().empty());
}
TEST_F(ComposerTest, DeleteAt) {
// "も"
table_->AddRule("mo", "\xE3\x82\x82", "");
// "ず"
table_->AddRule("zu", "\xE3\x81\x9a", "");
composer_->InsertCharacter("z");
// "z"
EXPECT_EQ("\xef\xbd\x9a", GetPreedit(composer_.get()));
EXPECT_EQ(1, composer_->GetCursor());
composer_->DeleteAt(0);
EXPECT_EQ("", GetPreedit(composer_.get()));
EXPECT_EQ(0, composer_->GetCursor());
composer_->InsertCharacter("mmoz");
// "mもz"
EXPECT_EQ("\xef\xbd\x8d\xe3\x82\x82\xef\xbd\x9a",
GetPreedit(composer_.get()));
EXPECT_EQ(3, composer_->GetCursor());
composer_->DeleteAt(0);
// "もz"
EXPECT_EQ("\xe3\x82\x82\xef\xbd\x9a", GetPreedit(composer_.get()));
EXPECT_EQ(2, composer_->GetCursor());
composer_->InsertCharacter("u");
// "もず"
EXPECT_EQ("\xe3\x82\x82\xe3\x81\x9a", GetPreedit(composer_.get()));
EXPECT_EQ(2, composer_->GetCursor());
composer_->InsertCharacter("m");
// "もずm"
EXPECT_EQ("\xe3\x82\x82\xe3\x81\x9a\xef\xbd\x8d",
GetPreedit(composer_.get()));
EXPECT_EQ(3, composer_->GetCursor());
composer_->DeleteAt(1);
// "もm"
EXPECT_EQ("\xe3\x82\x82\xef\xbd\x8d", GetPreedit(composer_.get()));
EXPECT_EQ(2, composer_->GetCursor());
composer_->InsertCharacter("o");
// "もも"
EXPECT_EQ("\xe3\x82\x82\xe3\x82\x82", GetPreedit(composer_.get()));
EXPECT_EQ(2, composer_->GetCursor());
}
TEST_F(ComposerTest, DeleteRange) {
// "も"
table_->AddRule("mo", "\xE3\x82\x82", "");
// "ず"
table_->AddRule("zu", "\xE3\x81\x9a", "");
composer_->InsertCharacter("z");
// "z"
EXPECT_EQ("\xef\xbd\x9a", GetPreedit(composer_.get()));
EXPECT_EQ(1, composer_->GetCursor());
composer_->DeleteRange(0, 1);
EXPECT_EQ("", GetPreedit(composer_.get()));
EXPECT_EQ(0, composer_->GetCursor());
composer_->InsertCharacter("mmozmoz");
// "mもzもz"
EXPECT_EQ("\xef\xbd\x8d\xe3\x82\x82\xef\xbd\x9a\xe3\x82\x82\xef\xbd\x9a",
GetPreedit(composer_.get()));
EXPECT_EQ(5, composer_->GetCursor());
composer_->DeleteRange(0, 3);
// "もz"
EXPECT_EQ("\xe3\x82\x82\xef\xbd\x9a", GetPreedit(composer_.get()));
EXPECT_EQ(2, composer_->GetCursor());
composer_->InsertCharacter("u");
// "もず"
EXPECT_EQ("\xe3\x82\x82\xe3\x81\x9a", GetPreedit(composer_.get()));
EXPECT_EQ(2, composer_->GetCursor());
composer_->InsertCharacter("xyz");
composer_->MoveCursorToBeginning();
composer_->InsertCharacter("mom");
// "もm|もずxyz"
EXPECT_EQ("\xe3\x82\x82\xef\xbd\x8d\xe3\x82\x82\xe3\x81\x9a"
"\xef\xbd\x98\xef\xbd\x99\xef\xbd\x9a",
GetPreedit(composer_.get()));
EXPECT_EQ(2, composer_->GetCursor());
composer_->DeleteRange(2, 3);
// "もm|yz"
EXPECT_EQ("\xe3\x82\x82\xef\xbd\x8d\xef\xbd\x99\xef\xbd\x9a",
GetPreedit(composer_.get()));
EXPECT_EQ(2, composer_->GetCursor());
composer_->InsertCharacter("o");
// "もも|yz"
EXPECT_EQ("\xe3\x82\x82\xe3\x82\x82\xef\xbd\x99\xef\xbd\x9a",
GetPreedit(composer_.get()));
EXPECT_EQ(2, composer_->GetCursor());
composer_->DeleteRange(2, 1000);
// "もも|"
EXPECT_EQ("\xe3\x82\x82\xe3\x82\x82",
GetPreedit(composer_.get()));
EXPECT_EQ(2, composer_->GetCursor());
}
TEST_F(ComposerTest, 12KeysAsciiGetQueryForPrediction) {
// http://b/5509480
commands::Request request;
request.set_zero_query_suggestion(true);
request.set_mixed_conversion(true);
request.set_combine_all_segments(true);
request.set_special_romanji_table(
commands::Request::TWELVE_KEYS_TO_HALFWIDTHASCII);
composer_->SetRequest(&request);
table_->InitializeWithRequestAndConfig(request,
config::ConfigHandler::GetConfig());
composer_->InsertCharacter("2");
EXPECT_EQ("a", GetPreedit(composer_.get()));
string result;
composer_->GetQueryForConversion(&result);
EXPECT_EQ("a", result);
result.clear();
composer_->GetQueryForPrediction(&result);
EXPECT_EQ("a", result);
}
TEST_F(ComposerTest, InsertCharacterPreedit) {
// "ああakka。"
const char kTestStr[] =
"\xe3\x81\x82\xe3\x81\x82\x61\xef\xbd\x8b\x6b\x61\xe3\x80\x82";
{
string preedit;
string conversion_query;
string prediction_query;
string base;
set<string> expanded;
composer_->InsertCharacterPreedit(kTestStr);
composer_->GetStringForPreedit(&preedit);
composer_->GetQueryForConversion(&conversion_query);
composer_->GetQueryForPrediction(&prediction_query);
composer_->GetQueriesForPrediction(&base, &expanded);
EXPECT_FALSE(preedit.empty());
EXPECT_FALSE(conversion_query.empty());
EXPECT_FALSE(prediction_query.empty());
EXPECT_FALSE(base.empty());
}
composer_->Reset();
{
string preedit;
string conversion_query;
string prediction_query;
string base;
set<string> expanded;
vector<string> chars;
Util::SplitStringToUtf8Chars(kTestStr, &chars);
for (size_t i = 0; i < chars.size(); ++i) {
composer_->InsertCharacterPreedit(chars[i]);
}
composer_->GetStringForPreedit(&preedit);
composer_->GetQueryForConversion(&conversion_query);
composer_->GetQueryForPrediction(&prediction_query);
composer_->GetQueriesForPrediction(&base, &expanded);
EXPECT_FALSE(preedit.empty());
EXPECT_FALSE(conversion_query.empty());
EXPECT_FALSE(prediction_query.empty());
EXPECT_FALSE(base.empty());
}
}
namespace {
ProbableKeyEvents GetStubProbableKeyEvent(int key_code, double probability) {
ProbableKeyEvents result;
ProbableKeyEvent *event;
event = result.Add();
event->set_key_code(key_code);
event->set_probability(probability);
event = result.Add();
event->set_key_code('z');
event->set_probability(1.0f - probability);
return result;
}
} // namespace
class MockTypingModel : public TypingModel {
public:
MockTypingModel() : TypingModel(NULL, 0, NULL, 0, NULL) {}
virtual ~MockTypingModel() {}
virtual int GetCost(StringPiece key) const {
return 10;
}
};
// Test fixture for setting up mobile qwerty romaji table to test typing
// corrector inside composer.
class TypingCorrectionTest : public ::testing::Test {
protected:
virtual void SetUp() {
SystemUtil::SetUserProfileDirectory(FLAGS_test_tmpdir);
ConfigHandler::GetConfig(&config_backup_);
Config config;
ConfigHandler::GetDefaultConfig(&config);
config.set_use_typing_correction(true);
ConfigHandler::SetConfig(config);
table_.reset(new Table);
table_->LoadFromFile("system://qwerty_mobile-hiragana.tsv");
request_.reset(new Request);
request_->set_special_romanji_table(Request::QWERTY_MOBILE_TO_HIRAGANA);
composer_.reset(new Composer(table_.get(), request_.get()));
table_->typing_model_ = Singleton<MockTypingModel>::get();
}
virtual void TearDown() {
ConfigHandler::SetConfig(config_backup_);
}
static bool IsTypingCorrectorClearedOrInvalidated(const Composer &composer) {
vector<TypeCorrectedQuery> queries;
composer.GetTypeCorrectedQueriesForPrediction(&queries);
return queries.empty();
}
scoped_ptr<Request> request_;
scoped_ptr<Composer> composer_;
scoped_ptr<Table> table_;
Config config_backup_;
};
TEST_F(TypingCorrectionTest, ResetAfterComposerReset) {
composer_->InsertCharacterForProbableKeyEvents(
"a",
GetStubProbableKeyEvent('a', 0.9f));
EXPECT_FALSE(IsTypingCorrectorClearedOrInvalidated(*composer_));
composer_->Reset();
EXPECT_TRUE(IsTypingCorrectorClearedOrInvalidated(*composer_));
composer_->InsertCharacterForProbableKeyEvents(
"a",
GetStubProbableKeyEvent('a', 0.9f));
EXPECT_FALSE(IsTypingCorrectorClearedOrInvalidated(*composer_));
}
TEST_F(TypingCorrectionTest, InvalidateAfterDeleteAt) {
composer_->InsertCharacterForProbableKeyEvents(
"a",
GetStubProbableKeyEvent('a', 0.9f));
EXPECT_FALSE(IsTypingCorrectorClearedOrInvalidated(*composer_));
composer_->DeleteAt(0);
EXPECT_TRUE(IsTypingCorrectorClearedOrInvalidated(*composer_));
}
TEST_F(TypingCorrectionTest, InvalidateAfterDelete) {
composer_->InsertCharacterForProbableKeyEvents(
"a",
GetStubProbableKeyEvent('a', 0.9f));
EXPECT_FALSE(IsTypingCorrectorClearedOrInvalidated(*composer_));
composer_->Delete();
EXPECT_TRUE(IsTypingCorrectorClearedOrInvalidated(*composer_));
}
TEST_F(TypingCorrectionTest, InvalidateAfterDeleteRange) {
composer_->InsertCharacterForProbableKeyEvents(
"a",
GetStubProbableKeyEvent('a', 0.9f));
EXPECT_FALSE(IsTypingCorrectorClearedOrInvalidated(*composer_));
composer_->DeleteRange(0, 1);
EXPECT_TRUE(IsTypingCorrectorClearedOrInvalidated(*composer_));
}
TEST_F(TypingCorrectionTest, ResetAfterEditErase) {
composer_->InsertCharacterForProbableKeyEvents(
"a",
GetStubProbableKeyEvent('a', 0.9f));
EXPECT_FALSE(IsTypingCorrectorClearedOrInvalidated(*composer_));
composer_->EditErase();
EXPECT_TRUE(IsTypingCorrectorClearedOrInvalidated(*composer_));
composer_->InsertCharacterForProbableKeyEvents(
"a",
GetStubProbableKeyEvent('a', 0.9f));
EXPECT_FALSE(IsTypingCorrectorClearedOrInvalidated(*composer_));
}
TEST_F(TypingCorrectionTest, InvalidateAfterBackspace) {
composer_->InsertCharacterForProbableKeyEvents(
"a",
GetStubProbableKeyEvent('a', 0.9f));
EXPECT_FALSE(IsTypingCorrectorClearedOrInvalidated(*composer_));
composer_->Backspace();
EXPECT_TRUE(IsTypingCorrectorClearedOrInvalidated(*composer_));
}
TEST_F(TypingCorrectionTest, InvalidateAfterMoveCursorLeft) {
composer_->InsertCharacterForProbableKeyEvents(
"a",
GetStubProbableKeyEvent('a', 0.9f));
EXPECT_FALSE(IsTypingCorrectorClearedOrInvalidated(*composer_));
composer_->MoveCursorLeft();
EXPECT_TRUE(IsTypingCorrectorClearedOrInvalidated(*composer_));
}
TEST_F(TypingCorrectionTest, InvalidateAfterMoveCursorRight) {
composer_->InsertCharacterForProbableKeyEvents(
"a",
GetStubProbableKeyEvent('a', 0.9f));
EXPECT_FALSE(IsTypingCorrectorClearedOrInvalidated(*composer_));
composer_->MoveCursorRight();
EXPECT_TRUE(IsTypingCorrectorClearedOrInvalidated(*composer_));
}
TEST_F(TypingCorrectionTest, InvalidateAfterMoveCursorToBeginning) {
composer_->InsertCharacterForProbableKeyEvents(
"a",
GetStubProbableKeyEvent('a', 0.9f));
EXPECT_FALSE(IsTypingCorrectorClearedOrInvalidated(*composer_));
composer_->MoveCursorToBeginning();
EXPECT_TRUE(IsTypingCorrectorClearedOrInvalidated(*composer_));
}
TEST_F(TypingCorrectionTest, InvalidateAfterMoveCursorToEnd) {
composer_->InsertCharacterForProbableKeyEvents(
"a",
GetStubProbableKeyEvent('a', 0.9f));
EXPECT_FALSE(IsTypingCorrectorClearedOrInvalidated(*composer_));
composer_->MoveCursorToEnd();
EXPECT_TRUE(IsTypingCorrectorClearedOrInvalidated(*composer_));
}
TEST_F(TypingCorrectionTest, InvalidateAfterMoveCursorTo) {
composer_->InsertCharacterForProbableKeyEvents(
"a",
GetStubProbableKeyEvent('a', 0.9f));
composer_->InsertCharacterForProbableKeyEvents(
"b",
GetStubProbableKeyEvent('a', 0.9f));
EXPECT_FALSE(IsTypingCorrectorClearedOrInvalidated(*composer_));
composer_->MoveCursorTo(0);
EXPECT_TRUE(IsTypingCorrectorClearedOrInvalidated(*composer_));
}
TEST_F(TypingCorrectionTest, GetTypeCorrectedQueriesForPrediction) {
// This test only checks if typing correction candidates are nonempty after
// each key insertion. The quality of typing correction depends on data model
// and is tested in composer/internal/typing_corrector_test.cc.
const char *kKeys[] = { "m", "o", "z", "u", "k", "u" };
for (size_t i = 0; i < arraysize(kKeys); ++i) {
composer_->InsertCharacterForProbableKeyEvents(
kKeys[i],
GetStubProbableKeyEvent(kKeys[i][0], 0.9f));
EXPECT_FALSE(IsTypingCorrectorClearedOrInvalidated(*composer_));
}
composer_->Backspace();
for (size_t i = 0; i < arraysize(kKeys); ++i) {
composer_->InsertCharacterForProbableKeyEvents(kKeys[i],
ProbableKeyEvents());
EXPECT_TRUE(IsTypingCorrectorClearedOrInvalidated(*composer_));
}
}
TEST_F(ComposerTest, GetRawString) {
// "さ"
table_->AddRule("sa", "\xE3\x81\x95", "");
// "し"
table_->AddRule("shi", "\xE3\x81\x97", "");
// "み"
table_->AddRule("mi", "\xE3\x81\xBF", "");
composer_->SetOutputMode(transliteration::HIRAGANA);
composer_->InsertCharacter("sashimi");
string output;
composer_->GetStringForPreedit(&output);
// "さしみ"
EXPECT_EQ("\xE3\x81\x95\xE3\x81\x97\xE3\x81\xBF", output);
string raw_string;
composer_->GetRawString(&raw_string);
EXPECT_EQ("sashimi", raw_string);
string raw_sub_string;
composer_->GetRawSubString(0, 2, &raw_sub_string);
EXPECT_EQ("sashi", raw_sub_string);
composer_->GetRawSubString(1, 1, &raw_sub_string);
EXPECT_EQ("shi", raw_sub_string);
}
} // namespace composer
} // namespace mozc