blob: 3b4ad4db1c9cba79bc76ab17bf0940acb9ebf867 [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 "testing/base/public/googletest.h"
#include "testing/base/public/gunit.h"
#include "base/util.h"
#include "session/commands.pb.h"
#include "win32/ime/ime_composition_string.h"
namespace mozc {
namespace win32 {
namespace {
const size_t kNumCandidates = 13;
const char* kValueList[kNumCandidates] = {
"Beta",
"\343\203\231\343\203\274\343\202\277", // "ベータ"
"BETA",
"beta",
"\316\262", // "β"
"\316\222", // "Β"
"\343\214\274", // "㌼"
"Beta",
"\343\201\271\343\203\274\343\201\237", // "べーた"
"\343\203\231\343\203\274\343\202\277", // "ベータ"
"be-ta",
// "be-ta"
"\357\275\202\357\275\205\357\274\215\357\275\224\357\275\201",
"\357\276\215\357\276\236\357\275\260\357\276\200", // "ベータ"
};
const int32 kValueLengths[kNumCandidates] = {
4, 3, 4, 4, 1, 1, 1, 4, 3, 3, 5, 5, 4,
};
const int32 kIDs[kNumCandidates] = {
0, 1, 2, 3, 4, 5, 6, 7, -1, -2, -3, -7, -11,
};
string GetStringImpl(const CompositionString &composition,
const DWORD offset, const DWORD length) {
const BYTE *addr = reinterpret_cast<const BYTE*>(&composition);
const wchar_t *string_start =
reinterpret_cast<const wchar_t *>(addr + offset);
const wstring wstr(string_start, string_start + length);
string str;
Util::WideToUTF8(wstr.c_str(), &str);
return str;
}
BYTE GetAttributeImpl(const CompositionString &composition,
const DWORD offset, const DWORD length, size_t index) {
const BYTE *addr = reinterpret_cast<const BYTE*>(&composition);
const BYTE *attribute_start = addr + offset;
EXPECT_LE(0, index);
EXPECT_LT(index, length);
return attribute_start[index];
}
#define GET_STRING(composition, field_name) \
GetStringImpl((composition), (composition).info.dw##field_name##Offset, \
(composition).info.dw##field_name##Len)
#define GET_ATTRIBUTE(composition, field_name, index) \
GetAttributeImpl((composition), \
(composition).info.dw##field_name##Offset, \
(composition).info.dw##field_name##Len, \
(index))
// TODO(yukawa): Make a common library for this function.
void FillOutputForSuggestion(commands::Output *output) {
DCHECK_NE(nullptr, output);
output->Clear();
output->set_mode(commands::HIRAGANA);
output->set_consumed(true);
{
commands::Preedit *preedit = output->mutable_preedit();
preedit->set_cursor(4);
{
commands::Preedit::Segment *segment = preedit->add_segment();
segment->set_annotation(commands::Preedit::Segment::UNDERLINE);
// "あるふぁ"
segment->set_value("\343\201\202\343\202\213\343\201\265\343\201\201");
segment->set_value_length(4);
// "あるふぁ"
segment->set_key("\343\201\202\343\202\213\343\201\265\343\201\201");
}
}
{
commands::Candidates *candidates = output->mutable_candidates();
candidates->set_size(2);
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(0);
candidate->set_value("AlphaBeta");
candidate->set_id(0);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(1);
// "アルファ"
candidate->set_value("\343\202\242\343\203\253\343\203\225\343\202\241");
candidate->set_id(1);
}
candidates->set_position(0);
candidates->set_category(commands::SUGGESTION);
candidates->set_display_type(commands::MAIN);
{
commands::Footer *footer = candidates->mutable_footer();
footer->set_sub_label("build 436");
}
}
{
commands::Status *status = output->mutable_status();
status->set_activated(true);
status->set_mode(commands::HIRAGANA);
}
{
commands::CandidateList *candidate_list =
output->mutable_all_candidate_words();
candidate_list->set_focused_index(0);
{
commands::CandidateWord *candidate = candidate_list->add_candidates();
candidate->set_id(0);
candidate->set_index(0);
// "あるふぁべーた"
candidate->set_key("\343\201\202\343\202\213\343\201\265\343\201\201"
"\343\201\271\343\203\274\343\201\237");
candidate->set_value("AlphaBeta");
}
{
commands::CandidateWord *candidate = candidate_list->add_candidates();
candidate->set_id(1);
candidate->set_index(1);
// "アルファ"
candidate->set_value("\343\202\242\343\203\253\343\203\225\343\202\241");
}
candidate_list->set_category(commands::SUGGESTION);
}
}
// TODO(yukawa): Make a common library for this function.
void FillOutputForPrediction(commands::Output *output) {
DCHECK_NE(nullptr, output);
output->Clear();
output->set_mode(commands::HIRAGANA);
output->set_consumed(true);
{
commands::Preedit *preedit = output->mutable_preedit();
preedit->set_cursor(9);
{
commands::Preedit::Segment *segment = preedit->add_segment();
segment->set_annotation(commands::Preedit::Segment::HIGHLIGHT);
segment->set_value("AlphaBeta");
segment->set_value_length(9);
// "あるふぁ"
segment->set_key("\343\201\202\343\202\213\343\201\265\343\201\201");
}
}
{
commands::Candidates *candidates = output->mutable_candidates();
candidates->set_focused_index(0);
candidates->set_size(2);
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(0);
candidate->set_value("AlphaBeta");
{
commands::Annotation *annotation = candidate->mutable_annotation();
annotation->set_shortcut("1");
}
candidate->set_id(0);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(1);
// "アルファ"
candidate->set_value("\343\202\242\343\203\253\343\203\225\343\202\241");
{
commands::Annotation *annotation = candidate->mutable_annotation();
annotation->set_shortcut("2");
}
candidate->set_id(1);
}
candidates->set_position(0);
candidates->set_category(commands::PREDICTION);
candidates->set_display_type(commands::MAIN);
{
commands::Footer *footer = candidates->mutable_footer();
footer->set_index_visible(true);
footer->set_logo_visible(true);
footer->set_sub_label("build 436");
}
}
{
commands::Status *status = output->mutable_status();
status->set_activated(true);
status->set_mode(commands::HIRAGANA);
}
{
commands::CandidateList *candidate_list =
output->mutable_all_candidate_words();
candidate_list->set_focused_index(0);
{
commands::CandidateWord *candidate = candidate_list->add_candidates();
candidate->set_id(0);
candidate->set_index(0);
// "あるふぁべーた"
candidate->set_key("\343\201\202\343\202\213\343\201\265\343\201\201"
"\343\201\271\343\203\274\343\201\237");
candidate->set_value("AlphaBeta");
}
{
commands::CandidateWord *candidate = candidate_list->add_candidates();
candidate->set_id(1);
candidate->set_index(1);
// "アルファ"
candidate->set_value("\343\202\242\343\203\253\343\203\225\343\202\241");
}
candidate_list->set_category(commands::PREDICTION);
}
}
// TODO(yukawa): Make a common library for this function.
void FillOutputForConversion(
commands::Output *output, int focused_index, bool has_candidates) {
DCHECK_LE(0, focused_index);
DCHECK_GT(kNumCandidates, focused_index);
DCHECK_NE(nullptr, output);
output->Clear();
const int32 focused_value_length = kValueLengths[focused_index];
const char *focused_value = kValueList[focused_index];
const int32 focused_id = kIDs[focused_index];
output->set_mode(commands::HIRAGANA);
output->set_consumed(true);
{
const int alpha_length = 5;
commands::Preedit *preedit = output->mutable_preedit();
preedit->set_cursor(alpha_length + focused_value_length);
{
commands::Preedit::Segment *segment = preedit->add_segment();
segment->set_annotation(commands::Preedit::Segment::UNDERLINE);
segment->set_value("Alpha");
segment->set_value_length(alpha_length);
// "あるふぁ"
segment->set_key("\343\201\202\343\202\213\343\201\265\343\201\201");
}
{
commands::Preedit::Segment *segment = preedit->add_segment();
segment->set_annotation(commands::Preedit::Segment::HIGHLIGHT);
segment->set_value(focused_value);
segment->set_value_length(focused_value_length);
// "べーた"
segment->set_key("\343\201\271\343\203\274\343\201\237");
}
preedit->set_highlighted_position(alpha_length);
}
if (has_candidates) {
commands::Candidates *candidates = output->mutable_candidates();
candidates->set_focused_index(focused_index);
candidates->set_size(9);
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(0);
candidate->set_value("BETA");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "[半] アルファベット"
annotation->set_description(
"[\345\215\212] \343\202\242\343\203\253\343\203\225\343\202\241"
"\343\203\231\343\203\203\343\203\210");
annotation->set_shortcut("1");
}
candidate->set_id(0);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(1);
candidate->set_value("\343\203\231\343\203\274\343\202\277");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "[全] カタカナ"
annotation->set_description(
"[\345\215\212] \343\202\253\343\202\277\343\202\253\343\203\212");
annotation->set_shortcut("2");
}
candidate->set_id(1);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(2);
candidate->set_value("beta");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "[半] アルファベット"
annotation->set_description(
"[\345\215\212] \343\202\242\343\203\253\343\203\225\343\202\241"
"\343\203\231\343\203\203\343\203\210");
annotation->set_shortcut("3");
}
candidate->set_id(2);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(3);
// "β"
candidate->set_value("\316\262");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "ギリシャ文字(小文字)"
annotation->set_description(
"\343\202\256\343\203\252\343\202\267\343\203\243\346\226\207"
"\345\255\227(\345\260\217\346\226\207\345\255\227)");
annotation->set_shortcut("4");
}
candidate->set_id(3);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(4);
// "Β"
candidate->set_value("\316\222");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "ギリシャ文字(大文字)"
annotation->set_description(
"\343\202\256\343\203\252\343\202\267\343\203\243\346\226\207"
"\345\255\227(\345\244\247\346\226\207\345\255\227)");
annotation->set_shortcut("5");
}
candidate->set_id(4);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(5);
// "㌼"
candidate->set_value("\343\214\274");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "<機種依存文字>"
annotation->set_description("<\346\251\237\347\250\256\344\276\235"
"\345\255\230\346\226\207\345\255\227>");
annotation->set_shortcut("6");
}
candidate->set_id(5);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(6);
candidate->set_value("Beta");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "[半] アルファベット"
annotation->set_description(
"[\345\215\212] \343\202\242\343\203\253\343\203\225\343\202\241"
"\343\203\231\343\203\203\343\203\210");
annotation->set_shortcut("7");
}
candidate->set_id(6);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(7);
// "べーた"
candidate->set_value("\343\201\271\343\203\274\343\201\237");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "ひらがな"
annotation->set_description(
"\343\201\262\343\202\211\343\201\214\343\201\252");
annotation->set_shortcut("8");
}
candidate->set_id(7);
}
{
commands::Candidates::Candidate *candidate = candidates->add_candidate();
candidate->set_index(8);
// "そのほかの文字種"
candidate->set_value("\343\201\235\343\201\256\343\201\273\343\201\213"
"\343\201\256\346\226\207\345\255\227\347\250\256");
{
commands::Annotation *annotation = candidate->mutable_annotation();
annotation->set_shortcut("9");
}
candidate->set_id(-3);
}
candidates->set_position(5);
{
commands::Candidates *sub_candidates =
candidates->mutable_subcandidates();
sub_candidates->set_focused_index(2);
sub_candidates->set_size(5);
{
{
commands::Candidates::Candidate *candidate =
sub_candidates->add_candidate();
candidate->set_index(0);
// "べーた"
candidate->set_value("\343\201\271\343\203\274\343\201\237");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "ひらがな"
annotation->set_description(
"\343\201\262\343\202\211\343\201\214\343\201\252");
}
candidate->set_id(-1);
}
{
commands::Candidates::Candidate *candidate =
sub_candidates->add_candidate();
candidate->set_index(1);
// "ベータ"
candidate->set_value("\343\203\231\343\203\274\343\202\277");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "[全] カタカナ"
annotation->set_description(
"[\345\215\212] "
"\343\202\253\343\202\277\343\202\253\343\203\212");
}
candidate->set_id(-2);
}
{
commands::Candidates::Candidate *candidate =
sub_candidates->add_candidate();
candidate->set_index(2);
candidate->set_value("be-ta");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "[半]"
annotation->set_description("[\345\215\212]");
}
candidate->set_id(-3);
}
{
commands::Candidates::Candidate *candidate =
sub_candidates->add_candidate();
candidate->set_index(3);
// "be-ta"
candidate->set_value(
"\357\275\202\357\275\205\357\274\215\357\275\224\357\275\201");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "[全]"
annotation->set_description("[\345\205\250]");
}
candidate->set_id(-7);
}
{
commands::Candidates::Candidate *candidate =
sub_candidates->add_candidate();
candidate->set_index(4);
// "ベータ"
candidate->set_value(
"\357\276\215\357\276\236\357\275\260\357\276\200");
{
commands::Annotation *annotation = candidate->mutable_annotation();
// "[半] カタカナ"
annotation->set_description(
"[\345\215\212] "
"\343\202\253\343\202\277\343\202\253\343\203\212");
}
candidate->set_id(-11);
}
}
sub_candidates->set_position(8);
sub_candidates->set_category(commands::TRANSLITERATION);
sub_candidates->set_display_type(commands::CASCADE);
}
candidates->set_category(commands::CONVERSION);
candidates->set_display_type(commands::MAIN);
{
commands::Footer *footer = candidates->mutable_footer();
footer->set_index_visible(true);
footer->set_logo_visible(true);
footer->set_sub_label("build 436");
}
}
{
commands::Status *status = output->mutable_status();
status->set_activated(true);
status->set_mode(commands::HIRAGANA);
}
{
commands::CandidateList *candidate_list =
output->mutable_all_candidate_words();
candidate_list->set_focused_index(focused_index);
for (size_t i = 0; i < kNumCandidates; ++i) {
commands::CandidateWord *candidate = candidate_list->add_candidates();
candidate->set_id(kIDs[i]);
candidate->set_index(i);
candidate->set_value(kValueList[i]);
}
candidate_list->set_category(commands::CONVERSION);
}
}
} // anonymous namespace
TEST(ImeCompositionStringTest, StartCompositionTest) {
CompositionString compstr;
EXPECT_TRUE(compstr.Initialize());
commands::Output output;
commands::Preedit *preedit = output.mutable_preedit();
commands::Preedit::Segment *segment = preedit->add_segment();
preedit->set_cursor(1);
segment->set_annotation(commands::Preedit::Segment::UNDERLINE);
// "が"
segment->set_key("\xE3\x81\x8C");
// "が"
segment->set_value("\xE3\x81\x8C");
segment->set_value_length(1);
vector<UIMessage> messages;
EXPECT_TRUE(compstr.Update(output, &messages));
EXPECT_EQ(2, messages.size());
EXPECT_EQ(WM_IME_STARTCOMPOSITION, messages[0].message());
EXPECT_EQ(0, messages[0].wparam());
EXPECT_EQ(0, messages[0].lparam());
EXPECT_EQ(WM_IME_COMPOSITION, messages[1].message());
EXPECT_EQ(0, messages[1].wparam());
// When the preedit is updated, the following flags should be sent
// regardless of which field is actually updated. Otherwise, some
// applications such as wordpad OOo Writer 3.0 will not update composition
// window and caret state properly.
EXPECT_EQ((GCS_COMPREADSTR | GCS_COMPREADATTR | GCS_COMPREADCLAUSE |
GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE | GCS_CURSORPOS |
GCS_DELTASTART),
messages[1].lparam());
EXPECT_EQ(0, compstr.focused_character_index_);
EXPECT_EQ(2, compstr.info.dwCompReadAttrLen);
EXPECT_EQ(8, compstr.info.dwCompReadClauseLen);
EXPECT_EQ(2, compstr.info.dwCompReadStrLen);
EXPECT_EQ(1, compstr.info.dwCompAttrLen);
EXPECT_EQ(8, compstr.info.dwCompClauseLen);
EXPECT_EQ(1, compstr.info.dwCompStrLen);
EXPECT_EQ(1, compstr.info.dwCursorPos);
EXPECT_EQ(0, compstr.info.dwDeltaStart);
EXPECT_EQ(0, compstr.info.dwResultReadClauseLen);
EXPECT_EQ(0, compstr.info.dwResultReadStrLen);
EXPECT_EQ(0, compstr.info.dwResultClauseLen);
EXPECT_EQ(0, compstr.info.dwResultStrLen);
// "ガ"
EXPECT_EQ("\xEF\xBD\xB6\xEF\xBE\x9E", GET_STRING(compstr, CompReadStr));
EXPECT_EQ(ATTR_INPUT, GET_ATTRIBUTE(compstr, CompReadAttr, 0));
EXPECT_EQ(ATTR_INPUT, GET_ATTRIBUTE(compstr, CompReadAttr, 1));
// TODO(yukawa): Check other fields in |compstr.info|
}
TEST(ImeCompositionStringTest, EndCompositionWhenCompositionBecomesEmpty) {
// WM_IME_COMPOSITION should be sent with setting 0 to wparam and lparam.
// Otherwise, OOo 3.0.1 will not show the caret again.
CompositionString compstr;
EXPECT_TRUE(compstr.Initialize());
compstr.info.dwCompStrLen = 1;
compstr.info.dwCompReadStrLen = 1;
commands::Output output;
output.set_consumed(true);
output.set_mode(mozc::commands::HIRAGANA);
output.mutable_status()->set_activated(true);
output.mutable_status()->set_mode(mozc::commands::HIRAGANA);
vector<UIMessage> messages;
EXPECT_TRUE(compstr.Update(output, &messages));
EXPECT_EQ(2, messages.size());
EXPECT_EQ(WM_IME_COMPOSITION, messages[0].message());
EXPECT_EQ(0, messages[0].wparam());
EXPECT_EQ(0, messages[0].lparam());
EXPECT_EQ(WM_IME_ENDCOMPOSITION, messages[1].message());
EXPECT_EQ(0, messages[1].wparam());
EXPECT_EQ(0, messages[1].lparam());
EXPECT_EQ(0, compstr.focused_character_index_);
EXPECT_EQ(0, compstr.info.dwCompReadAttrLen);
EXPECT_EQ(0, compstr.info.dwCompReadClauseLen);
EXPECT_EQ(0, compstr.info.dwCompReadStrLen);
EXPECT_EQ(0, compstr.info.dwCompAttrLen);
EXPECT_EQ(0, compstr.info.dwCompClauseLen);
EXPECT_EQ(0, compstr.info.dwCompStrLen);
EXPECT_EQ(-1, compstr.info.dwCursorPos);
EXPECT_EQ(0, compstr.info.dwDeltaStart);
EXPECT_EQ(0, compstr.info.dwResultReadClauseLen);
EXPECT_EQ(0, compstr.info.dwResultReadStrLen);
EXPECT_EQ(0, compstr.info.dwResultClauseLen);
EXPECT_EQ(0, compstr.info.dwResultStrLen);
}
TEST(ImeCompositionStringTest, EndCompositionWhenCompositionIsCommited) {
// WM_IME_COMPOSITION should be sent up to once.
// Otherwise, the result string will be commited twice in wordpad.exe.
CompositionString compstr;
EXPECT_TRUE(compstr.Initialize());
compstr.info.dwCompStrLen = 1;
compstr.info.dwCompReadStrLen = 1;
commands::Output output;
output.set_consumed(true);
output.set_mode(mozc::commands::HIRAGANA);
output.mutable_status()->set_activated(true);
output.mutable_status()->set_mode(mozc::commands::HIRAGANA);
commands::Result *result = output.mutable_result();
// "が"
result->set_key("\xE3\x81\x8C");
// "が"
result->set_value("\xE3\x81\x8C");
result->set_type(mozc::commands::Result::STRING);
vector<UIMessage> messages;
EXPECT_TRUE(compstr.Update(output, &messages));
EXPECT_EQ(2, messages.size());
EXPECT_EQ(WM_IME_COMPOSITION, messages[0].message());
EXPECT_EQ(0, messages[0].wparam());
// When the result string is updated, the following flags should be sent
// regardless of which field is actually updated. Otherwise, some
// applications such as wordpad OOo Writer 3.0 will not update composition
// window and caret state properly.
EXPECT_EQ((GCS_RESULTREADSTR | GCS_RESULTREADCLAUSE | GCS_RESULTSTR |
GCS_RESULTCLAUSE),
messages[0].lparam());
EXPECT_EQ(WM_IME_ENDCOMPOSITION, messages[1].message());
EXPECT_EQ(0, messages[1].wparam());
EXPECT_EQ(0, messages[1].lparam());
EXPECT_EQ(0, compstr.focused_character_index_);
EXPECT_EQ(0, compstr.info.dwCompReadAttrLen);
EXPECT_EQ(0, compstr.info.dwCompReadClauseLen);
EXPECT_EQ(0, compstr.info.dwCompReadStrLen);
EXPECT_EQ(0, compstr.info.dwCompAttrLen);
EXPECT_EQ(0, compstr.info.dwCompClauseLen);
EXPECT_EQ(0, compstr.info.dwCompStrLen);
EXPECT_EQ(-1, compstr.info.dwCursorPos);
EXPECT_EQ(0, compstr.info.dwDeltaStart);
EXPECT_EQ(8, compstr.info.dwResultReadClauseLen);
EXPECT_EQ(2, compstr.info.dwResultReadStrLen);
EXPECT_EQ(8, compstr.info.dwResultClauseLen);
EXPECT_EQ(1, compstr.info.dwResultStrLen);
// "ガ"
EXPECT_EQ("\xEF\xBD\xB6\xEF\xBE\x9E", GET_STRING(compstr, ResultReadStr));
}
TEST(ImeCompositionStringTest, SpaceKeyWhenIMEIsTurnedOn_Issue3200585) {
// If the current state is no composition and the server returns a result
// string, it should be interpreted as one-shot composition as follows.
// WM_IME_STARTCOMPOSITION
// -> WM_IME_COMPOSITION
// -> WM_IME_ENDCOMPOSITION
// Otherwise, you cannot input Full-width space on Outlook 2010. (b/3200585)
CompositionString compstr;
EXPECT_TRUE(compstr.Initialize());
commands::Output output;
// Emulate special_key::SPACE key when IME is turned on.
output.set_mode(mozc::commands::HIRAGANA);
output.set_consumed(true);
output.mutable_result()->set_key(" ");
output.mutable_result()->set_value("\343\200\200"); // Full-width space
output.mutable_result()->set_type(mozc::commands::Result::STRING);
output.mutable_status()->set_activated(true);
output.mutable_status()->set_mode(mozc::commands::HIRAGANA);
vector<UIMessage> messages;
EXPECT_TRUE(compstr.Update(output, &messages));
EXPECT_EQ(3, messages.size());
EXPECT_EQ(WM_IME_STARTCOMPOSITION, messages[0].message());
EXPECT_EQ(0, messages[0].wparam());
EXPECT_EQ(0, messages[0].lparam());
EXPECT_EQ(WM_IME_COMPOSITION, messages[1].message());
EXPECT_EQ(0, messages[1].wparam());
EXPECT_EQ((GCS_RESULTREADSTR | GCS_RESULTREADCLAUSE | GCS_RESULTSTR |
GCS_RESULTCLAUSE),
messages[1].lparam());
EXPECT_EQ(WM_IME_ENDCOMPOSITION, messages[2].message());
EXPECT_EQ(0, messages[2].wparam());
EXPECT_EQ(0, messages[2].lparam());
EXPECT_EQ(0, compstr.focused_character_index_);
EXPECT_EQ(0, compstr.info.dwCompReadAttrLen);
EXPECT_EQ(0, compstr.info.dwCompReadClauseLen);
EXPECT_EQ(0, compstr.info.dwCompReadStrLen);
EXPECT_EQ(0, compstr.info.dwCompAttrLen);
EXPECT_EQ(0, compstr.info.dwCompClauseLen);
EXPECT_EQ(0, compstr.info.dwCompStrLen);
EXPECT_EQ(-1, compstr.info.dwCursorPos);
EXPECT_EQ(0, compstr.info.dwDeltaStart);
EXPECT_EQ(8, compstr.info.dwResultReadClauseLen);
EXPECT_EQ(1, compstr.info.dwResultReadStrLen);
EXPECT_EQ(8, compstr.info.dwResultClauseLen);
EXPECT_EQ(1, compstr.info.dwResultStrLen);
// " "
EXPECT_EQ("\343\200\200", GET_STRING(compstr, ResultStr));
// " "
EXPECT_EQ(" ", GET_STRING(compstr, ResultReadStr));
}
TEST(ImeCompositionStringTest,
EndCompositionWhenCompositionIsCommitedWithPreedit) {
// WM_IME_COMPOSITION should be sent up to once.
// Otherwise, the result string will be commited twice in wordpad.exe.
CompositionString compstr;
EXPECT_TRUE(compstr.Initialize());
compstr.info.dwCompStrLen = 1;
compstr.info.dwCompReadStrLen = 1;
commands::Output output;
output.set_consumed(true);
output.set_mode(mozc::commands::HIRAGANA);
output.mutable_status()->set_activated(true);
output.mutable_status()->set_mode(mozc::commands::HIRAGANA);
commands::Result *result = output.mutable_result();
// "が"
result->set_key("\xE3\x81\x8C");
// "が"
result->set_value("\xE3\x81\x8C");
result->set_type(mozc::commands::Result::STRING);
commands::Preedit *preedit = output.mutable_preedit();
preedit->set_cursor(1);
commands::Preedit::Segment *segment = preedit->add_segment();
segment->set_annotation(commands::Preedit::Segment::UNDERLINE);
// "が"
segment->set_key("\xE3\x81\x8C");
// "が"
segment->set_value("\xE3\x81\x8C");
segment->set_value_length(1);
vector<UIMessage> messages;
EXPECT_TRUE(compstr.Update(output, &messages));
EXPECT_EQ(1, messages.size());
EXPECT_EQ(WM_IME_COMPOSITION, messages[0].message());
EXPECT_EQ(0, messages[0].wparam());
// When both the preedit and result string is updated, the following flags
// should be sent regardless of which field is actually updated. Otherwise,
// some applications such as wordpad OOo Writer 3.0 will not update
// composition window and caret state properly.
EXPECT_EQ((GCS_COMPREADSTR | GCS_COMPREADATTR | GCS_COMPREADCLAUSE |
GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE | GCS_CURSORPOS |
GCS_DELTASTART) |
(GCS_RESULTREADSTR | GCS_RESULTREADCLAUSE | GCS_RESULTSTR |
GCS_RESULTCLAUSE),
messages[0].lparam());
EXPECT_EQ(0, compstr.focused_character_index_);
EXPECT_EQ(2, compstr.info.dwCompReadAttrLen);
EXPECT_EQ(8, compstr.info.dwCompReadClauseLen);
EXPECT_EQ(2, compstr.info.dwCompReadStrLen);
EXPECT_EQ(1, compstr.info.dwCompAttrLen);
EXPECT_EQ(8, compstr.info.dwCompClauseLen);
EXPECT_EQ(1, compstr.info.dwCompStrLen);
EXPECT_EQ(1, compstr.info.dwCursorPos);
EXPECT_EQ(0, compstr.info.dwDeltaStart);
EXPECT_EQ(8, compstr.info.dwResultReadClauseLen);
EXPECT_EQ(2, compstr.info.dwResultReadStrLen);
EXPECT_EQ(8, compstr.info.dwResultClauseLen);
EXPECT_EQ(1, compstr.info.dwResultStrLen);
// "ガ"
EXPECT_EQ("\xEF\xBD\xB6\xEF\xBE\x9E", GET_STRING(compstr, CompReadStr));
// "ガ"
EXPECT_EQ("\xEF\xBD\xB6\xEF\xBE\x9E", GET_STRING(compstr, ResultReadStr));
EXPECT_EQ(ATTR_INPUT, GET_ATTRIBUTE(compstr, CompReadAttr, 0));
EXPECT_EQ(ATTR_INPUT, GET_ATTRIBUTE(compstr, CompReadAttr, 1));
}
TEST(ImeCompositionStringTest, Suggest) {
commands::Output output;
FillOutputForSuggestion(&output);
CompositionString compstr;
EXPECT_TRUE(compstr.Initialize());
vector<UIMessage> messages;
EXPECT_TRUE(compstr.Update(output, &messages));
EXPECT_EQ(2, messages.size());
EXPECT_EQ(WM_IME_STARTCOMPOSITION, messages[0].message());
EXPECT_EQ(0, messages[0].wparam());
EXPECT_EQ(0, messages[0].lparam());
EXPECT_EQ(WM_IME_COMPOSITION, messages[1].message());
EXPECT_EQ(0, messages[1].wparam());
// When the preedit is updated, the following flags should be sent
// regardless of which field is actually updated. Otherwise, some
// applications such as wordpad OOo Writer 3.0 will not update composition
// window and caret state properly.
EXPECT_EQ((GCS_COMPREADSTR | GCS_COMPREADATTR | GCS_COMPREADCLAUSE |
GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE | GCS_CURSORPOS |
GCS_DELTASTART),
messages[1].lparam());
EXPECT_EQ(0, compstr.focused_character_index_);
EXPECT_EQ(4, compstr.info.dwCompReadAttrLen);
EXPECT_EQ(8, compstr.info.dwCompReadClauseLen);
EXPECT_EQ(4, compstr.info.dwCompReadStrLen);
EXPECT_EQ(4, compstr.info.dwCompAttrLen);
EXPECT_EQ(8, compstr.info.dwCompClauseLen);
EXPECT_EQ(4, compstr.info.dwCompStrLen);
EXPECT_EQ(4, compstr.info.dwCursorPos);
EXPECT_EQ(0, compstr.info.dwDeltaStart);
EXPECT_EQ(0, compstr.info.dwResultReadClauseLen);
EXPECT_EQ(0, compstr.info.dwResultReadStrLen);
EXPECT_EQ(0, compstr.info.dwResultClauseLen);
EXPECT_EQ(0, compstr.info.dwResultStrLen);
// "アルファ"
EXPECT_EQ("\357\275\261\357\276\231\357\276\214\357\275\247",
GET_STRING(compstr, CompReadStr));
EXPECT_EQ("\343\201\202\343\202\213\343\201\265\343\201\201",
GET_STRING(compstr, CompStr));
EXPECT_EQ(ATTR_INPUT, GET_ATTRIBUTE(compstr, CompReadAttr, 0));
EXPECT_EQ(ATTR_INPUT, GET_ATTRIBUTE(compstr, CompReadAttr, 1));
EXPECT_EQ(ATTR_INPUT, GET_ATTRIBUTE(compstr, CompReadAttr, 2));
EXPECT_EQ(ATTR_INPUT, GET_ATTRIBUTE(compstr, CompReadAttr, 3));
EXPECT_EQ(ATTR_INPUT, GET_ATTRIBUTE(compstr, CompAttr, 0));
EXPECT_EQ(ATTR_INPUT, GET_ATTRIBUTE(compstr, CompAttr, 1));
EXPECT_EQ(ATTR_INPUT, GET_ATTRIBUTE(compstr, CompAttr, 2));
EXPECT_EQ(ATTR_INPUT, GET_ATTRIBUTE(compstr, CompAttr, 3));
}
TEST(ImeCompositionStringTest, Predict) {
commands::Output output;
FillOutputForPrediction(&output);
CompositionString compstr;
EXPECT_TRUE(compstr.Initialize());
vector<UIMessage> messages;
EXPECT_TRUE(compstr.Update(output, &messages));
EXPECT_EQ(2, messages.size());
EXPECT_EQ(WM_IME_STARTCOMPOSITION, messages[0].message());
EXPECT_EQ(0, messages[0].wparam());
EXPECT_EQ(0, messages[0].lparam());
EXPECT_EQ(WM_IME_COMPOSITION, messages[1].message());
EXPECT_EQ(0, messages[1].wparam());
// When the preedit is updated, the following flags should be sent
// regardless of which field is actually updated. Otherwise, some
// applications such as wordpad OOo Writer 3.0 will not update composition
// window and caret state properly.
EXPECT_EQ((GCS_COMPREADSTR | GCS_COMPREADATTR | GCS_COMPREADCLAUSE |
GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE | GCS_CURSORPOS |
GCS_DELTASTART),
messages[1].lparam());
EXPECT_EQ(0, compstr.focused_character_index_);
EXPECT_EQ(4, compstr.info.dwCompReadAttrLen);
EXPECT_EQ(8, compstr.info.dwCompReadClauseLen);
EXPECT_EQ(4, compstr.info.dwCompReadStrLen);
EXPECT_EQ(9, compstr.info.dwCompAttrLen);
EXPECT_EQ(8, compstr.info.dwCompClauseLen);
EXPECT_EQ(9, compstr.info.dwCompStrLen);
EXPECT_EQ(9, compstr.info.dwCursorPos);
EXPECT_EQ(0, compstr.info.dwDeltaStart);
EXPECT_EQ(0, compstr.info.dwResultReadClauseLen);
EXPECT_EQ(0, compstr.info.dwResultReadStrLen);
EXPECT_EQ(0, compstr.info.dwResultClauseLen);
EXPECT_EQ(0, compstr.info.dwResultStrLen);
// "アルファ"
EXPECT_EQ("\357\275\261\357\276\231\357\276\214\357\275\247",
GET_STRING(compstr, CompReadStr));
EXPECT_EQ("AlphaBeta", GET_STRING(compstr, CompStr));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 0));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 1));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 2));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 3));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 0));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 1));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 2));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 3));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 4));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 5));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 6));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 7));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 8));
}
TEST(ImeCompositionStringTest, Convert) {
commands::Output output;
CompositionString compstr;
EXPECT_TRUE(compstr.Initialize());
// First conversion
// It is common for traditional IMEs not to display candidate window for the
// first conversion. These IMEs do not fill CandidateInfo for the first
// conversiontoo, too. See b/2978825 for details. Mozc server conforms
// to this behavior by keeping |output.candidates()| empty for the first
// conversion.
FillOutputForConversion(&output, 0, false);
{
vector<UIMessage> messages;
EXPECT_TRUE(compstr.Update(output, &messages));
EXPECT_EQ(2, messages.size());
EXPECT_EQ(WM_IME_STARTCOMPOSITION, messages[0].message());
EXPECT_EQ(0, messages[0].wparam());
EXPECT_EQ(0, messages[0].lparam());
EXPECT_EQ(WM_IME_COMPOSITION, messages[1].message());
EXPECT_EQ(0, messages[1].wparam());
// When the preedit is updated, the following flags should be sent
// regardless of which field is actually updated. Otherwise, some
// applications such as wordpad OOo Writer 3.0 will not update composition
// window and caret state properly.
EXPECT_EQ((GCS_COMPREADSTR | GCS_COMPREADATTR | GCS_COMPREADCLAUSE |
GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE | GCS_CURSORPOS |
GCS_DELTASTART),
messages[1].lparam());
EXPECT_EQ(5, compstr.focused_character_index_);
EXPECT_EQ(8, compstr.info.dwCompReadAttrLen);
EXPECT_EQ(12, compstr.info.dwCompReadClauseLen);
EXPECT_EQ(8, compstr.info.dwCompReadStrLen);
EXPECT_EQ(9, compstr.info.dwCompAttrLen);
EXPECT_EQ(12, compstr.info.dwCompClauseLen);
EXPECT_EQ(9, compstr.info.dwCompStrLen);
EXPECT_EQ(5, compstr.info.dwCursorPos);
EXPECT_EQ(0, compstr.info.dwDeltaStart);
EXPECT_EQ(0, compstr.info.dwResultReadClauseLen);
EXPECT_EQ(0, compstr.info.dwResultReadStrLen);
EXPECT_EQ(0, compstr.info.dwResultClauseLen);
EXPECT_EQ(0, compstr.info.dwResultStrLen);
// "アルファベータ"
EXPECT_EQ("\357\275\261\357\276\231\357\276\214\357\275\247"
"\357\276\215\357\276\236\357\275\260\357\276\200",
GET_STRING(compstr, CompReadStr));
EXPECT_EQ("AlphaBeta", GET_STRING(compstr, CompStr));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 0));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 1));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 2));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 3));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 4));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 5));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 6));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 7));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 0));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 1));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 2));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 3));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 4));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 5));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 6));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 7));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 8));
}
// Second conversion
FillOutputForConversion(&output, 1, true);
{
vector<UIMessage> messages;
EXPECT_TRUE(compstr.Update(output, &messages));
EXPECT_EQ(1, messages.size());
EXPECT_EQ(WM_IME_COMPOSITION, messages[0].message());
EXPECT_EQ(0, messages[0].wparam());
// When the preedit is updated, the following flags should be sent
// regardless of which field is actually updated. Otherwise, some
// applications such as wordpad OOo Writer 3.0 will not update composition
// window and caret state properly.
EXPECT_EQ((GCS_COMPREADSTR | GCS_COMPREADATTR | GCS_COMPREADCLAUSE |
GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE | GCS_CURSORPOS |
GCS_DELTASTART),
messages[0].lparam());
EXPECT_EQ(5, compstr.focused_character_index_);
EXPECT_EQ(8, compstr.info.dwCompReadAttrLen);
EXPECT_EQ(12, compstr.info.dwCompReadClauseLen);
EXPECT_EQ(8, compstr.info.dwCompReadStrLen);
EXPECT_EQ(8, compstr.info.dwCompAttrLen);
EXPECT_EQ(12, compstr.info.dwCompClauseLen);
EXPECT_EQ(8, compstr.info.dwCompStrLen);
EXPECT_EQ(5, compstr.info.dwCursorPos);
EXPECT_EQ(0, compstr.info.dwDeltaStart);
EXPECT_EQ(0, compstr.info.dwResultReadClauseLen);
EXPECT_EQ(0, compstr.info.dwResultReadStrLen);
EXPECT_EQ(0, compstr.info.dwResultClauseLen);
EXPECT_EQ(0, compstr.info.dwResultStrLen);
// "アルファベータ"
EXPECT_EQ("\357\275\261\357\276\231\357\276\214\357\275\247"
"\357\276\215\357\276\236\357\275\260\357\276\200",
GET_STRING(compstr, CompReadStr));
// "Alphaベータ"
EXPECT_EQ("Alpha\343\203\231\343\203\274\343\202\277",
GET_STRING(compstr, CompStr));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 0));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 1));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 2));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 3));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 4));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 5));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 6));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 7));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 0));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 1));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 2));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 3));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 4));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 5));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 6));
EXPECT_EQ(ATTR_TARGET_CONVERTED, GET_ATTRIBUTE(compstr, CompAttr, 7));
}
}
// Check if surrogate-pair is handled properly. See b/4163234 and b/4159275
// for details.
TEST(ImeCompositionStringTest, SurrogatePairSupport) {
CompositionString compstr;
EXPECT_TRUE(compstr.Initialize());
commands::Output output;
output.set_mode(commands::HIRAGANA);
output.set_consumed(true);
{
commands::Preedit *preedit = output.mutable_preedit();
preedit->set_cursor(5);
{
commands::Preedit::Segment *segment = preedit->add_segment();
segment->set_annotation(commands::Preedit::Segment::UNDERLINE);
// "𠮟る" (U+20B9F)
segment->set_value("\360\240\256\237\343\202\213");
segment->set_value_length(2);
// "しかる"
segment->set_key("\343\201\227\343\201\213\343\202\213");
}
{
commands::Preedit::Segment *segment = preedit->add_segment();
segment->set_annotation(commands::Preedit::Segment::UNDERLINE);
// "と"
segment->set_value("\343\201\250");
segment->set_value_length(1);
// "と"
segment->set_key("\343\201\250");
}
{
commands::Preedit::Segment *segment = preedit->add_segment();
segment->set_annotation(commands::Preedit::Segment::HIGHLIGHT);
// "叱る" (U+53F1)
segment->set_value("\345\217\261\343\202\213");
segment->set_value_length(2);
// "しかる"
segment->set_key("\343\201\227\343\201\213\343\202\213");
}
preedit->set_highlighted_position(3);
}
{
commands::Status *status = output.mutable_status();
status->set_activated(true);
status->set_mode(commands::HIRAGANA);
}
vector<UIMessage> messages;
EXPECT_TRUE(compstr.Update(output, &messages));
// Here, |focused_character_index_| != Preedit::highlighted_position()
// because of surrogate parir.
EXPECT_EQ(4, compstr.focused_character_index_);
EXPECT_EQ(7, compstr.info.dwCompReadAttrLen);
EXPECT_EQ(16, compstr.info.dwCompReadClauseLen);
EXPECT_EQ(7, compstr.info.dwCompReadStrLen);
EXPECT_EQ(6, compstr.info.dwCompAttrLen);
EXPECT_EQ(16, compstr.info.dwCompClauseLen);
EXPECT_EQ(6, compstr.info.dwCompStrLen);
EXPECT_EQ(4, compstr.info.dwCursorPos);
EXPECT_EQ(0, compstr.info.dwDeltaStart);
EXPECT_EQ(0, compstr.info.dwResultReadClauseLen);
EXPECT_EQ(0, compstr.info.dwResultReadStrLen);
EXPECT_EQ(0, compstr.info.dwResultClauseLen);
EXPECT_EQ(0, compstr.info.dwResultStrLen);
// "シカルトシカル"
EXPECT_EQ("\357\275\274\357\275\266\357\276\231"
"\357\276\204"
"\357\275\274\357\275\266\357\276\231",
GET_STRING(compstr, CompReadStr));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 0));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 1));
EXPECT_EQ(ATTR_CONVERTED, GET_ATTRIBUTE(compstr, CompReadAttr, 2));
// TODO(yukawa): Check other fields in |compstr.info|
}
} // namespace win32
} // namespace mozc