| // 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/internal/composition.h" |
| |
| #include <algorithm> |
| #include <set> |
| #include <string> |
| |
| #include "composer/internal/char_chunk.h" |
| #include "composer/internal/composition_input.h" |
| #include "composer/internal/transliterators.h" |
| #include "composer/table.h" |
| #include "testing/base/public/gunit.h" |
| |
| namespace mozc { |
| namespace composer { |
| |
| namespace { |
| |
| string GetString(const Composition &composition) { |
| string output; |
| composition.GetString(&output); |
| return output; |
| } |
| |
| string GetRawString(const Composition &composition) { |
| string output; |
| composition.GetStringWithTransliterator(Transliterators::RAW_STRING, &output); |
| return output; |
| } |
| |
| void SetInput(const string &raw, |
| const string &conversion, |
| const bool is_new_input, |
| CompositionInput *input) { |
| input->Clear(); |
| input->set_raw(raw); |
| if (!conversion.empty()) { |
| input->set_conversion(conversion); |
| } |
| input->set_is_new_input(is_new_input); |
| } |
| |
| size_t InsertCharacters(const string &input, |
| size_t pos, |
| Composition *composition) { |
| for (size_t i = 0; i < input.size(); ++i) { |
| pos = composition->InsertAt(pos, input.substr(i, 1)); |
| } |
| return pos; |
| } |
| |
| } // anonymous namespace |
| |
| class CompositionTest : public testing::Test { |
| protected: |
| virtual void SetUp() { |
| table_.reset(new Table); |
| composition_.reset(new Composition(table_.get())); |
| composition_->SetInputMode(Transliterators::CONVERSION_STRING); |
| } |
| |
| scoped_ptr<Table> table_; |
| scoped_ptr<Composition> composition_; |
| }; |
| |
| static int InitComposition(Composition* comp) { |
| static const struct TestCharChunk { |
| const char* conversion; |
| const char* pending; |
| const char* raw; |
| } test_chunks[] = { |
| // "あ ky き った っty" (9 chars) |
| // a ky ki tta tty |
| // "あ" |
| { "\xe3\x81\x82", "", "a" }, |
| { "", "ky", "ky" }, |
| // "き" |
| { "\xe3\x81\x8d", "", "ki" }, |
| // "った" |
| { "\xe3\x81\xa3\xe3\x81\x9f", "", "tta" }, |
| // "っ" |
| { "\xe3\x81\xa3", "ty", "tty" }, |
| }; |
| static const int test_chunks_size = arraysize(test_chunks); |
| CharChunkList::iterator it; |
| comp->MaybeSplitChunkAt(0, &it); |
| for (int i = 0; i < test_chunks_size; ++i) { |
| const TestCharChunk& data = test_chunks[i]; |
| CharChunk* chunk = *comp->InsertChunk(&it); |
| chunk->set_conversion(data.conversion); |
| chunk->set_pending(data.pending); |
| chunk->set_raw(data.raw); |
| } |
| return test_chunks_size; |
| } |
| |
| static CharChunk *AppendChunk(const char *conversion, |
| const char *pending, |
| const char *raw, |
| Composition *comp) { |
| CharChunkList::iterator it; |
| comp->MaybeSplitChunkAt(comp->GetLength(), &it); |
| |
| CharChunk* chunk = *comp->InsertChunk(&it); |
| chunk->set_conversion(conversion); |
| chunk->set_pending(pending); |
| chunk->set_raw(raw); |
| return chunk; |
| } |
| |
| TEST_F(CompositionTest, GetChunkLength) { |
| static const struct TestCase { |
| const char* conversion; |
| const char* pending; |
| const char* raw; |
| const int expected_conv_length; |
| const int expected_raw_length; |
| } test_cases[] = { |
| // "あ" |
| { "\xe3\x81\x82", "", "a", 1, 1 }, |
| { "", "ky", "ky", 2, 2 }, |
| // "き" |
| { "\xe3\x81\x8d", "", "ki", 1, 2 }, |
| // "った" |
| { "\xe3\x81\xa3\xe3\x81\x9f", "", "tta", 2, 3 }, |
| // "っ" |
| { "\xe3\x81\xa3", "ty", "tty", 3, 3 }, |
| }; |
| CharChunk *chunk = AppendChunk("", "", "", composition_.get()); |
| |
| for (int i = 0; i < arraysize(test_cases); ++i) { |
| const TestCase& test = test_cases[i]; |
| chunk->set_conversion(test.conversion); |
| chunk->set_pending(test.pending); |
| chunk->set_raw(test.raw); |
| |
| const int conv_length = |
| chunk->GetLength(Transliterators::CONVERSION_STRING); |
| EXPECT_EQ(test.expected_conv_length, conv_length); |
| |
| const int raw_length = chunk->GetLength(Transliterators::RAW_STRING); |
| EXPECT_EQ(test.expected_raw_length, raw_length); |
| } |
| } |
| |
| namespace { |
| bool TestGetChunkAt(Composition *comp, |
| Transliterators::Transliterator transliterator, |
| const size_t index, |
| const size_t expected_index, |
| const size_t expected_inner_position) { |
| CharChunkList::iterator it; |
| CharChunkList::const_iterator expected_it; |
| size_t inner_position; |
| |
| expected_it = comp->GetCharChunkList().begin(); |
| for (int j = 0; j < expected_index; ++j, ++expected_it) {} |
| |
| comp->GetChunkAt(index, transliterator, &it, &inner_position); |
| if (it == comp->GetCharChunkList().end()) { |
| EXPECT_TRUE(expected_it == it); |
| EXPECT_EQ(expected_inner_position, inner_position); |
| } else { |
| string result, expected_result; |
| EXPECT_EQ((*expected_it)->conversion(), (*it)->conversion()); |
| EXPECT_EQ((*expected_it)->pending(), (*it)->pending()); |
| EXPECT_EQ((*expected_it)->raw(), (*it)->raw()); |
| EXPECT_EQ(expected_inner_position, inner_position); |
| } |
| return true; |
| } |
| } // anonymous namespace |
| |
| TEST_F(CompositionTest, GetChunkAt) { |
| InitComposition(composition_.get()); |
| |
| TestGetChunkAt(composition_.get(), |
| Transliterators::CONVERSION_STRING, 0, 0, 0); |
| TestGetChunkAt(composition_.get(), |
| Transliterators::CONVERSION_STRING, 1, 0, 1); |
| TestGetChunkAt(composition_.get(), |
| Transliterators::CONVERSION_STRING, 2, 1, 1); |
| TestGetChunkAt(composition_.get(), |
| Transliterators::CONVERSION_STRING, 3, 1, 2); |
| TestGetChunkAt(composition_.get(), |
| Transliterators::CONVERSION_STRING, 4, 2, 1); |
| TestGetChunkAt(composition_.get(), |
| Transliterators::CONVERSION_STRING, 5, 3, 1); |
| TestGetChunkAt(composition_.get(), |
| Transliterators::CONVERSION_STRING, 6, 3, 2); |
| TestGetChunkAt(composition_.get(), |
| Transliterators::CONVERSION_STRING, 7, 4, 1); |
| TestGetChunkAt(composition_.get(), |
| Transliterators::CONVERSION_STRING, 8, 4, 2); |
| TestGetChunkAt(composition_.get(), |
| Transliterators::CONVERSION_STRING, 9, 4, 3); |
| // end |
| TestGetChunkAt(composition_.get(), |
| Transliterators::CONVERSION_STRING, 10, 4, 3); |
| // end |
| TestGetChunkAt(composition_.get(), |
| Transliterators::CONVERSION_STRING, 11, 4, 3); |
| |
| TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 0, 0, 0); |
| TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 1, 0, 1); |
| TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 2, 1, 1); |
| TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 3, 1, 2); |
| TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 4, 2, 1); |
| TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 5, 2, 2); |
| TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 6, 3, 1); |
| TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 7, 3, 2); |
| TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 8, 3, 3); |
| TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 9, 4, 1); |
| TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 10, 4, 2); |
| TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 11, 4, 3); |
| // end |
| TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 12, 4, 3); |
| // end |
| TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 13, 4, 3); |
| } |
| |
| TEST_F(CompositionTest, GetString) { |
| InitComposition(composition_.get()); |
| string composition; |
| |
| const size_t dummy_position = 0; |
| |
| // Test RAW mode |
| composition_->SetDisplayMode(dummy_position, Transliterators::RAW_STRING); |
| composition_->GetString(&composition); |
| EXPECT_EQ("akykittatty", composition); |
| |
| // Test CONVERSION mode |
| composition_->SetDisplayMode(dummy_position, |
| Transliterators::CONVERSION_STRING); |
| composition_->GetString(&composition); |
| // "あkyきったっty" |
| EXPECT_EQ("\xe3\x81\x82\x6b\x79\xe3\x81\x8d\xe3\x81\xa3\xe3\x81\x9f\xe3\x81" |
| "\xa3\x74\x79", composition); |
| } |
| |
| TEST_F(CompositionTest, GetStringWithDisplayMode) { |
| // "も" |
| AppendChunk("\xe3\x82\x82", "", "mo", composition_.get()); |
| // "ず" |
| AppendChunk("\xe3\x81\x9a", "", "z", composition_.get()); |
| // "く" |
| AppendChunk("\xe3\x81\x8f", "", "c", composition_.get()); |
| |
| string composition; |
| composition_->GetStringWithTransliterator(Transliterators::CONVERSION_STRING, |
| &composition); |
| // "もずく" |
| EXPECT_EQ("\xe3\x82\x82\xe3\x81\x9a\xe3\x81\x8f", composition); |
| |
| composition_->GetStringWithTransliterator(Transliterators::RAW_STRING, |
| &composition); |
| EXPECT_EQ("mozc", composition); |
| } |
| |
| TEST_F(CompositionTest, SplitRawChunk) { |
| static const struct TestCase { |
| const char* conversion; |
| const char* pending; |
| const char* raw; |
| const int position; |
| const char* expected_left_conversion; |
| const char* expected_left_pending; |
| const char* expected_left_raw; |
| const char* expected_right_conversion; |
| const char* expected_right_pending; |
| const char* expected_right_raw; |
| } test_cases[] = { |
| // "あ", "あ" |
| { "\xe3\x81\x82", "", "a", 0, "", "", "", "\xe3\x81\x82", "", "a" }, |
| { "", "ky", "ky", 1, "", "k", "k", "", "y", "y" }, |
| // "き" |
| { "\xe3\x81\x8d", "", "ki", 1, "k", "", "k", "i", "", "i" }, |
| // "った" |
| { "\xe3\x81\xa3\xe3\x81\x9f", "", "tta", 1, "t", "", "t", "ta", "", "ta" }, |
| // "った" |
| { "\xe3\x81\xa3\xe3\x81\x9f", "", "tta", 2, "tt", "", "tt", "a", "", "a" }, |
| // "っ", "っ" |
| { "\xe3\x81\xa3", "ty", "tty", 1, "\xe3\x81\xa3", "", "t", "", "ty", "ty" }, |
| // "っ", "っ" |
| { "\xe3\x81\xa3", "ty", "tty", 2, "\xe3\x81\xa3", "t", "tt", "", "y", "y" }, |
| // "っ", "っ" |
| { "\xe3\x81\xa3", "ty", "tty", 3, "", "", "", "\xe3\x81\xa3", "ty", "tty" }, |
| }; |
| for (int i = 0; i < arraysize(test_cases); ++i) { |
| const TestCase& test = test_cases[i]; |
| CharChunk right_orig_chunk(Transliterators::CONVERSION_STRING, NULL); |
| right_orig_chunk.set_conversion(test.conversion); |
| right_orig_chunk.set_pending(test.pending); |
| right_orig_chunk.set_raw(test.raw); |
| CharChunk *left_new_chunk_ptr = NULL; |
| right_orig_chunk.SplitChunk(Transliterators::RAW_STRING, |
| test.position, &left_new_chunk_ptr); |
| scoped_ptr<CharChunk> left_new_chunk(left_new_chunk_ptr); |
| |
| if (left_new_chunk.get() != NULL) { |
| EXPECT_EQ(test.expected_left_conversion, left_new_chunk->conversion()); |
| EXPECT_EQ(test.expected_left_pending, left_new_chunk->pending()); |
| EXPECT_EQ(test.expected_left_raw, left_new_chunk->raw()); |
| } |
| |
| EXPECT_EQ(test.expected_right_conversion, right_orig_chunk.conversion()); |
| EXPECT_EQ(test.expected_right_pending, right_orig_chunk.pending()); |
| EXPECT_EQ(test.expected_right_raw, right_orig_chunk.raw()); |
| } |
| } |
| |
| TEST_F(CompositionTest, SplitConversionChunk) { |
| static const struct TestCase { |
| const char* conversion; |
| const char* pending; |
| const char* raw; |
| const int position; |
| const char* expected_left_conversion; |
| const char* expected_left_pending; |
| const char* expected_left_raw; |
| const char* expected_right_conversion; |
| const char* expected_right_pending; |
| const char* expected_right_raw; |
| } test_cases[] = { |
| // "あ", "あ" |
| { "\xe3\x81\x82", "", "a", 0, "", "", "", "\xe3\x81\x82", "", "a" }, |
| { "", "ky", "ky", 1, "", "k", "k", "", "y", "y" }, |
| // "きょ", "き", "き", "ょ", "ょ" |
| { "\xe3\x81\x8d\xe3\x82\x87", "", "kyo", 1, "\xe3\x81\x8d", "", |
| "\xe3\x81\x8d", "\xe3\x82\x87", "", "\xe3\x82\x87" }, |
| // "っ", "っ" |
| { "\xe3\x81\xa3", "t", "tt", 1, "\xe3\x81\xa3", "", "t", "", "t", "t" }, |
| // "った", "っ", "っ", "た", "た" |
| { "\xe3\x81\xa3\xe3\x81\x9f", "", "tta", 1, "\xe3\x81\xa3", "", |
| "\xe3\x81\xa3", "\xe3\x81\x9f", "", "\xe3\x81\x9f" }, |
| // "っ", "っ" |
| { "\xe3\x81\xa3", "ty", "tty", 1, "\xe3\x81\xa3", "", "t", "", "ty", "ty" }, |
| // "っ", "っ" |
| { "\xe3\x81\xa3", "ty", "tty", 2, "\xe3\x81\xa3", "t", "tt", "", "y", "y" }, |
| // "っ", "っ" |
| { "\xe3\x81\xa3", "ty", "tty", 3, "", "", "", "\xe3\x81\xa3", "ty", "tty" }, |
| }; |
| for (int i = 0; i < arraysize(test_cases); ++i) { |
| const TestCase& test = test_cases[i]; |
| CharChunk right_orig_chunk(Transliterators::CONVERSION_STRING, NULL); |
| right_orig_chunk.set_conversion(test.conversion); |
| right_orig_chunk.set_pending(test.pending); |
| right_orig_chunk.set_raw(test.raw); |
| CharChunk *left_new_chunk_ptr = NULL; |
| right_orig_chunk.SplitChunk(Transliterators::CONVERSION_STRING, |
| test.position, &left_new_chunk_ptr); |
| scoped_ptr<CharChunk> left_new_chunk(left_new_chunk_ptr); |
| |
| if (left_new_chunk.get() != NULL) { |
| EXPECT_EQ(test.expected_left_conversion, left_new_chunk->conversion()); |
| EXPECT_EQ(test.expected_left_pending, left_new_chunk->pending()); |
| EXPECT_EQ(test.expected_left_raw, left_new_chunk->raw()); |
| } |
| |
| EXPECT_EQ(test.expected_right_conversion, right_orig_chunk.conversion()); |
| EXPECT_EQ(test.expected_right_pending, right_orig_chunk.pending()); |
| EXPECT_EQ(test.expected_right_raw, right_orig_chunk.raw()); |
| } |
| } |
| |
| TEST_F(CompositionTest, GetLength) { |
| table_->AddRule("a", "A", ""); |
| table_->AddRule("ka", "K", ""); |
| |
| EXPECT_EQ(0, composition_->GetLength()); |
| |
| InsertCharacters("aka", 0, composition_.get()); |
| EXPECT_EQ(2, composition_->GetLength()); |
| } |
| |
| TEST_F(CompositionTest, MaybeSplitChunkAt) { |
| static const struct TestCase { |
| const int position; |
| const int expected_raw_chunks_size; |
| const int expected_conv_chunks_size; |
| } test_cases[] = { |
| // "あ ky き った っty" (9 chars) |
| // a ky ki tta tty (11 chars) |
| { 0, 5, 5 }, |
| { 1, 5, 5 }, |
| { 2, 6, 6 }, |
| { 3, 5, 5 }, |
| { 4, 6, 5 }, |
| { 5, 5, 6 }, |
| { 6, 6, 5 }, |
| { 7, 6, 6 }, |
| { 8, 5, 6 }, |
| { 9, 6, 5 }, |
| { 10, 6, 5 }, |
| { 11, 5, 5 }, |
| { 12, 5, 5 }, |
| }; |
| const size_t dummy_position = 0; |
| for (int i = 0; i < arraysize(test_cases); ++i) { |
| const TestCase& test = test_cases[i]; |
| |
| { // Test RAW mode |
| Composition raw_comp(table_.get()); |
| InitComposition(&raw_comp); |
| raw_comp.SetDisplayMode(dummy_position, Transliterators::RAW_STRING); |
| CharChunkList::iterator raw_it; |
| |
| raw_comp.MaybeSplitChunkAt(test.position, &raw_it); |
| const size_t raw_chunks_size = raw_comp.GetCharChunkList().size(); |
| EXPECT_EQ(test.expected_raw_chunks_size, raw_chunks_size); |
| } |
| |
| { // Test CONVERSION mode |
| Composition conv_comp(table_.get()); |
| InitComposition(&conv_comp); |
| conv_comp.SetDisplayMode(dummy_position, |
| Transliterators::CONVERSION_STRING); |
| CharChunkList::iterator conv_it; |
| |
| conv_comp.MaybeSplitChunkAt(test.position, &conv_it); |
| const size_t conv_chunks_size = conv_comp.GetCharChunkList().size(); |
| EXPECT_EQ(test.expected_conv_chunks_size, conv_chunks_size); |
| } |
| } |
| } |
| |
| namespace { |
| string GetDeletedString(Transliterators::Transliterator t12r, |
| const int position) { |
| scoped_ptr<Table> table(new Table); |
| scoped_ptr<Composition> comp(new Composition(table.get())); |
| |
| InitComposition(comp.get()); |
| comp->SetDisplayMode(0, t12r); |
| comp->DeleteAt(position); |
| string composition; |
| comp->GetString(&composition); |
| |
| comp.reset(); |
| table.reset(); |
| return composition; |
| } |
| } // anonymous namespace |
| |
| TEST_F(CompositionTest, DeleteAt) { |
| // "あkyきったっty" is the original string |
| |
| // "kyきったっty" |
| EXPECT_EQ("\x6b\x79\xe3\x81\x8d\xe3\x81\xa3\xe3\x81\x9f\xe3\x81\xa3\x74\x79", |
| GetDeletedString(Transliterators::CONVERSION_STRING, 0)); |
| // "あyきったっty" |
| EXPECT_EQ("\xe3\x81\x82\x79\xe3\x81\x8d\xe3\x81\xa3\xe3\x81\x9f\xe3\x81\xa3" |
| "\x74\x79", |
| GetDeletedString(Transliterators::CONVERSION_STRING, 1)); |
| // "あkきったっty" |
| EXPECT_EQ("\xe3\x81\x82\x6b\xe3\x81\x8d\xe3\x81\xa3\xe3\x81\x9f\xe3\x81\xa3" |
| "\x74\x79", |
| GetDeletedString(Transliterators::CONVERSION_STRING, 2)); |
| // "あkyったっty" |
| EXPECT_EQ("\xe3\x81\x82\x6b\x79\xe3\x81\xa3\xe3\x81\x9f\xe3\x81\xa3\x74\x79", |
| GetDeletedString(Transliterators::CONVERSION_STRING, 3)); |
| // "あkyきたっty" |
| EXPECT_EQ("\xe3\x81\x82\x6b\x79\xe3\x81\x8d\xe3\x81\x9f\xe3\x81\xa3\x74\x79", |
| GetDeletedString(Transliterators::CONVERSION_STRING, 4)); |
| // "あkyきっっty" |
| EXPECT_EQ("\xe3\x81\x82\x6b\x79\xe3\x81\x8d\xe3\x81\xa3\xe3\x81\xa3\x74\x79", |
| GetDeletedString(Transliterators::CONVERSION_STRING, 5)); |
| // "あkyきったty" |
| EXPECT_EQ("\xe3\x81\x82\x6b\x79\xe3\x81\x8d\xe3\x81\xa3\xe3\x81\x9f\x74\x79", |
| GetDeletedString(Transliterators::CONVERSION_STRING, 6)); |
| // "あkyきったっy" |
| EXPECT_EQ("\xe3\x81\x82\x6b\x79\xe3\x81\x8d\xe3\x81\xa3\xe3\x81\x9f\xe3\x81" |
| "\xa3\x79", |
| GetDeletedString(Transliterators::CONVERSION_STRING, 7)); |
| // "あkyきったっt" |
| EXPECT_EQ("\xe3\x81\x82\x6b\x79\xe3\x81\x8d\xe3\x81\xa3\xe3\x81\x9f\xe3\x81" |
| "\xa3\x74", |
| GetDeletedString(Transliterators::CONVERSION_STRING, 8)); |
| // "あkyきったっty" |
| // end |
| EXPECT_EQ("\xe3\x81\x82\x6b\x79\xe3\x81\x8d\xe3\x81\xa3\xe3\x81\x9f" |
| "\xe3\x81\xa3\x74\x79", |
| GetDeletedString(Transliterators::CONVERSION_STRING, 9)); |
| |
| // "あkyきったっty" |
| EXPECT_EQ("\xe3\x81\x82\x6b\x79\xe3\x81\x8d\xe3\x81\xa3\xe3\x81\x9f" |
| "\xe3\x81\xa3\x74\x79", |
| GetDeletedString(Transliterators::CONVERSION_STRING, -1)); |
| |
| // "akykittatty" is the original string |
| EXPECT_EQ("kykittatty", GetDeletedString(Transliterators::RAW_STRING, 0)); |
| EXPECT_EQ("aykittatty", GetDeletedString(Transliterators::RAW_STRING, 1)); |
| EXPECT_EQ("akkittatty", GetDeletedString(Transliterators::RAW_STRING, 2)); |
| EXPECT_EQ("akyittatty", GetDeletedString(Transliterators::RAW_STRING, 3)); |
| EXPECT_EQ("akykttatty", GetDeletedString(Transliterators::RAW_STRING, 4)); |
| EXPECT_EQ("akykitatty", GetDeletedString(Transliterators::RAW_STRING, 5)); |
| EXPECT_EQ("akykitatty", GetDeletedString(Transliterators::RAW_STRING, 6)); |
| EXPECT_EQ("akykitttty", GetDeletedString(Transliterators::RAW_STRING, 7)); |
| EXPECT_EQ("akykittaty", GetDeletedString(Transliterators::RAW_STRING, 8)); |
| EXPECT_EQ("akykittaty", GetDeletedString(Transliterators::RAW_STRING, 9)); |
| EXPECT_EQ("akykittatt", GetDeletedString(Transliterators::RAW_STRING, 10)); |
| // end |
| EXPECT_EQ("akykittatty", GetDeletedString(Transliterators::RAW_STRING, 11)); |
| EXPECT_EQ("akykittatty", GetDeletedString(Transliterators::RAW_STRING, -1)); |
| } |
| |
| TEST_F(CompositionTest, DeleteAt_InvisibleCharacter) { |
| CharChunkList::iterator it; |
| CharChunk *chunk; |
| |
| composition_->MaybeSplitChunkAt(0, &it); |
| |
| chunk = *composition_->InsertChunk(&it); |
| chunk->set_raw("1"); |
| chunk->set_pending(Table::ParseSpecialKey("{1}")); |
| |
| chunk = *composition_->InsertChunk(&it); |
| chunk->set_raw("2"); |
| chunk->set_pending(Table::ParseSpecialKey("{2}2")); |
| |
| chunk = *composition_->InsertChunk(&it); |
| chunk->set_raw("3"); |
| chunk->set_pending("3"); |
| |
| // Now the CharChunks in the comp are expected to be following; |
| // (raw, pending) = [ ("1", "{1}"), ("2", "{2}2"), ("3", "3") ] |
| // {} means invisible characters. |
| |
| composition_->DeleteAt(0); |
| string composition; |
| composition_->GetString(&composition); |
| EXPECT_EQ("3", composition); |
| } |
| |
| namespace { |
| |
| void InitTable(Table* table) { |
| // "い" |
| table->AddRule("i", "\xe3\x81\x84", ""); |
| // "き" |
| table->AddRule("ki", "\xe3\x81\x8d", ""); |
| // "きぃ" |
| table->AddRule("kyi", "\xe3\x81\x8d\xe3\x81\x83", ""); |
| // "ち" |
| table->AddRule("ti", "\xe3\x81\xa1", ""); |
| // "ちゃ" |
| table->AddRule("tya", "\xe3\x81\xa1\xe3\x82\x83", ""); |
| // "ちぃ" |
| table->AddRule("tyi", "\xe3\x81\xa1\xe3\x81\x83", ""); |
| // "や" |
| table->AddRule("ya", "\xe3\x82\x84", ""); |
| // "っ" |
| table->AddRule("yy", "\xe3\x81\xa3", "y"); |
| } |
| |
| string GetInsertedString(Transliterators::Transliterator t12r, |
| const size_t position, |
| const string &input) { |
| scoped_ptr<Table> table(new Table); |
| InitTable(table.get()); |
| scoped_ptr<Composition> comp(new Composition(table.get())); |
| InitComposition(comp.get()); |
| |
| comp->SetTable(table.get()); |
| comp->SetDisplayMode(0, t12r); |
| comp->InsertAt(position, input); |
| |
| string composition; |
| comp->GetString(&composition); |
| |
| comp.reset(); |
| table.reset(); |
| |
| return composition; |
| } |
| } // anonymous namespace |
| |
| TEST_F(CompositionTest, InsertAt) { |
| // "あkyきったっty" is the original string |
| |
| // "いあkyきったっty" |
| EXPECT_EQ("\xe3\x81\x84\xe3\x81\x82\x6b\x79\xe3\x81\x8d\xe3\x81\xa3" |
| "\xe3\x81\x9f\xe3\x81\xa3\x74\x79", |
| GetInsertedString(Transliterators::CONVERSION_STRING, 0, "i")); |
| |
| // "あいkyきったっty" |
| EXPECT_EQ("\xE3\x81\x82\xE3\x81\x84\x6B\x79\xE3\x81\x8D\xE3\x81\xA3" |
| "\xE3\x81\x9F\xE3\x81\xA3\x74\x79", |
| GetInsertedString(Transliterators::CONVERSION_STRING, 1, "i")); |
| |
| // "あきyきったっty" |
| EXPECT_EQ("\xE3\x81\x82\xE3\x81\x8D\x79\xE3\x81\x8D\xE3\x81\xA3" |
| "\xE3\x81\x9F\xE3\x81\xA3\x74\x79", |
| GetInsertedString(Transliterators::CONVERSION_STRING, 2, "i")); |
| |
| // "あきぃきったっty" |
| EXPECT_EQ("\xE3\x81\x82\xE3\x81\x8D\xE3\x81\x83\xE3\x81\x8D\xE3\x81\xA3" |
| "\xE3\x81\x9F\xE3\x81\xA3\x74\x79", |
| GetInsertedString(Transliterators::CONVERSION_STRING, 3, "i")); |
| |
| // "あkyきいったっty" |
| EXPECT_EQ("\xE3\x81\x82\x6B\x79\xE3\x81\x8D\xE3\x81\x84\xE3\x81\xA3" |
| "\xE3\x81\x9F\xE3\x81\xA3\x74\x79", |
| GetInsertedString(Transliterators::CONVERSION_STRING, 4, "i")); |
| |
| // "あkyきっいたっty" |
| EXPECT_EQ("\xE3\x81\x82\x6B\x79\xE3\x81\x8D\xE3\x81\xA3\xE3\x81\x84" |
| "\xE3\x81\x9F\xE3\x81\xA3\x74\x79", |
| GetInsertedString(Transliterators::CONVERSION_STRING, 5, "i")); |
| |
| // "あkyきったっちぃ" |
| EXPECT_EQ("\xE3\x81\x82\x6B\x79\xE3\x81\x8D\xE3\x81\xA3\xE3\x81\x9F" |
| "\xE3\x81\xA3\xE3\x81\xA1\xE3\x81\x83", |
| GetInsertedString(Transliterators::CONVERSION_STRING, 9, "i")); |
| |
| // "yあkyきったっty" |
| EXPECT_EQ("\x79\xE3\x81\x82\x6B\x79\xE3\x81\x8D\xE3\x81\xA3\xE3\x81\x9F" |
| "\xE3\x81\xA3\x74\x79", |
| GetInsertedString(Transliterators::CONVERSION_STRING, 0, "y")); |
| |
| // "あykyきったっty" |
| EXPECT_EQ("\xE3\x81\x82\x79\x6B\x79\xE3\x81\x8D\xE3\x81\xA3\xE3\x81\x9F" |
| "\xE3\x81\xA3\x74\x79", |
| GetInsertedString(Transliterators::CONVERSION_STRING, 1, "y")); |
| |
| // "あkyyきったっty" |
| EXPECT_EQ("\xE3\x81\x82\x6B\x79\x79\xE3\x81\x8D\xE3\x81\xA3\xE3\x81\x9F" |
| "\xE3\x81\xA3\x74\x79", |
| GetInsertedString(Transliterators::CONVERSION_STRING, 2, "y")); |
| |
| // "あkyyきったっty" |
| EXPECT_EQ("\xE3\x81\x82\x6B\x79\x79\xE3\x81\x8D\xE3\x81\xA3\xE3\x81\x9F" |
| "\xE3\x81\xA3\x74\x79", |
| GetInsertedString(Transliterators::CONVERSION_STRING, 3, "y")); |
| |
| // "あkyきyったっty" |
| EXPECT_EQ("\xE3\x81\x82\x6B\x79\xE3\x81\x8D\x79\xE3\x81\xA3\xE3\x81\x9F" |
| "\xE3\x81\xA3\x74\x79", |
| GetInsertedString(Transliterators::CONVERSION_STRING, 4, "y")); |
| |
| // "あkyきっyたっty" |
| EXPECT_EQ("\xE3\x81\x82\x6B\x79\xE3\x81\x8D\xE3\x81\xA3\x79\xE3\x81\x9F" |
| "\xE3\x81\xA3\x74\x79", |
| GetInsertedString(Transliterators::CONVERSION_STRING, 5, "y")); |
| |
| // "あkyきったっちぃ" |
| // end |
| EXPECT_EQ("\xE3\x81\x82\x6B\x79\xE3\x81\x8D\xE3\x81\xA3\xE3\x81\x9F" |
| "\xE3\x81\xA3\xE3\x81\xA1\xE3\x81\x83", |
| GetInsertedString(Transliterators::CONVERSION_STRING, 9, "i")); |
| |
| // "あkyきったっtyy" |
| // end |
| EXPECT_EQ("\xE3\x81\x82\x6B\x79\xE3\x81\x8D\xE3\x81\xA3\xE3\x81\x9F" |
| "\xE3\x81\xA3\x74\x79\x79", |
| GetInsertedString(Transliterators::CONVERSION_STRING, 9, "y")); |
| |
| // "akykittatty" is the original string |
| EXPECT_EQ("iakykittatty", |
| GetInsertedString(Transliterators::RAW_STRING, 0, "i")); |
| |
| EXPECT_EQ("aikykittatty", |
| GetInsertedString(Transliterators::RAW_STRING, 1, "i")); |
| |
| EXPECT_EQ("akiykittatty", |
| GetInsertedString(Transliterators::RAW_STRING, 2, "i")); |
| |
| EXPECT_EQ("akyikittatty", |
| GetInsertedString(Transliterators::RAW_STRING, 3, "i")); |
| |
| EXPECT_EQ("akykiittatty", |
| GetInsertedString(Transliterators::RAW_STRING, 4, "i")); |
| |
| EXPECT_EQ("akykiittatty", |
| GetInsertedString(Transliterators::RAW_STRING, 5, "i")); |
| |
| EXPECT_EQ("akykittattyi", |
| GetInsertedString(Transliterators::RAW_STRING, 11, "i")); // end |
| } |
| |
| TEST_F(CompositionTest, GetExpandedStrings) { |
| Table table; |
| InitTable(&table); |
| composition_->SetTable(&table); |
| InitComposition(composition_.get()); |
| |
| // a ky ki tta tty |
| string base; |
| set<string> expanded; |
| composition_->GetExpandedStrings(&base, &expanded); |
| // "あkyきったっ" |
| EXPECT_EQ( |
| "\xe3\x81\x82\x6b\x79\xe3\x81\x8d\xe3\x81\xa3\xe3\x81\x9f\xe3\x81\xa3", |
| base); |
| EXPECT_EQ(2, expanded.size()); |
| // "ちぃ" |
| // You cannot use EXPECT_NE here because it causes compile error in gtest |
| // when the compiler is Visual C++. b/5655673 |
| EXPECT_TRUE(expanded.find("\xe3\x81\xa1\xe3\x81\x83") != expanded.end()); |
| // "ちゃ" |
| // You cannot use EXPECT_NE here because it causes compile error in gtest |
| // when the compiler is Visual C++. b/5655673 |
| EXPECT_TRUE(expanded.find("\xe3\x81\xa1\xe3\x82\x83") != expanded.end()); |
| } |
| |
| TEST_F(CompositionTest, ConvertPosition) { |
| // Test against http://b/1550597 |
| |
| // Invalid positions. |
| EXPECT_EQ(0, |
| composition_->ConvertPosition( |
| static_cast<size_t>(-1), |
| Transliterators::CONVERSION_STRING, |
| Transliterators::RAW_STRING)); |
| EXPECT_EQ(0, |
| composition_->ConvertPosition( |
| 0, |
| Transliterators::CONVERSION_STRING, |
| Transliterators::RAW_STRING)); |
| EXPECT_EQ(0, |
| composition_->ConvertPosition( |
| 1, |
| Transliterators::CONVERSION_STRING, |
| Transliterators::RAW_STRING)); |
| EXPECT_EQ(0, |
| composition_->ConvertPosition( |
| 0, |
| Transliterators::RAW_STRING, |
| Transliterators::CONVERSION_STRING)); |
| EXPECT_EQ(0, |
| composition_->ConvertPosition( |
| static_cast<size_t>(-1), |
| Transliterators::RAW_STRING, |
| Transliterators::CONVERSION_STRING)); |
| EXPECT_EQ(0, |
| composition_->ConvertPosition( |
| 1, |
| Transliterators::RAW_STRING, |
| Transliterators::CONVERSION_STRING)); |
| |
| // "ね" |
| AppendChunk("\xe3\x81\xad", "", "ne", composition_.get()); |
| // "っと" |
| AppendChunk("\xe3\x81\xa3\xe3\x81\xa8", "", "tto", composition_.get()); |
| |
| // "|ねっと" -> "|netto" |
| EXPECT_EQ(0, |
| composition_->ConvertPosition( |
| 0, |
| Transliterators::CONVERSION_STRING, |
| Transliterators::RAW_STRING)); |
| // "ね|っと" -> "ne|tto" |
| EXPECT_EQ(2, |
| composition_->ConvertPosition( |
| 1, |
| Transliterators::CONVERSION_STRING, |
| Transliterators::RAW_STRING)); |
| // "ねっ|と" -> "net|to" |
| EXPECT_EQ(3, |
| composition_->ConvertPosition( |
| 2, |
| Transliterators::CONVERSION_STRING, |
| Transliterators::RAW_STRING)); |
| // "ねっと|" -> "netto|" |
| EXPECT_EQ(5, |
| composition_->ConvertPosition( |
| 3, |
| Transliterators::CONVERSION_STRING, |
| Transliterators::RAW_STRING)); |
| |
| // Invalid positions. |
| EXPECT_EQ(5, |
| composition_->ConvertPosition( |
| static_cast<size_t>(-1), |
| Transliterators::CONVERSION_STRING, |
| Transliterators::RAW_STRING)); |
| EXPECT_EQ(5, |
| composition_->ConvertPosition( |
| 4, |
| Transliterators::CONVERSION_STRING, |
| Transliterators::RAW_STRING)); |
| |
| // "|netto" -> "|ねっと" |
| EXPECT_EQ(0, |
| composition_->ConvertPosition( |
| 0, |
| Transliterators::RAW_STRING, |
| Transliterators::CONVERSION_STRING)); |
| // "n|etto" -> "ね|っと" |
| EXPECT_EQ(1, |
| composition_->ConvertPosition( |
| 1, |
| Transliterators::RAW_STRING, |
| Transliterators::CONVERSION_STRING)); |
| // "ne|tto" -> "ね|っと" |
| EXPECT_EQ(1, |
| composition_->ConvertPosition( |
| 2, |
| Transliterators::RAW_STRING, |
| Transliterators::CONVERSION_STRING)); |
| // "net|to" -> "ねっ|と" |
| EXPECT_EQ(2, |
| composition_->ConvertPosition( |
| 3, |
| Transliterators::RAW_STRING, |
| Transliterators::CONVERSION_STRING)); |
| // "nett|o" -> "ねっと|" |
| EXPECT_EQ(3, |
| composition_->ConvertPosition( |
| 4, |
| Transliterators::RAW_STRING, |
| Transliterators::CONVERSION_STRING)); |
| // "netto|" -> "ねっと|" |
| EXPECT_EQ(3, |
| composition_->ConvertPosition( |
| 5, |
| Transliterators::RAW_STRING, |
| Transliterators::CONVERSION_STRING)); |
| // Invalid positions. |
| EXPECT_EQ(3, |
| composition_->ConvertPosition( |
| static_cast<size_t>(-1), |
| Transliterators::RAW_STRING, |
| Transliterators::CONVERSION_STRING)); |
| EXPECT_EQ(3, |
| composition_->ConvertPosition( |
| 6, |
| Transliterators::RAW_STRING, |
| Transliterators::CONVERSION_STRING)); |
| |
| CharChunkList::iterator chunk_it; |
| size_t inner_position; |
| composition_->GetChunkAt(5, Transliterators::RAW_STRING, |
| &chunk_it, &inner_position); |
| |
| EXPECT_EQ("tto", (*chunk_it)->raw()); |
| EXPECT_EQ(3, inner_position); |
| } |
| |
| TEST_F(CompositionTest, SetDisplayMode) { |
| // "も" |
| AppendChunk("\xe3\x82\x82", "", "mo", composition_.get()); |
| // "ず" |
| AppendChunk("\xe3\x81\x9a", "", "zu", composition_.get()); |
| // "く" |
| AppendChunk("\xe3\x81\x8f", "", "ku", composition_.get()); |
| |
| CharChunkList::iterator chunk_it; |
| size_t inner_position; |
| composition_->GetChunkAt(0, Transliterators::CONVERSION_STRING, |
| &chunk_it, &inner_position); |
| EXPECT_EQ("mo", (*chunk_it)->raw()); |
| EXPECT_EQ(0, inner_position); |
| composition_->GetChunkAt(1, Transliterators::CONVERSION_STRING, |
| &chunk_it, &inner_position); |
| EXPECT_EQ("mo", (*chunk_it)->raw()); |
| EXPECT_EQ(1, inner_position); |
| composition_->GetChunkAt(2, Transliterators::CONVERSION_STRING, |
| &chunk_it, &inner_position); |
| EXPECT_EQ("zu", (*chunk_it)->raw()); |
| EXPECT_EQ(1, inner_position); |
| composition_->GetChunkAt(3, Transliterators::CONVERSION_STRING, |
| &chunk_it, &inner_position); |
| EXPECT_EQ("ku", (*chunk_it)->raw()); |
| EXPECT_EQ(1, inner_position); |
| |
| EXPECT_EQ(6, |
| composition_->SetDisplayMode(1, |
| Transliterators::RAW_STRING)); |
| EXPECT_EQ(3, |
| composition_->SetDisplayMode(2, |
| Transliterators::CONVERSION_STRING)); |
| EXPECT_EQ(6, |
| composition_->SetDisplayMode(2, |
| Transliterators::RAW_STRING)); |
| } |
| |
| TEST_F(CompositionTest, GetStringWithTrimMode) { |
| Table table; |
| // "か" |
| table.AddRule("ka", "\xe3\x81\x8b", ""); |
| // "ん" |
| table.AddRule("n", "\xe3\x82\x93", ""); |
| // This makes the above rule ambiguous. |
| // "な" |
| table.AddRule("na", "\xe3\x81\xaa", ""); |
| composition_->SetTable(&table); |
| |
| string output_empty; |
| composition_->GetStringWithTrimMode(TRIM, &output_empty); |
| EXPECT_TRUE(output_empty.empty()); |
| |
| size_t pos = 0; |
| pos = composition_->InsertAt(pos, "k"); |
| pos = composition_->InsertAt(pos, "a"); |
| pos = composition_->InsertAt(pos, "n"); |
| |
| string output_trim; |
| composition_->GetStringWithTrimMode(TRIM, &output_trim); |
| // "か" |
| EXPECT_EQ("\xe3\x81\x8b", output_trim); |
| |
| string output_asis; |
| composition_->GetStringWithTrimMode(ASIS, &output_asis); |
| // "かn" |
| EXPECT_EQ("\xe3\x81\x8b\x6e", output_asis); |
| |
| string output_fix; |
| composition_->GetStringWithTrimMode(FIX, &output_asis); |
| // "かん" |
| EXPECT_EQ("\xe3\x81\x8b\xe3\x82\x93", output_asis); |
| } |
| |
| TEST_F(CompositionTest, InsertKeyAndPreeditAt) { |
| Table table; |
| // "す゛", "ず" |
| table.AddRule("\xe3\x81\x99\xe3\x82\x9b", "\xe3\x81\x9a", ""); |
| // "く゛", "ぐ" |
| table.AddRule("\xe3\x81\x8f\xe3\x82\x9b", "\xe3\x81\x90", ""); |
| composition_->SetTable(&table); |
| |
| size_t pos = 0; |
| // "も" |
| pos = composition_->InsertKeyAndPreeditAt(pos, "m", "\xe3\x82\x82"); |
| // "す" |
| pos = composition_->InsertKeyAndPreeditAt(pos, "r", "\xe3\x81\x99"); |
| // "゛" |
| pos = composition_->InsertKeyAndPreeditAt(pos, "@", "\xe3\x82\x9b"); |
| // "く" |
| pos = composition_->InsertKeyAndPreeditAt(pos, "h", "\xe3\x81\x8f"); |
| pos = composition_->InsertKeyAndPreeditAt(pos, "!", "!"); |
| |
| string comp_str; |
| composition_->GetString(&comp_str); |
| // "もずく!" |
| EXPECT_EQ("\xe3\x82\x82\xe3\x81\x9a\xe3\x81\x8f\x21", comp_str); |
| |
| string comp_ascii_str; |
| composition_->GetStringWithTransliterator( |
| Transliterators::RAW_STRING, &comp_ascii_str); |
| EXPECT_EQ("mr@h!", comp_ascii_str); |
| } |
| |
| TEST_F(CompositionTest, InsertKey_ForN) { |
| Table table; |
| 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]", ""); |
| composition_->SetTable(&table); |
| |
| size_t pos = 0; |
| pos = composition_->InsertAt(pos, "n"); |
| pos = composition_->InsertAt(pos, "y"); |
| pos = composition_->InsertAt(pos, "n"); |
| pos = composition_->InsertAt(pos, "y"); |
| pos = composition_->InsertAt(pos, "a"); |
| |
| string comp_str; |
| composition_->GetString(&comp_str); |
| EXPECT_EQ("ny[NYA]", comp_str); |
| } |
| |
| TEST_F(CompositionTest, GetStringWithDisplayMode_ForKana) { |
| Table table; |
| // Empty table is OK. |
| composition_->SetTable(&table); |
| |
| size_t pos = 0; |
| // "も" |
| pos = composition_->InsertKeyAndPreeditAt(pos, "m", "\xe3\x82\x82"); |
| |
| string comp_str; |
| composition_->GetStringWithTransliterator( |
| Transliterators::RAW_STRING, &comp_str); |
| EXPECT_EQ("m", comp_str); |
| } |
| |
| TEST_F(CompositionTest, InputMode) { |
| Table table; |
| // "あ" |
| table.AddRule("a", "\xE3\x81\x82", ""); |
| // "か" |
| table.AddRule("ka", "\xE3\x81\x8B", ""); |
| composition_->SetTable(&table); |
| |
| size_t pos = 0; |
| pos = composition_->InsertAt(pos, "k"); |
| |
| string result; |
| composition_->GetString(&result); |
| // "k" |
| EXPECT_EQ("k", result); |
| |
| composition_->SetInputMode(Transliterators::FULL_KATAKANA); |
| pos = composition_->InsertAt(pos, "a"); |
| composition_->GetString(&result); |
| // If a vowel and a consonant were typed with different |
| // transliterators, these characters should not be combined. |
| // "kア" |
| EXPECT_EQ("\x6B\xE3\x82\xA2", result); |
| |
| composition_->SetInputMode(Transliterators::HALF_ASCII); |
| pos = composition_->InsertAt(pos, "k"); |
| composition_->GetString(&result); |
| // "kアk" |
| EXPECT_EQ("\x6B\xE3\x82\xA2\x6B", result); |
| |
| composition_->SetInputMode(Transliterators::HIRAGANA); |
| pos = composition_->InsertAt(pos, "a"); |
| composition_->GetString(&result); |
| // "kアkあ" |
| EXPECT_EQ("\x6B\xE3\x82\xA2\x6B\xE3\x81\x82", result); |
| |
| // "|kアkあ" |
| EXPECT_EQ(Transliterators::CONVERSION_STRING, |
| composition_->GetTransliterator(0)); |
| // "k|アkあ" |
| EXPECT_EQ(Transliterators::CONVERSION_STRING, |
| composition_->GetTransliterator(1)); |
| // "kア|kあ" |
| EXPECT_EQ(Transliterators::FULL_KATAKANA, composition_->GetTransliterator(2)); |
| // "kアk|あ" |
| EXPECT_EQ(Transliterators::HALF_ASCII, composition_->GetTransliterator(3)); |
| // "kアkあ|" |
| EXPECT_EQ(Transliterators::HIRAGANA, composition_->GetTransliterator(4)); |
| // "kアkあ...|" |
| EXPECT_EQ(Transliterators::HIRAGANA, composition_->GetTransliterator(5)); |
| EXPECT_EQ(Transliterators::HIRAGANA, composition_->GetTransliterator(10)); |
| } |
| |
| TEST_F(CompositionTest, SetTable) { |
| Table table; |
| // "あ" |
| table.AddRule("a", "\xE3\x81\x82", ""); |
| // "か" |
| table.AddRule("ka", "\xE3\x81\x8B", ""); |
| |
| Table table2; |
| // "あ" |
| table2.AddRule("a", "\xE3\x81\x82", ""); |
| // "か" |
| table2.AddRule("ka", "\xE3\x81\x8B", ""); |
| |
| composition_->SetTable(&table); |
| composition_->SetInputMode(Transliterators::HIRAGANA); |
| |
| size_t pos = 0; |
| pos = composition_->InsertAt(pos, "k"); |
| |
| string result; |
| composition_->GetString(&result); |
| // "k" |
| EXPECT_EQ("\xEF\xBD\x8B", result); |
| |
| composition_->SetTable(&table2); |
| |
| pos = composition_->InsertAt(pos, "a"); |
| composition_->GetString(&result); |
| // "kあ"; |
| EXPECT_EQ("\xEF\xBD\x8B\xE3\x81\x82", result); |
| } |
| |
| TEST_F(CompositionTest, Transliterator) { |
| Table table; |
| // "あ" |
| table.AddRule("a", "\xE3\x81\x82", ""); |
| composition_->SetTable(&table); |
| |
| // Insert "a" which is converted to "あ". |
| size_t pos = 0; |
| pos = composition_->InsertAt(pos, "a"); |
| EXPECT_EQ(1, pos); |
| string result; |
| composition_->GetString(&result); |
| // "あ" |
| EXPECT_EQ("\xE3\x81\x82", result); |
| |
| // Set transliterator for Half Ascii. |
| composition_->SetTransliterator(0, pos, Transliterators::HALF_ASCII); |
| composition_->GetString(&result); |
| EXPECT_EQ("a", result); |
| |
| // Insert "a" again. |
| pos = composition_->InsertAt(pos, "a"); |
| EXPECT_EQ(2, pos); |
| result.clear(); |
| composition_->GetString(&result); |
| // "aあ" |
| EXPECT_EQ("a\xE3\x81\x82", result); |
| |
| // Set transliterator for Full Katakana. |
| composition_->SetTransliterator(0, pos, Transliterators::FULL_KATAKANA); |
| composition_->GetString(&result); |
| // "アア" |
| EXPECT_EQ("\xE3\x82\xA2\xE3\x82\xA2", result); |
| } |
| |
| TEST_F(CompositionTest, HalfAsciiTransliterator) { |
| Table table; |
| // "ー" |
| table.AddRule("-", "\xE3\x83\xBC", ""); |
| composition_->SetTable(&table); |
| composition_->SetInputMode(Transliterators::HALF_ASCII); |
| |
| size_t pos = 0; |
| pos = composition_->InsertKeyAndPreeditAt(pos, "-", "-"); |
| EXPECT_EQ(1, pos); |
| EXPECT_EQ("-", GetString(*composition_)); |
| |
| pos = composition_->InsertKeyAndPreeditAt(pos, "-", "-"); |
| EXPECT_EQ(2, pos); |
| EXPECT_EQ("--", GetString(*composition_)); |
| } |
| |
| TEST_F(CompositionTest, ShouldCommit) { |
| table_->AddRuleWithAttributes("ka", "[KA]", "", DIRECT_INPUT); |
| table_->AddRuleWithAttributes("tt", "[X]", "t", DIRECT_INPUT); |
| table_->AddRuleWithAttributes("ta", "[TA]", "", NO_TABLE_ATTRIBUTE); |
| |
| size_t pos = 0; |
| |
| // k |
| pos = composition_->InsertAt(pos, "k"); |
| EXPECT_FALSE(composition_->ShouldCommit()); |
| |
| // k + a |
| pos = composition_->InsertAt(pos, "a"); |
| EXPECT_TRUE(composition_->ShouldCommit()); |
| |
| // ka + t |
| pos = composition_->InsertAt(pos, "t"); |
| EXPECT_FALSE(composition_->ShouldCommit()); |
| |
| // kat + t |
| pos = composition_->InsertAt(pos, "t"); |
| EXPECT_FALSE(composition_->ShouldCommit()); |
| |
| // katt + a |
| pos = composition_->InsertAt(pos, "a"); |
| EXPECT_TRUE(composition_->ShouldCommit()); |
| |
| // katta + t |
| pos = composition_->InsertAt(pos, "t"); |
| EXPECT_FALSE(composition_->ShouldCommit()); |
| |
| // kattat + a |
| pos = composition_->InsertAt(pos, "a"); |
| EXPECT_FALSE(composition_->ShouldCommit()); |
| EXPECT_EQ("[KA][X][TA][TA]", GetString(*composition_)); |
| } |
| |
| TEST_F(CompositionTest, Issue2190364) { |
| // This is a unittest against http://b/2190364 |
| Table table; |
| composition_->SetTable(&table); |
| |
| size_t pos = 0; |
| |
| composition_->SetInputMode(Transliterators::FULL_ASCII); |
| // "ち" |
| pos = composition_->InsertKeyAndPreeditAt(pos, "a", "\xE3\x81\xA1"); |
| // "a" |
| EXPECT_EQ("\xEF\xBD\x81", GetString(*composition_)); |
| |
| pos = composition_->InsertAt(pos, " "); |
| // "a " |
| EXPECT_EQ("\xEF\xBD\x81\xE3\x80\x80", GetString(*composition_)); |
| } |
| |
| |
| TEST_F(CompositionTest, Issue1817410) { |
| // This is a unittest against http://b/2190364 |
| Table table; |
| // "っ" |
| table.AddRule("ss", "\xE3\x81\xA3", "s"); |
| composition_->SetTable(&table); |
| |
| size_t pos = 0; |
| pos = composition_->InsertAt(pos, "s"); |
| pos = composition_->InsertAt(pos, "s"); |
| |
| string preedit; |
| composition_->GetString(&preedit); |
| // "っs" |
| EXPECT_EQ("\xE3\x81\xA3\x73", preedit); |
| |
| EXPECT_EQ(0, composition_->ConvertPosition(0, Transliterators::LOCAL, |
| Transliterators::HALF_ASCII)); |
| EXPECT_EQ(1, composition_->ConvertPosition(1, Transliterators::LOCAL, |
| Transliterators::HALF_ASCII)); |
| EXPECT_EQ(2, composition_->ConvertPosition(2, Transliterators::LOCAL, |
| Transliterators::HALF_ASCII)); |
| |
| { // "s|s" |
| CharChunkList::iterator chunk_it; |
| size_t inner_position; |
| composition_->GetChunkAt(1, Transliterators::LOCAL, |
| &chunk_it, &inner_position); |
| EXPECT_EQ(1, inner_position); |
| EXPECT_EQ(2, (*chunk_it)->GetLength(Transliterators::LOCAL)); |
| |
| EXPECT_EQ(0, composition_->GetPosition(Transliterators::HALF_ASCII, |
| chunk_it)); |
| EXPECT_EQ(2, (*chunk_it)->GetLength(Transliterators::HALF_ASCII)); |
| } |
| |
| { // "ss|" |
| CharChunkList::iterator chunk_it; |
| size_t inner_position; |
| composition_->GetChunkAt(2, Transliterators::LOCAL, |
| &chunk_it, &inner_position); |
| EXPECT_EQ(2, inner_position); |
| EXPECT_EQ(2, (*chunk_it)->GetLength(Transliterators::LOCAL)); |
| |
| EXPECT_EQ(0, composition_->GetPosition(Transliterators::HALF_ASCII, |
| chunk_it)); |
| EXPECT_EQ(2, (*chunk_it)->GetLength(Transliterators::HALF_ASCII)); |
| } |
| } |
| |
| TEST_F(CompositionTest, Issue2209634) { |
| // This is a unittest against http://b/2209634 |
| // "q@" becomes "qた@". |
| Table table; |
| // "た" |
| table.AddRule("q", "", "\xE3\x81\x9F"); |
| // "た@", "だ" |
| table.AddRule("\xE3\x81\x9F\x40", "\xE3\x81\xA0", ""); |
| composition_->SetTable(&table); |
| |
| composition_->SetInputMode(Transliterators::HALF_ASCII); |
| |
| size_t pos = 0; |
| pos = composition_->InsertAt(pos, "q"); |
| pos = composition_->InsertAt(pos, "@"); |
| |
| string preedit; |
| composition_->GetString(&preedit); |
| EXPECT_EQ("q@", preedit); |
| } |
| |
| TEST_F(CompositionTest, Issue2330530) { |
| // This is a unittest against http://b/2330530 |
| // "Win" + Numpad7 becomes "Win77" instead of "Win7". |
| Table table; |
| // "うぃ" |
| table.AddRule("wi", "\xe3\x81\x86\xe3\x81\x83", ""); |
| // "い" |
| table.AddRule("i", "\xe3\x81\x84", ""); |
| // "ん" |
| table.AddRule("n", "\xe3\x82\x93", ""); |
| // "な" |
| table.AddRule("na", "\xe3\x81\xaa", ""); |
| composition_->SetTable(&table); |
| |
| composition_->SetInputMode(Transliterators::HALF_ASCII); |
| |
| size_t pos = 0; |
| pos = composition_->InsertAt(pos, "W"); |
| pos = composition_->InsertAt(pos, "i"); |
| pos = composition_->InsertAt(pos, "n"); |
| |
| string preedit; |
| composition_->GetString(&preedit); |
| EXPECT_EQ("Win", preedit); |
| |
| pos = composition_->InsertKeyAndPreeditAt(pos, "7", "7"); |
| composition_->GetString(&preedit); |
| EXPECT_EQ("Win7", preedit); |
| } |
| |
| TEST_F(CompositionTest, Issue2819580) { |
| // This is a unittest against http://b/2819580. |
| // 'y' after 'n' disappears. |
| Table table; |
| // "ぽ" |
| 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", ""); |
| // "びょ" |
| table.AddRule("byo", "\xe3\x81\xb3\xe3\x82\x87", ""); |
| |
| composition_->SetTable(&table); |
| |
| composition_->SetInputMode(Transliterators::HIRAGANA); |
| |
| size_t pos = 0; |
| pos = composition_->InsertAt(pos, "n"); |
| pos = composition_->InsertAt(pos, "y"); |
| { |
| string output; |
| composition_->GetStringWithTrimMode(FIX, &output); |
| // "んy" |
| EXPECT_EQ("\xe3\x82\x93\xef\xbd\x99", output); |
| |
| composition_->GetStringWithTrimMode(ASIS, &output); |
| // "ny" |
| EXPECT_EQ("\xef\xbd\x8e\xef\xbd\x99", output); |
| |
| composition_->GetStringWithTrimMode(TRIM, &output); |
| // "" |
| EXPECT_EQ("", output); |
| } |
| } |
| |
| TEST_F(CompositionTest, Issue2990253) { |
| // SplitChunk fails. |
| // Ambiguous text is left in rhs CharChunk invalidly. |
| Table table; |
| // "ぽ" |
| 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", ""); |
| // "びょ" |
| table.AddRule("byo", "\xe3\x81\xb3\xe3\x82\x87", ""); |
| |
| composition_->SetTable(&table); |
| |
| composition_->SetInputMode(Transliterators::HIRAGANA); |
| |
| size_t pos = 0; |
| pos = composition_->InsertAt(pos, "n"); |
| pos = composition_->InsertAt(pos, "y"); |
| pos = 1; |
| pos = composition_->InsertAt(pos, "b"); |
| { |
| string output; |
| composition_->GetStringWithTrimMode(FIX, &output); |
| // "んby" |
| EXPECT_EQ("\xe3\x82\x93\xef\xbd\x82\xef\xbd\x99", output); |
| |
| composition_->GetStringWithTrimMode(ASIS, &output); |
| // "んby" |
| EXPECT_EQ("\xe3\x82\x93\xef\xbd\x82\xef\xbd\x99", output); |
| |
| composition_->GetStringWithTrimMode(TRIM, &output); |
| // "んb" |
| // doubtful result. should be "ん" |
| // May relate to http://b/2990358 |
| EXPECT_EQ("\xe3\x82\x93\xef\xbd\x82", output); |
| } |
| } |
| |
| TEST_F(CompositionTest, InsertionIntoPreeditMakesInvalidText_1) { |
| // http://b/2990358 |
| // Test for mainly Composition::InsertAt() |
| |
| Table table; |
| // "ぽ" |
| 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", ""); |
| // "びょ" |
| table.AddRule("byo", "\xe3\x81\xb3\xe3\x82\x87", ""); |
| |
| composition_->SetTable(&table); |
| |
| composition_->SetInputMode(Transliterators::HIRAGANA); |
| |
| size_t pos = 0; |
| pos = composition_->InsertAt(pos, "n"); |
| pos = composition_->InsertAt(pos, "y"); |
| pos = 1; |
| pos = composition_->InsertAt(pos, "b"); |
| pos = 3; |
| pos = composition_->InsertAt(pos, "o"); |
| { |
| string output; |
| composition_->GetStringWithTrimMode(FIX, &output); |
| // "んびょ" |
| EXPECT_EQ("\xe3\x82\x93\xe3\x81\xb3\xe3\x82\x87", output); |
| |
| composition_->GetStringWithTrimMode(ASIS, &output); |
| // "んびょ" |
| EXPECT_EQ("\xe3\x82\x93\xe3\x81\xb3\xe3\x82\x87", output); |
| |
| composition_->GetStringWithTrimMode(TRIM, &output); |
| // "んびょ" |
| EXPECT_EQ("\xe3\x82\x93\xe3\x81\xb3\xe3\x82\x87", output); |
| } |
| } |
| |
| TEST_F(CompositionTest, InsertionIntoPreeditMakesInvalidText_2) { |
| // http://b/2990358 |
| // Test for mainly Composition::InsertKeyAndPreeditAt() |
| |
| Table table; |
| // "す゛", "ず" |
| table.AddRule("\xe3\x81\x99\xe3\x82\x9b", "\xe3\x81\x9a", ""); |
| // "く゛", "ぐ" |
| table.AddRule("\xe3\x81\x8f\xe3\x82\x9b", "\xe3\x81\x90", ""); |
| composition_->SetTable(&table); |
| |
| size_t pos = 0; |
| // "も" |
| pos = composition_->InsertKeyAndPreeditAt(pos, "m", "\xe3\x82\x82"); |
| // "す" |
| pos = composition_->InsertKeyAndPreeditAt(pos, "r", "\xe3\x81\x99"); |
| // "く" |
| pos = composition_->InsertKeyAndPreeditAt(pos, "h", "\xe3\x81\x8f"); |
| // "゛" |
| pos = composition_->InsertKeyAndPreeditAt(2, "@", "\xe3\x82\x9b"); |
| pos = composition_->InsertKeyAndPreeditAt(5, "!", "!"); |
| |
| string comp_str; |
| composition_->GetString(&comp_str); |
| // "もずく!" |
| EXPECT_EQ("\xe3\x82\x82\xe3\x81\x9a\xe3\x81\x8f\x21", comp_str); |
| |
| string comp_ascii_str; |
| composition_->GetStringWithTransliterator( |
| Transliterators::RAW_STRING, &comp_ascii_str); |
| EXPECT_EQ("mr@h!", comp_ascii_str); |
| } |
| |
| TEST_F(CompositionTest, CombinePendingChunks) { |
| Table table; |
| // "ぽ" |
| 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", ""); |
| // "びょ" |
| table.AddRule("byo", "\xe3\x81\xb3\xe3\x82\x87", ""); |
| |
| { |
| // empty chunks + "n" -> empty chunks + "n" |
| Composition comp(&table); |
| comp.SetInputMode(Transliterators::HIRAGANA); |
| |
| size_t pos = 0; |
| |
| CharChunkList::iterator it; |
| comp.MaybeSplitChunkAt(pos, &it); |
| CharChunkList::iterator chunk_it = comp.GetInsertionChunk(&it); |
| |
| CompositionInput input; |
| SetInput("n", "", false, &input); |
| comp.CombinePendingChunks(chunk_it, input); |
| EXPECT_EQ("", (*chunk_it)->pending()); |
| EXPECT_EQ("", (*chunk_it)->conversion()); |
| EXPECT_EQ("", (*chunk_it)->raw()); |
| EXPECT_EQ("", (*chunk_it)->ambiguous()); |
| } |
| { |
| // [x] + "n" -> [x] + "n" |
| // No combination performed. |
| Composition comp(&table); |
| comp.SetInputMode(Transliterators::HIRAGANA); |
| |
| size_t pos = 0; |
| pos = comp.InsertAt(pos, "x"); |
| |
| CharChunkList::iterator it; |
| comp.MaybeSplitChunkAt(pos, &it); |
| CharChunkList::iterator chunk_it = comp.GetInsertionChunk(&it); |
| CompositionInput input; |
| SetInput("n", "", false, &input); |
| |
| comp.CombinePendingChunks(chunk_it, input); |
| EXPECT_EQ("", (*chunk_it)->pending()); |
| EXPECT_EQ("", (*chunk_it)->conversion()); |
| EXPECT_EQ("", (*chunk_it)->raw()); |
| EXPECT_EQ("", (*chunk_it)->ambiguous()); |
| } |
| { |
| // Append "a" to [n][y] -> [ny] + "a" |
| // Combination performed. |
| Composition comp(&table); |
| comp.SetInputMode(Transliterators::HIRAGANA); |
| |
| size_t pos = 0; |
| pos = comp.InsertAt(pos, "y"); |
| pos = comp.InsertAt(0, "n"); |
| |
| CharChunkList::iterator it; |
| comp.MaybeSplitChunkAt(2, &it); |
| CharChunkList::iterator chunk_it = comp.GetInsertionChunk(&it); |
| CompositionInput input; |
| SetInput("a", "", false, &input); |
| |
| comp.CombinePendingChunks(chunk_it, input); |
| EXPECT_EQ("ny", (*chunk_it)->pending()); |
| EXPECT_EQ("", (*chunk_it)->conversion()); |
| EXPECT_EQ("ny", (*chunk_it)->raw()); |
| // "んy" |
| EXPECT_EQ("\xe3\x82\x93y", (*chunk_it)->ambiguous()); |
| } |
| { |
| // Append "a" to [x][n][y] -> [x][ny] + "a" |
| // Combination performed. |
| Composition comp(&table); |
| comp.SetTable(&table); |
| comp.SetInputMode(Transliterators::HIRAGANA); |
| |
| size_t pos = 0; |
| pos = comp.InsertAt(pos, "x"); |
| pos = comp.InsertAt(pos, "y"); |
| pos = comp.InsertAt(1, "n"); |
| |
| CharChunkList::iterator it; |
| comp.MaybeSplitChunkAt(3, &it); |
| CharChunkList::iterator chunk_it = comp.GetInsertionChunk(&it); |
| CompositionInput input; |
| SetInput("a", "", false, &input); |
| |
| comp.CombinePendingChunks(chunk_it, input); |
| EXPECT_EQ("ny", (*chunk_it)->pending()); |
| EXPECT_EQ("", (*chunk_it)->conversion()); |
| EXPECT_EQ("ny", (*chunk_it)->raw()); |
| // "んy" |
| EXPECT_EQ("\xe3\x82\x93y", (*chunk_it)->ambiguous()); |
| } |
| |
| { |
| // Append "a" of conversion value to [x][n][y] -> [x][ny] + "a" |
| // Combination performed. If composition input contains a |
| // conversion, the conversion is used rather than a raw value. |
| Composition comp(&table); |
| comp.SetInputMode(Transliterators::HIRAGANA); |
| |
| size_t pos = 0; |
| pos = comp.InsertAt(pos, "x"); |
| pos = comp.InsertAt(pos, "y"); |
| pos = comp.InsertAt(1, "n"); |
| |
| CharChunkList::iterator it; |
| comp.MaybeSplitChunkAt(3, &it); |
| CharChunkList::iterator chunk_it = comp.GetInsertionChunk(&it); |
| CompositionInput input; |
| SetInput("x", "a", false, &input); |
| |
| comp.CombinePendingChunks(chunk_it, input); |
| EXPECT_EQ("ny", (*chunk_it)->pending()); |
| EXPECT_EQ("", (*chunk_it)->conversion()); |
| EXPECT_EQ("ny", (*chunk_it)->raw()); |
| } |
| } |
| |
| TEST_F(CompositionTest, NewChunkBehaviors) { |
| Table table; |
| // "ん" |
| table.AddRule("n", "", "\xe3\x82\x93"); |
| // "な" |
| table.AddRule("na", "", "\xe3\x81\xaa"); |
| // "あ" |
| table.AddRuleWithAttributes("a", "", "\xE3\x81\x82", NEW_CHUNK); |
| // "ん*" -> "猫" |
| table.AddRule("\xe3\x82\x93*", "", "\xE7\x8C\xAB"); |
| // "*" -> "" |
| table.AddRule("*", "", ""); |
| // "ん#" -> "猫" |
| table.AddRule("\xe3\x82\x93#", "", "\xE7\x8C\xAB"); |
| |
| composition_->SetTable(&table); |
| |
| CompositionInput input; |
| { |
| size_t pos = 0; |
| composition_->Erase(); |
| SetInput("n", "", true, &input); |
| pos = composition_->InsertInput(pos, input); |
| SetInput("a", "", true, &input); |
| pos = composition_->InsertInput(pos, input); |
| // "nあ" |
| EXPECT_EQ("n\xe3\x81\x82", GetString(*composition_)); |
| } |
| { |
| size_t pos = 0; |
| composition_->Erase(); |
| SetInput("n", "", false, &input); |
| pos = composition_->InsertInput(pos, input); |
| SetInput("a", "", false, &input); |
| pos = composition_->InsertInput(pos, input); |
| // "な" |
| EXPECT_EQ("\xe3\x81\xaa", GetString(*composition_)); |
| } |
| |
| { |
| size_t pos = 0; |
| composition_->Erase(); |
| SetInput("n", "", true, &input); |
| pos = composition_->InsertInput(pos, input); |
| SetInput("*", "", true, &input); |
| pos = composition_->InsertInput(pos, input); |
| // "猫" |
| EXPECT_EQ("\xE7\x8C\xAB", GetString(*composition_)); |
| } |
| { |
| size_t pos = 0; |
| composition_->Erase(); |
| SetInput("n", "", false, &input); |
| pos = composition_->InsertInput(pos, input); |
| SetInput("*", "", false, &input); |
| pos = composition_->InsertInput(pos, input); |
| // "猫" |
| EXPECT_EQ("\xE7\x8C\xAB", GetString(*composition_)); |
| } |
| |
| { |
| size_t pos = 0; |
| composition_->Erase(); |
| SetInput("n", "", true, &input); |
| pos = composition_->InsertInput(pos, input); |
| SetInput("#", "", true, &input); |
| pos = composition_->InsertInput(pos, input); |
| EXPECT_EQ("n#", GetString(*composition_)); |
| } |
| { |
| size_t pos = 0; |
| composition_->Erase(); |
| SetInput("n", "", false, &input); |
| pos = composition_->InsertInput(pos, input); |
| SetInput("#", "", false, &input); |
| pos = composition_->InsertInput(pos, input); |
| // "猫" |
| EXPECT_EQ("\xE7\x8C\xAB", GetString(*composition_)); |
| } |
| |
| { |
| size_t pos = 0; |
| composition_->Erase(); |
| SetInput("n", "", true, &input); |
| pos = composition_->InsertInput(pos, input); |
| SetInput("1", "", true, &input); |
| pos = composition_->InsertInput(pos, input); |
| EXPECT_EQ("n1", GetString(*composition_)); |
| } |
| { |
| size_t pos = 0; |
| composition_->Erase(); |
| SetInput("n", "", false, &input); |
| pos = composition_->InsertInput(pos, input); |
| SetInput("1", "", false, &input); |
| pos = composition_->InsertInput(pos, input); |
| // "ん1" |
| EXPECT_EQ("\xE3\x82\x93""1", GetString(*composition_)); |
| } |
| } |
| |
| TEST_F(CompositionTest, TwelveKeysInput) { |
| // Simulates flick + toggle input mode. |
| |
| Table table; |
| // "ん" |
| table.AddRule("n", "", "\xe3\x82\x93"); |
| // "な" |
| table.AddRule("na", "", "\xe3\x81\xaa"); |
| // "あ" |
| table.AddRule("a", "", "\xE3\x81\x82"); |
| // "*" -> "" |
| table.AddRule("*", "", ""); |
| // "ほ" + "*" ->"ぼ" |
| table.AddRule("\xE3\x81\xBB*", "", "\xE3\x81\xBC"); |
| // "は" |
| table.AddRuleWithAttributes("7", "", "\xE3\x81\xAF", NEW_CHUNK); |
| // "は7" -> "ひ" |
| table.AddRule("\xE3\x81\xAF""7", "", "\xE3\x81\xB2"); |
| // "ひ" + "*" ->"び" |
| table.AddRule("\xE3\x81\xB2*", "", "\xE3\x81\xB3"); |
| |
| composition_->SetTable(&table); |
| |
| CompositionInput input; |
| size_t pos = 0; |
| |
| SetInput("n", "", true, &input); |
| pos = composition_->InsertInput(pos, input); |
| |
| SetInput("a", "", false, &input); |
| pos = composition_->InsertInput(pos, input); |
| |
| // "ほ" |
| SetInput("7", "\xE3\x81\xBB", false, &input); |
| pos = composition_->InsertInput(pos, input); |
| |
| SetInput("*", "", true, &input); |
| pos = composition_->InsertInput(pos, input); |
| |
| // "ひ" |
| SetInput("7", "\xE3\x81\xB2", false, &input); |
| pos = composition_->InsertInput(pos, input); |
| |
| SetInput("7", "", true, &input); |
| pos = composition_->InsertInput(pos, input); |
| |
| // "は" |
| SetInput("7", "\xE3\x81\xAF", false, &input); |
| pos = composition_->InsertInput(pos, input); |
| |
| SetInput("7", "", true, &input); |
| pos = composition_->InsertInput(pos, input); |
| |
| // "は" |
| SetInput("7", "\xE3\x81\xAF", false, &input); |
| pos = composition_->InsertInput(pos, input); |
| |
| // "なぼひはははは" |
| EXPECT_EQ("\xE3\x81\xAA\xE3\x81\xBC\xE3\x81\xB2\xE3\x81\xAF" |
| "\xE3\x81\xAF\xE3\x81\xAF\xE3\x81\xAF", |
| GetString(*composition_)); |
| } |
| |
| TEST_F(CompositionTest, DifferentRulesForSamePendingWithSpecialKeys) { |
| table_->AddRule("4", "", "[ta]"); |
| table_->AddRule("[to]4", "", "[x]{#1}"); |
| table_->AddRule("[x]{#1}4", "", "[ta]"); |
| |
| table_->AddRule("*", "", ""); |
| table_->AddRule("[tu]*", "", "[x]{#2}"); |
| table_->AddRule("[x]{#2}*", "", "[tu]"); |
| |
| { |
| composition_->Erase(); |
| size_t pos = 0; |
| pos = composition_->InsertAt(pos, "[to]4"); |
| EXPECT_EQ(3, pos); |
| EXPECT_EQ("[x]", GetString(*composition_)); |
| EXPECT_EQ("[to]4", GetRawString(*composition_)); |
| |
| pos = composition_->InsertAt(pos, "4"); |
| EXPECT_EQ(4, pos); |
| EXPECT_EQ("[ta]", GetString(*composition_)); |
| EXPECT_EQ("[to]44", GetRawString(*composition_)); |
| } |
| |
| { |
| composition_->Erase(); |
| size_t pos = 0; |
| pos = composition_->InsertAt(pos, "[to]4"); |
| EXPECT_EQ(3, pos); |
| EXPECT_EQ("[x]", GetString(*composition_)); |
| EXPECT_EQ("[to]4", GetRawString(*composition_)); |
| |
| pos = composition_->InsertAt(pos, "*"); |
| EXPECT_EQ(3, pos); |
| EXPECT_EQ("[x]", GetString(*composition_)); |
| EXPECT_EQ("[to]4*", GetRawString(*composition_)); |
| } |
| |
| { |
| composition_->Erase(); |
| size_t pos = 0; |
| pos = composition_->InsertAt(pos, "[tu]*"); |
| EXPECT_EQ(3, pos); |
| EXPECT_EQ("[x]", GetString(*composition_)); |
| EXPECT_EQ("[tu]*", GetRawString(*composition_)); |
| |
| pos = composition_->InsertAt(pos, "*"); |
| EXPECT_EQ(4, pos); |
| EXPECT_EQ("[tu]", GetString(*composition_)); |
| EXPECT_EQ("[tu]**", GetRawString(*composition_)); |
| } |
| |
| { |
| composition_->Erase(); |
| size_t pos = 0; |
| pos = composition_->InsertAt(pos, "[tu]*"); |
| EXPECT_EQ(3, pos); |
| EXPECT_EQ("[x]", GetString(*composition_)); |
| EXPECT_EQ("[tu]*", GetRawString(*composition_)); |
| |
| pos = composition_->InsertAt(pos, "*"); |
| EXPECT_EQ(4, pos); |
| EXPECT_EQ("[tu]", GetString(*composition_)); |
| EXPECT_EQ("[tu]**", GetRawString(*composition_)); |
| } |
| } |
| |
| TEST_F(CompositionTest, LoopingRuleFor12KeysWithSpecialKeys) { |
| table_->AddRule("2", "", "a"); |
| table_->AddRule("a2", "", "b"); |
| table_->AddRule("b2", "", "c"); |
| table_->AddRule("c2", "", "{2}2"); |
| table_->AddRule("{2}22", "", "a"); |
| |
| size_t pos = 0; |
| pos = composition_->InsertAt(pos, "2"); |
| EXPECT_EQ("a", GetString(*composition_)); |
| EXPECT_EQ("2", GetRawString(*composition_)); |
| |
| pos = composition_->InsertAt(pos, "2"); |
| EXPECT_EQ("b", GetString(*composition_)); |
| EXPECT_EQ("22", GetRawString(*composition_)); |
| |
| pos = composition_->InsertAt(pos, "2"); |
| EXPECT_EQ("c", GetString(*composition_)); |
| EXPECT_EQ("222", GetRawString(*composition_)); |
| |
| pos = composition_->InsertAt(pos, "2"); |
| EXPECT_EQ("2", GetString(*composition_)); |
| EXPECT_EQ("2222", GetRawString(*composition_)); |
| |
| pos = composition_->InsertAt(pos, "2"); |
| EXPECT_EQ("a", GetString(*composition_)); |
| EXPECT_EQ("22222", GetRawString(*composition_)); |
| |
| pos = composition_->InsertAt(pos, "2"); |
| EXPECT_EQ("b", GetString(*composition_)); |
| EXPECT_EQ("222222", GetRawString(*composition_)); |
| |
| pos = composition_->InsertAt(pos, "2"); |
| EXPECT_EQ("c", GetString(*composition_)); |
| EXPECT_EQ("2222222", GetRawString(*composition_)); |
| } |
| |
| TEST_F(CompositionTest, AlphanumericOfSSH) { |
| // This is a unittest against http://b/3199626 |
| // 'ssh' (っsh) + F10 should be 'ssh'. |
| Table table; |
| // "っ" |
| table.AddRule("ss", "\xE3\x81\xA3", "s"); |
| // "し" |
| table.AddRule("shi", "\xE3\x81\x97", ""); |
| |
| composition_->SetTable(&table); |
| composition_->SetInputMode(Transliterators::HIRAGANA); |
| size_t pos = 0; |
| pos = composition_->InsertAt(pos, "s"); |
| pos = composition_->InsertAt(pos, "s"); |
| pos = composition_->InsertAt(pos, "h"); |
| EXPECT_EQ(3, pos); |
| |
| string output; |
| composition_->GetStringWithTrimMode(FIX, &output); |
| // "っsh" |
| EXPECT_EQ("\xE3\x81\xA3\xEF\xBD\x93\xEF\xBD\x88", output); |
| } |
| |
| TEST_F(CompositionTest, GrassHack) { |
| Table table; |
| // "っ" |
| table.AddRule("ww", "\xE3\x81\xA3", "w"); |
| // "うぇ" |
| table.AddRule("we", "\xE3\x81\x86\xE3\x81\x87", ""); |
| table.AddRule("www", "w", "ww"); |
| |
| composition_->SetTable(&table); |
| composition_->SetInputMode(Transliterators::HIRAGANA); |
| size_t pos = 0; |
| pos = composition_->InsertAt(pos, "w"); |
| pos = composition_->InsertAt(pos, "w"); |
| pos = composition_->InsertAt(pos, "w"); |
| |
| // "www" |
| EXPECT_EQ("\xEF\xBD\x97" "\xEF\xBD\x97" "\xEF\xBD\x97", |
| GetString(*composition_)); |
| |
| pos = composition_->InsertAt(pos, "e"); |
| // "wっうぇ" |
| EXPECT_EQ("\xEF\xBD\x97" "\xE3\x81\xA3" "\xE3\x81\x86\xE3\x81\x87", |
| GetString(*composition_)); |
| } |
| |
| TEST_F(CompositionTest, RulesForFirstKeyEvents) { |
| table_->AddRuleWithAttributes("a", "[A]", "", NEW_CHUNK); |
| table_->AddRule("n", "[N]", ""); |
| table_->AddRule("nn", "[N]", ""); |
| table_->AddRule("na", "[NA]", ""); |
| table_->AddRuleWithAttributes("ni", "[NI]", "", NEW_CHUNK); |
| |
| CompositionInput input; |
| |
| { |
| SetInput("a", "", true, &input); |
| composition_->InsertInput(0, input); |
| EXPECT_EQ("[A]", GetString(*composition_)); |
| } |
| |
| { |
| composition_->Erase(); |
| CompositionInput input; |
| SetInput("anaa", "", true, &input); |
| composition_->InsertInput(0, input); |
| EXPECT_EQ("[A][NA][A]", GetString(*composition_)); |
| } |
| |
| { |
| composition_->Erase(); |
| |
| CompositionInput input; |
| SetInput("an", "", true, &input); |
| const size_t position_an = composition_->InsertInput(0, input); |
| |
| SetInput("a", "", true, &input); |
| composition_->InsertInput(position_an, input); |
| EXPECT_EQ("[A]n[A]", GetString(*composition_)); |
| |
| // This input should be treated as a part of "NA". |
| SetInput("a", "", false, &input); |
| composition_->InsertInput(position_an, input); |
| EXPECT_EQ("[A][NA][A]", GetString(*composition_)); |
| |
| string raw_t13n; |
| composition_->GetStringWithTransliterator( |
| Transliterators::RAW_STRING, &raw_t13n); |
| EXPECT_EQ("anaa", raw_t13n); |
| } |
| |
| { |
| composition_->Erase(); |
| |
| CompositionInput input; |
| SetInput("an", "", true, &input); |
| const size_t position_an = composition_->InsertInput(0, input); |
| |
| SetInput("ni", "", true, &input); |
| composition_->InsertInput(position_an, input); |
| EXPECT_EQ("[A]n[NI]", GetString(*composition_)); |
| |
| string raw_t13n; |
| composition_->GetStringWithTransliterator( |
| Transliterators::RAW_STRING, &raw_t13n); |
| EXPECT_EQ("anni", raw_t13n); |
| } |
| } |
| |
| TEST_F(CompositionTest, NoTransliteration) { |
| table_->AddRuleWithAttributes("0", "0", "", NO_TABLE_ATTRIBUTE); |
| table_->AddRuleWithAttributes("1", "1", "", NO_TRANSLITERATION); |
| // "っ" |
| table_->AddRuleWithAttributes("kk", "\xE3\x81\xA3", "k", NO_TABLE_ATTRIBUTE); |
| // "か" |
| table_->AddRuleWithAttributes("ka", "\xE3\x81\x8B", "", NO_TRANSLITERATION); |
| // "っ" |
| table_->AddRuleWithAttributes("ss", "\xE3\x81\xA3", "s", NO_TRANSLITERATION); |
| // "さ" |
| table_->AddRuleWithAttributes("sa", "\xE3\x81\x95", "", NO_TABLE_ATTRIBUTE); |
| // "っ" |
| table_->AddRuleWithAttributes("tt", "\xE3\x81\xA3", "t", NO_TRANSLITERATION); |
| // "た" |
| table_->AddRuleWithAttributes("ta", "\xE3\x81\x9F", "", NO_TRANSLITERATION); |
| |
| composition_->SetInputMode(Transliterators::FULL_KATAKANA); |
| |
| InsertCharacters("01kkassatta", 0, composition_.get()); |
| // "01ッカっさった" |
| EXPECT_EQ("\xEF\xBC\x90\x31\xE3\x83\x83\xE3\x82\xAB\xE3\x81\xA3\xE3\x81\x95" |
| "\xE3\x81\xA3\xE3\x81\x9F", |
| GetString(*composition_)); |
| } |
| |
| TEST_F(CompositionTest, NoTransliteration_Issue3497962) { |
| table_->AddRuleWithAttributes("2", "", "a", NEW_CHUNK | NO_TRANSLITERATION); |
| table_->AddRuleWithAttributes("a2", "", "b", NO_TABLE_ATTRIBUTE); |
| table_->AddRuleWithAttributes("b2", "", "c", NO_TABLE_ATTRIBUTE); |
| table_->AddRuleWithAttributes("c2", "", "{2}2", NO_TABLE_ATTRIBUTE); |
| table_->AddRuleWithAttributes("{2}22", "", "a", NO_TABLE_ATTRIBUTE); |
| |
| composition_->SetInputMode(Transliterators::HIRAGANA); |
| |
| int pos = 0; |
| pos = composition_->InsertAt(pos, "2"); |
| EXPECT_EQ("a", GetString(*composition_)); |
| |
| pos = composition_->InsertAt(pos, "2"); |
| EXPECT_EQ("b", GetString(*composition_)); |
| } |
| |
| TEST_F(CompositionTest, SetTransliteratorOnEmpty) { |
| composition_->SetTransliterator(0, 0, Transliterators::HIRAGANA); |
| CompositionInput input; |
| SetInput("a", "", true, &input); |
| composition_->InsertInput(0, input); |
| EXPECT_EQ(1, composition_->GetLength()); |
| } |
| |
| TEST_F(CompositionTest, Clone) { |
| Composition src(table_.get()); |
| src.SetInputMode(Transliterators::FULL_KATAKANA); |
| |
| // "も" |
| AppendChunk("\xe3\x82\x82", "", "mo", &src); |
| // "ず" |
| AppendChunk("\xe3\x81\x9a", "", "z", &src); |
| // "く" |
| AppendChunk("\xe3\x81\x8f", "", "c", &src); |
| |
| EXPECT_EQ(table_.get(), src.table()); |
| EXPECT_EQ(Transliterators::FULL_KATAKANA, src.input_t12r()); |
| EXPECT_EQ(3, src.chunks().size()); |
| |
| scoped_ptr<Composition> dest(src.CloneImpl()); |
| ASSERT_NE(nullptr, dest.get()); |
| EXPECT_EQ(src.table(), dest->table()); |
| EXPECT_EQ(src.input_t12r(), dest->input_t12r()); |
| ASSERT_EQ(src.chunks().size(), dest->chunks().size()); |
| |
| CharChunkList::const_iterator src_it = src.chunks().begin(); |
| CharChunkList::const_iterator dest_it = dest->chunks().begin(); |
| for (; src_it != src.chunks().end(); ++src_it, ++dest_it) { |
| EXPECT_EQ((*src_it)->raw(), (*dest_it)->raw()); |
| } |
| } |
| |
| } // namespace composer |
| } // namespace mozc |