1 // Copyright 2010-2018, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "composer/internal/composition.h"
31
32 #include <algorithm>
33 #include <memory>
34 #include <set>
35 #include <string>
36
37 #include "composer/internal/char_chunk.h"
38 #include "composer/internal/composition_input.h"
39 #include "composer/internal/transliterators.h"
40 #include "composer/table.h"
41 #include "testing/base/public/gunit.h"
42
43 namespace mozc {
44 namespace composer {
45 namespace {
46
GetString(const Composition & composition)47 string GetString(const Composition &composition) {
48 string output;
49 composition.GetString(&output);
50 return output;
51 }
52
GetRawString(const Composition & composition)53 string GetRawString(const Composition &composition) {
54 string output;
55 composition.GetStringWithTransliterator(Transliterators::RAW_STRING, &output);
56 return output;
57 }
58
SetInput(const string & raw,const string & conversion,const bool is_new_input,CompositionInput * input)59 void SetInput(const string &raw,
60 const string &conversion,
61 const bool is_new_input,
62 CompositionInput *input) {
63 input->Clear();
64 input->set_raw(raw);
65 if (!conversion.empty()) {
66 input->set_conversion(conversion);
67 }
68 input->set_is_new_input(is_new_input);
69 }
70
InsertCharacters(const string & input,size_t pos,Composition * composition)71 size_t InsertCharacters(const string &input,
72 size_t pos,
73 Composition *composition) {
74 for (size_t i = 0; i < input.size(); ++i) {
75 pos = composition->InsertAt(pos, input.substr(i, 1));
76 }
77 return pos;
78 }
79
80 } // namespace
81
82 class CompositionTest : public testing::Test {
83 protected:
SetUp()84 virtual void SetUp() {
85 table_.reset(new Table);
86 composition_.reset(new Composition(table_.get()));
87 composition_->SetInputMode(Transliterators::CONVERSION_STRING);
88 }
89
90 std::unique_ptr<Table> table_;
91 std::unique_ptr<Composition> composition_;
92 };
93
InitComposition(Composition * comp)94 static int InitComposition(Composition* comp) {
95 static const struct TestCharChunk {
96 const char* conversion;
97 const char* pending;
98 const char* raw;
99 } test_chunks[] = {
100 // "あ ky き った っty" (9 chars)
101 // a ky ki tta tty
102 { "あ", "", "a" },
103 { "", "ky", "ky" },
104 { "き", "", "ki" },
105 { "った", "", "tta" },
106 { "っ", "ty", "tty" },
107 };
108 static const int test_chunks_size = arraysize(test_chunks);
109 CharChunkList::iterator it;
110 comp->MaybeSplitChunkAt(0, &it);
111 for (int i = 0; i < test_chunks_size; ++i) {
112 const TestCharChunk& data = test_chunks[i];
113 CharChunk* chunk = *comp->InsertChunk(&it);
114 chunk->set_conversion(data.conversion);
115 chunk->set_pending(data.pending);
116 chunk->set_raw(data.raw);
117 }
118 return test_chunks_size;
119 }
120
AppendChunk(const char * conversion,const char * pending,const char * raw,Composition * comp)121 static CharChunk *AppendChunk(const char *conversion,
122 const char *pending,
123 const char *raw,
124 Composition *comp) {
125 CharChunkList::iterator it;
126 comp->MaybeSplitChunkAt(comp->GetLength(), &it);
127
128 CharChunk* chunk = *comp->InsertChunk(&it);
129 chunk->set_conversion(conversion);
130 chunk->set_pending(pending);
131 chunk->set_raw(raw);
132 return chunk;
133 }
134
TEST_F(CompositionTest,GetChunkLength)135 TEST_F(CompositionTest, GetChunkLength) {
136 static const struct TestCase {
137 const char* conversion;
138 const char* pending;
139 const char* raw;
140 const int expected_conv_length;
141 const int expected_raw_length;
142 } test_cases[] = {
143 { "あ", "", "a", 1, 1 },
144 { "", "ky", "ky", 2, 2 },
145 { "き", "", "ki", 1, 2 },
146 { "った", "", "tta", 2, 3 },
147 { "っ", "ty", "tty", 3, 3 },
148 };
149 CharChunk *chunk = AppendChunk("", "", "", composition_.get());
150
151 for (int i = 0; i < arraysize(test_cases); ++i) {
152 const TestCase& test = test_cases[i];
153 chunk->set_conversion(test.conversion);
154 chunk->set_pending(test.pending);
155 chunk->set_raw(test.raw);
156
157 const int conv_length =
158 chunk->GetLength(Transliterators::CONVERSION_STRING);
159 EXPECT_EQ(test.expected_conv_length, conv_length);
160
161 const int raw_length = chunk->GetLength(Transliterators::RAW_STRING);
162 EXPECT_EQ(test.expected_raw_length, raw_length);
163 }
164 }
165
166 namespace {
TestGetChunkAt(Composition * comp,Transliterators::Transliterator transliterator,const size_t index,const size_t expected_index,const size_t expected_inner_position)167 bool TestGetChunkAt(Composition *comp,
168 Transliterators::Transliterator transliterator,
169 const size_t index,
170 const size_t expected_index,
171 const size_t expected_inner_position) {
172 CharChunkList::iterator it;
173 CharChunkList::const_iterator expected_it;
174 size_t inner_position;
175
176 expected_it = comp->GetCharChunkList().begin();
177 for (int j = 0; j < expected_index; ++j, ++expected_it) {}
178
179 comp->GetChunkAt(index, transliterator, &it, &inner_position);
180 if (it == comp->GetCharChunkList().end()) {
181 EXPECT_TRUE(expected_it == it);
182 EXPECT_EQ(expected_inner_position, inner_position);
183 } else {
184 string result, expected_result;
185 EXPECT_EQ((*expected_it)->conversion(), (*it)->conversion());
186 EXPECT_EQ((*expected_it)->pending(), (*it)->pending());
187 EXPECT_EQ((*expected_it)->raw(), (*it)->raw());
188 EXPECT_EQ(expected_inner_position, inner_position);
189 }
190 return true;
191 }
192 } // namespace
193
TEST_F(CompositionTest,GetChunkAt)194 TEST_F(CompositionTest, GetChunkAt) {
195 InitComposition(composition_.get());
196
197 TestGetChunkAt(composition_.get(),
198 Transliterators::CONVERSION_STRING, 0, 0, 0);
199 TestGetChunkAt(composition_.get(),
200 Transliterators::CONVERSION_STRING, 1, 0, 1);
201 TestGetChunkAt(composition_.get(),
202 Transliterators::CONVERSION_STRING, 2, 1, 1);
203 TestGetChunkAt(composition_.get(),
204 Transliterators::CONVERSION_STRING, 3, 1, 2);
205 TestGetChunkAt(composition_.get(),
206 Transliterators::CONVERSION_STRING, 4, 2, 1);
207 TestGetChunkAt(composition_.get(),
208 Transliterators::CONVERSION_STRING, 5, 3, 1);
209 TestGetChunkAt(composition_.get(),
210 Transliterators::CONVERSION_STRING, 6, 3, 2);
211 TestGetChunkAt(composition_.get(),
212 Transliterators::CONVERSION_STRING, 7, 4, 1);
213 TestGetChunkAt(composition_.get(),
214 Transliterators::CONVERSION_STRING, 8, 4, 2);
215 TestGetChunkAt(composition_.get(),
216 Transliterators::CONVERSION_STRING, 9, 4, 3);
217 // end
218 TestGetChunkAt(composition_.get(),
219 Transliterators::CONVERSION_STRING, 10, 4, 3);
220 // end
221 TestGetChunkAt(composition_.get(),
222 Transliterators::CONVERSION_STRING, 11, 4, 3);
223
224 TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 0, 0, 0);
225 TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 1, 0, 1);
226 TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 2, 1, 1);
227 TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 3, 1, 2);
228 TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 4, 2, 1);
229 TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 5, 2, 2);
230 TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 6, 3, 1);
231 TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 7, 3, 2);
232 TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 8, 3, 3);
233 TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 9, 4, 1);
234 TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 10, 4, 2);
235 TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 11, 4, 3);
236 // end
237 TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 12, 4, 3);
238 // end
239 TestGetChunkAt(composition_.get(), Transliterators::RAW_STRING, 13, 4, 3);
240 }
241
TEST_F(CompositionTest,GetString)242 TEST_F(CompositionTest, GetString) {
243 InitComposition(composition_.get());
244 string composition;
245
246 const size_t dummy_position = 0;
247
248 // Test RAW mode
249 composition_->SetDisplayMode(dummy_position, Transliterators::RAW_STRING);
250 composition_->GetString(&composition);
251 EXPECT_EQ("akykittatty", composition);
252
253 // Test CONVERSION mode
254 composition_->SetDisplayMode(dummy_position,
255 Transliterators::CONVERSION_STRING);
256 composition_->GetString(&composition);
257 EXPECT_EQ("あkyきったっty", composition);
258 }
259
TEST_F(CompositionTest,GetStringWithDisplayMode)260 TEST_F(CompositionTest, GetStringWithDisplayMode) {
261 AppendChunk("も", "", "mo", composition_.get());
262 AppendChunk("ず", "", "z", composition_.get());
263 AppendChunk("く", "", "c", composition_.get());
264
265 string composition;
266 composition_->GetStringWithTransliterator(Transliterators::CONVERSION_STRING,
267 &composition);
268 EXPECT_EQ("もずく", composition);
269
270 composition_->GetStringWithTransliterator(Transliterators::RAW_STRING,
271 &composition);
272 EXPECT_EQ("mozc", composition);
273 }
274
TEST_F(CompositionTest,SplitRawChunk)275 TEST_F(CompositionTest, SplitRawChunk) {
276 static const struct TestCase {
277 const char* conversion;
278 const char* pending;
279 const char* raw;
280 const int position;
281 const char* expected_left_conversion;
282 const char* expected_left_pending;
283 const char* expected_left_raw;
284 const char* expected_right_conversion;
285 const char* expected_right_pending;
286 const char* expected_right_raw;
287 } test_cases[] = {
288 { "あ", "", "a", 0, "", "", "", "あ", "", "a" },
289 { "", "ky", "ky", 1, "", "k", "k", "", "y", "y" },
290 { "き", "", "ki", 1, "k", "", "k", "i", "", "i" },
291 { "った", "", "tta", 1, "t", "", "t", "ta", "", "ta" },
292 { "った", "", "tta", 2, "tt", "", "tt", "a", "", "a" },
293 { "っ", "ty", "tty", 1, "っ", "", "t", "", "ty", "ty" },
294 { "っ", "ty", "tty", 2, "っ", "t", "tt", "", "y", "y" },
295 { "っ", "ty", "tty", 3, "", "", "", "っ", "ty", "tty" },
296 };
297 for (int i = 0; i < arraysize(test_cases); ++i) {
298 const TestCase& test = test_cases[i];
299 CharChunk right_orig_chunk(Transliterators::CONVERSION_STRING, NULL);
300 right_orig_chunk.set_conversion(test.conversion);
301 right_orig_chunk.set_pending(test.pending);
302 right_orig_chunk.set_raw(test.raw);
303 CharChunk *left_new_chunk_ptr = NULL;
304 right_orig_chunk.SplitChunk(Transliterators::RAW_STRING,
305 test.position, &left_new_chunk_ptr);
306 std::unique_ptr<CharChunk> left_new_chunk(left_new_chunk_ptr);
307
308 if (left_new_chunk.get() != NULL) {
309 EXPECT_EQ(test.expected_left_conversion, left_new_chunk->conversion());
310 EXPECT_EQ(test.expected_left_pending, left_new_chunk->pending());
311 EXPECT_EQ(test.expected_left_raw, left_new_chunk->raw());
312 }
313
314 EXPECT_EQ(test.expected_right_conversion, right_orig_chunk.conversion());
315 EXPECT_EQ(test.expected_right_pending, right_orig_chunk.pending());
316 EXPECT_EQ(test.expected_right_raw, right_orig_chunk.raw());
317 }
318 }
319
TEST_F(CompositionTest,SplitConversionChunk)320 TEST_F(CompositionTest, SplitConversionChunk) {
321 static const struct TestCase {
322 const char* conversion;
323 const char* pending;
324 const char* raw;
325 const int position;
326 const char* expected_left_conversion;
327 const char* expected_left_pending;
328 const char* expected_left_raw;
329 const char* expected_right_conversion;
330 const char* expected_right_pending;
331 const char* expected_right_raw;
332 } test_cases[] = {
333 { "あ", "", "a", 0, "", "", "", "あ", "", "a" },
334 { "", "ky", "ky", 1, "", "k", "k", "", "y", "y" },
335 { "きょ", "", "kyo", 1, "き", "", "き", "ょ", "", "ょ" },
336 { "っ", "t", "tt", 1, "っ", "", "t", "", "t", "t" },
337 { "った", "", "tta", 1, "っ", "", "っ", "た", "", "た" },
338 { "っ", "ty", "tty", 1, "っ", "", "t", "", "ty", "ty" },
339 { "っ", "ty", "tty", 2, "っ", "t", "tt", "", "y", "y" },
340 { "っ", "ty", "tty", 3, "", "", "", "っ", "ty", "tty" },
341 };
342 for (int i = 0; i < arraysize(test_cases); ++i) {
343 const TestCase& test = test_cases[i];
344 CharChunk right_orig_chunk(Transliterators::CONVERSION_STRING, NULL);
345 right_orig_chunk.set_conversion(test.conversion);
346 right_orig_chunk.set_pending(test.pending);
347 right_orig_chunk.set_raw(test.raw);
348 CharChunk *left_new_chunk_ptr = NULL;
349 right_orig_chunk.SplitChunk(Transliterators::CONVERSION_STRING,
350 test.position, &left_new_chunk_ptr);
351 std::unique_ptr<CharChunk> left_new_chunk(left_new_chunk_ptr);
352
353 if (left_new_chunk.get() != NULL) {
354 EXPECT_EQ(test.expected_left_conversion, left_new_chunk->conversion());
355 EXPECT_EQ(test.expected_left_pending, left_new_chunk->pending());
356 EXPECT_EQ(test.expected_left_raw, left_new_chunk->raw());
357 }
358
359 EXPECT_EQ(test.expected_right_conversion, right_orig_chunk.conversion());
360 EXPECT_EQ(test.expected_right_pending, right_orig_chunk.pending());
361 EXPECT_EQ(test.expected_right_raw, right_orig_chunk.raw());
362 }
363 }
364
TEST_F(CompositionTest,GetLength)365 TEST_F(CompositionTest, GetLength) {
366 table_->AddRule("a", "A", "");
367 table_->AddRule("ka", "K", "");
368
369 EXPECT_EQ(0, composition_->GetLength());
370
371 InsertCharacters("aka", 0, composition_.get());
372 EXPECT_EQ(2, composition_->GetLength());
373 }
374
TEST_F(CompositionTest,MaybeSplitChunkAt)375 TEST_F(CompositionTest, MaybeSplitChunkAt) {
376 static const struct TestCase {
377 const int position;
378 const int expected_raw_chunks_size;
379 const int expected_conv_chunks_size;
380 } test_cases[] = {
381 // "あ ky き った っty" (9 chars)
382 // a ky ki tta tty (11 chars)
383 { 0, 5, 5 },
384 { 1, 5, 5 },
385 { 2, 6, 6 },
386 { 3, 5, 5 },
387 { 4, 6, 5 },
388 { 5, 5, 6 },
389 { 6, 6, 5 },
390 { 7, 6, 6 },
391 { 8, 5, 6 },
392 { 9, 6, 5 },
393 { 10, 6, 5 },
394 { 11, 5, 5 },
395 { 12, 5, 5 },
396 };
397 const size_t dummy_position = 0;
398 for (int i = 0; i < arraysize(test_cases); ++i) {
399 const TestCase& test = test_cases[i];
400
401 { // Test RAW mode
402 Composition raw_comp(table_.get());
403 InitComposition(&raw_comp);
404 raw_comp.SetDisplayMode(dummy_position, Transliterators::RAW_STRING);
405 CharChunkList::iterator raw_it;
406
407 raw_comp.MaybeSplitChunkAt(test.position, &raw_it);
408 const size_t raw_chunks_size = raw_comp.GetCharChunkList().size();
409 EXPECT_EQ(test.expected_raw_chunks_size, raw_chunks_size);
410 }
411
412 { // Test CONVERSION mode
413 Composition conv_comp(table_.get());
414 InitComposition(&conv_comp);
415 conv_comp.SetDisplayMode(dummy_position,
416 Transliterators::CONVERSION_STRING);
417 CharChunkList::iterator conv_it;
418
419 conv_comp.MaybeSplitChunkAt(test.position, &conv_it);
420 const size_t conv_chunks_size = conv_comp.GetCharChunkList().size();
421 EXPECT_EQ(test.expected_conv_chunks_size, conv_chunks_size);
422 }
423 }
424 }
425
426 namespace {
GetDeletedString(Transliterators::Transliterator t12r,const int position)427 string GetDeletedString(Transliterators::Transliterator t12r,
428 const int position) {
429 std::unique_ptr<Table> table(new Table);
430 std::unique_ptr<Composition> comp(new Composition(table.get()));
431
432 InitComposition(comp.get());
433 comp->SetDisplayMode(0, t12r);
434 comp->DeleteAt(position);
435 string composition;
436 comp->GetString(&composition);
437
438 comp.reset();
439 table.reset();
440 return composition;
441 }
442 } // namespace
443
TEST_F(CompositionTest,DeleteAt)444 TEST_F(CompositionTest, DeleteAt) {
445 // "あkyきったっty" is the original string
446 EXPECT_EQ("kyきったっty",
447 GetDeletedString(Transliterators::CONVERSION_STRING, 0));
448 EXPECT_EQ("あyきったっty",
449 GetDeletedString(Transliterators::CONVERSION_STRING, 1));
450 EXPECT_EQ("あkきったっty",
451 GetDeletedString(Transliterators::CONVERSION_STRING, 2));
452 EXPECT_EQ("あkyったっty",
453 GetDeletedString(Transliterators::CONVERSION_STRING, 3));
454 EXPECT_EQ("あkyきたっty",
455 GetDeletedString(Transliterators::CONVERSION_STRING, 4));
456 EXPECT_EQ("あkyきっっty",
457 GetDeletedString(Transliterators::CONVERSION_STRING, 5));
458 EXPECT_EQ("あkyきったty",
459 GetDeletedString(Transliterators::CONVERSION_STRING, 6));
460 EXPECT_EQ("あkyきったっy",
461 GetDeletedString(Transliterators::CONVERSION_STRING, 7));
462 EXPECT_EQ("あkyきったっt",
463 GetDeletedString(Transliterators::CONVERSION_STRING, 8));
464 // end
465 EXPECT_EQ("あkyきったっty",
466 GetDeletedString(Transliterators::CONVERSION_STRING, 9));
467 EXPECT_EQ("あkyきったっty",
468 GetDeletedString(Transliterators::CONVERSION_STRING, -1));
469
470 // "akykittatty" is the original string
471 EXPECT_EQ("kykittatty", GetDeletedString(Transliterators::RAW_STRING, 0));
472 EXPECT_EQ("aykittatty", GetDeletedString(Transliterators::RAW_STRING, 1));
473 EXPECT_EQ("akkittatty", GetDeletedString(Transliterators::RAW_STRING, 2));
474 EXPECT_EQ("akyittatty", GetDeletedString(Transliterators::RAW_STRING, 3));
475 EXPECT_EQ("akykttatty", GetDeletedString(Transliterators::RAW_STRING, 4));
476 EXPECT_EQ("akykitatty", GetDeletedString(Transliterators::RAW_STRING, 5));
477 EXPECT_EQ("akykitatty", GetDeletedString(Transliterators::RAW_STRING, 6));
478 EXPECT_EQ("akykitttty", GetDeletedString(Transliterators::RAW_STRING, 7));
479 EXPECT_EQ("akykittaty", GetDeletedString(Transliterators::RAW_STRING, 8));
480 EXPECT_EQ("akykittaty", GetDeletedString(Transliterators::RAW_STRING, 9));
481 EXPECT_EQ("akykittatt", GetDeletedString(Transliterators::RAW_STRING, 10));
482 // end
483 EXPECT_EQ("akykittatty", GetDeletedString(Transliterators::RAW_STRING, 11));
484 EXPECT_EQ("akykittatty", GetDeletedString(Transliterators::RAW_STRING, -1));
485 }
486
TEST_F(CompositionTest,DeleteAt_InvisibleCharacter)487 TEST_F(CompositionTest, DeleteAt_InvisibleCharacter) {
488 CharChunkList::iterator it;
489 CharChunk *chunk;
490
491 composition_->MaybeSplitChunkAt(0, &it);
492
493 chunk = *composition_->InsertChunk(&it);
494 chunk->set_raw("1");
495 chunk->set_pending(Table::ParseSpecialKey("{1}"));
496
497 chunk = *composition_->InsertChunk(&it);
498 chunk->set_raw("2");
499 chunk->set_pending(Table::ParseSpecialKey("{2}2"));
500
501 chunk = *composition_->InsertChunk(&it);
502 chunk->set_raw("3");
503 chunk->set_pending("3");
504
505 // Now the CharChunks in the comp are expected to be following;
506 // (raw, pending) = [ ("1", "{1}"), ("2", "{2}2"), ("3", "3") ]
507 // {} means invisible characters.
508
509 composition_->DeleteAt(0);
510 string composition;
511 composition_->GetString(&composition);
512 EXPECT_EQ("3", composition);
513 }
514
515 namespace {
516
InitTable(Table * table)517 void InitTable(Table* table) {
518 table->AddRule("i", "い", "");
519 table->AddRule("ki", "き", "");
520 table->AddRule("kyi", "きぃ", "");
521 table->AddRule("ti", "ち", "");
522 table->AddRule("tya", "ちゃ", "");
523 table->AddRule("tyi", "ちぃ", "");
524 table->AddRule("ya", "や", "");
525 table->AddRule("yy", "っ", "y");
526 }
527
GetInsertedString(Transliterators::Transliterator t12r,const size_t position,const string & input)528 string GetInsertedString(Transliterators::Transliterator t12r,
529 const size_t position,
530 const string &input) {
531 std::unique_ptr<Table> table(new Table);
532 InitTable(table.get());
533 std::unique_ptr<Composition> comp(new Composition(table.get()));
534 InitComposition(comp.get());
535
536 comp->SetTable(table.get());
537 comp->SetDisplayMode(0, t12r);
538 comp->InsertAt(position, input);
539
540 string composition;
541 comp->GetString(&composition);
542
543 comp.reset();
544 table.reset();
545
546 return composition;
547 }
548 } // namespace
549
TEST_F(CompositionTest,InsertAt)550 TEST_F(CompositionTest, InsertAt) {
551 // "あkyきったっty" is the original string
552 EXPECT_EQ("いあkyきったっty",
553 GetInsertedString(Transliterators::CONVERSION_STRING, 0, "i"));
554 EXPECT_EQ("あいkyきったっty",
555 GetInsertedString(Transliterators::CONVERSION_STRING, 1, "i"));
556 EXPECT_EQ("あきyきったっty",
557 GetInsertedString(Transliterators::CONVERSION_STRING, 2, "i"));
558 EXPECT_EQ("あきぃきったっty",
559 GetInsertedString(Transliterators::CONVERSION_STRING, 3, "i"));
560 EXPECT_EQ("あkyきいったっty",
561 GetInsertedString(Transliterators::CONVERSION_STRING, 4, "i"));
562 EXPECT_EQ("あkyきっいたっty",
563 GetInsertedString(Transliterators::CONVERSION_STRING, 5, "i"));
564 EXPECT_EQ("あkyきったっちぃ",
565 GetInsertedString(Transliterators::CONVERSION_STRING, 9, "i"));
566 EXPECT_EQ("yあkyきったっty",
567 GetInsertedString(Transliterators::CONVERSION_STRING, 0, "y"));
568 EXPECT_EQ("あykyきったっty",
569 GetInsertedString(Transliterators::CONVERSION_STRING, 1, "y"));
570 EXPECT_EQ("あkyyきったっty",
571 GetInsertedString(Transliterators::CONVERSION_STRING, 2, "y"));
572 EXPECT_EQ("あkyyきったっty",
573 GetInsertedString(Transliterators::CONVERSION_STRING, 3, "y"));
574 EXPECT_EQ("あkyきyったっty",
575 GetInsertedString(Transliterators::CONVERSION_STRING, 4, "y"));
576 EXPECT_EQ("あkyきっyたっty",
577 GetInsertedString(Transliterators::CONVERSION_STRING, 5, "y"));
578 // end
579 EXPECT_EQ("あkyきったっちぃ",
580 GetInsertedString(Transliterators::CONVERSION_STRING, 9, "i"));
581 // end
582 EXPECT_EQ("あkyきったっtyy",
583 GetInsertedString(Transliterators::CONVERSION_STRING, 9, "y"));
584
585 // "akykittatty" is the original string
586 EXPECT_EQ("iakykittatty",
587 GetInsertedString(Transliterators::RAW_STRING, 0, "i"));
588
589 EXPECT_EQ("aikykittatty",
590 GetInsertedString(Transliterators::RAW_STRING, 1, "i"));
591
592 EXPECT_EQ("akiykittatty",
593 GetInsertedString(Transliterators::RAW_STRING, 2, "i"));
594
595 EXPECT_EQ("akyikittatty",
596 GetInsertedString(Transliterators::RAW_STRING, 3, "i"));
597
598 EXPECT_EQ("akykiittatty",
599 GetInsertedString(Transliterators::RAW_STRING, 4, "i"));
600
601 EXPECT_EQ("akykiittatty",
602 GetInsertedString(Transliterators::RAW_STRING, 5, "i"));
603
604 EXPECT_EQ("akykittattyi",
605 GetInsertedString(Transliterators::RAW_STRING, 11, "i")); // end
606 }
607
TEST_F(CompositionTest,GetExpandedStrings)608 TEST_F(CompositionTest, GetExpandedStrings) {
609 Table table;
610 InitTable(&table);
611 composition_->SetTable(&table);
612 InitComposition(composition_.get());
613
614 // a ky ki tta tty
615 string base;
616 std::set<string> expanded;
617 composition_->GetExpandedStrings(&base, &expanded);
618 EXPECT_EQ("あkyきったっ", base);
619 EXPECT_EQ(2, expanded.size());
620 // You cannot use EXPECT_NE here because it causes compile error in gtest
621 // when the compiler is Visual C++. b/5655673
622 EXPECT_TRUE(expanded.find("ちぃ") != expanded.end());
623 // You cannot use EXPECT_NE here because it causes compile error in gtest
624 // when the compiler is Visual C++. b/5655673
625 EXPECT_TRUE(expanded.find("ちゃ") != expanded.end());
626 }
627
TEST_F(CompositionTest,ConvertPosition)628 TEST_F(CompositionTest, ConvertPosition) {
629 // Test against http://b/1550597
630
631 // Invalid positions.
632 EXPECT_EQ(0,
633 composition_->ConvertPosition(
634 static_cast<size_t>(-1),
635 Transliterators::CONVERSION_STRING,
636 Transliterators::RAW_STRING));
637 EXPECT_EQ(0,
638 composition_->ConvertPosition(
639 0,
640 Transliterators::CONVERSION_STRING,
641 Transliterators::RAW_STRING));
642 EXPECT_EQ(0,
643 composition_->ConvertPosition(
644 1,
645 Transliterators::CONVERSION_STRING,
646 Transliterators::RAW_STRING));
647 EXPECT_EQ(0,
648 composition_->ConvertPosition(
649 0,
650 Transliterators::RAW_STRING,
651 Transliterators::CONVERSION_STRING));
652 EXPECT_EQ(0,
653 composition_->ConvertPosition(
654 static_cast<size_t>(-1),
655 Transliterators::RAW_STRING,
656 Transliterators::CONVERSION_STRING));
657 EXPECT_EQ(0,
658 composition_->ConvertPosition(
659 1,
660 Transliterators::RAW_STRING,
661 Transliterators::CONVERSION_STRING));
662
663 AppendChunk("ね", "", "ne", composition_.get());
664 AppendChunk("っと", "", "tto", composition_.get());
665
666 // "|ねっと" -> "|netto"
667 EXPECT_EQ(0,
668 composition_->ConvertPosition(
669 0,
670 Transliterators::CONVERSION_STRING,
671 Transliterators::RAW_STRING));
672 // "ね|っと" -> "ne|tto"
673 EXPECT_EQ(2,
674 composition_->ConvertPosition(
675 1,
676 Transliterators::CONVERSION_STRING,
677 Transliterators::RAW_STRING));
678 // "ねっ|と" -> "net|to"
679 EXPECT_EQ(3,
680 composition_->ConvertPosition(
681 2,
682 Transliterators::CONVERSION_STRING,
683 Transliterators::RAW_STRING));
684 // "ねっと|" -> "netto|"
685 EXPECT_EQ(5,
686 composition_->ConvertPosition(
687 3,
688 Transliterators::CONVERSION_STRING,
689 Transliterators::RAW_STRING));
690
691 // Invalid positions.
692 EXPECT_EQ(5,
693 composition_->ConvertPosition(
694 static_cast<size_t>(-1),
695 Transliterators::CONVERSION_STRING,
696 Transliterators::RAW_STRING));
697 EXPECT_EQ(5,
698 composition_->ConvertPosition(
699 4,
700 Transliterators::CONVERSION_STRING,
701 Transliterators::RAW_STRING));
702
703 // "|netto" -> "|ねっと"
704 EXPECT_EQ(0,
705 composition_->ConvertPosition(
706 0,
707 Transliterators::RAW_STRING,
708 Transliterators::CONVERSION_STRING));
709 // "n|etto" -> "ね|っと"
710 EXPECT_EQ(1,
711 composition_->ConvertPosition(
712 1,
713 Transliterators::RAW_STRING,
714 Transliterators::CONVERSION_STRING));
715 // "ne|tto" -> "ね|っと"
716 EXPECT_EQ(1,
717 composition_->ConvertPosition(
718 2,
719 Transliterators::RAW_STRING,
720 Transliterators::CONVERSION_STRING));
721 // "net|to" -> "ねっ|と"
722 EXPECT_EQ(2,
723 composition_->ConvertPosition(
724 3,
725 Transliterators::RAW_STRING,
726 Transliterators::CONVERSION_STRING));
727 // "nett|o" -> "ねっと|"
728 EXPECT_EQ(3,
729 composition_->ConvertPosition(
730 4,
731 Transliterators::RAW_STRING,
732 Transliterators::CONVERSION_STRING));
733 // "netto|" -> "ねっと|"
734 EXPECT_EQ(3,
735 composition_->ConvertPosition(
736 5,
737 Transliterators::RAW_STRING,
738 Transliterators::CONVERSION_STRING));
739 // Invalid positions.
740 EXPECT_EQ(3,
741 composition_->ConvertPosition(
742 static_cast<size_t>(-1),
743 Transliterators::RAW_STRING,
744 Transliterators::CONVERSION_STRING));
745 EXPECT_EQ(3,
746 composition_->ConvertPosition(
747 6,
748 Transliterators::RAW_STRING,
749 Transliterators::CONVERSION_STRING));
750
751 CharChunkList::iterator chunk_it;
752 size_t inner_position;
753 composition_->GetChunkAt(5, Transliterators::RAW_STRING,
754 &chunk_it, &inner_position);
755
756 EXPECT_EQ("tto", (*chunk_it)->raw());
757 EXPECT_EQ(3, inner_position);
758 }
759
TEST_F(CompositionTest,SetDisplayMode)760 TEST_F(CompositionTest, SetDisplayMode) {
761 AppendChunk("も", "", "mo", composition_.get());
762 AppendChunk("ず", "", "zu", composition_.get());
763 AppendChunk("く", "", "ku", composition_.get());
764
765 CharChunkList::iterator chunk_it;
766 size_t inner_position;
767 composition_->GetChunkAt(0, Transliterators::CONVERSION_STRING,
768 &chunk_it, &inner_position);
769 EXPECT_EQ("mo", (*chunk_it)->raw());
770 EXPECT_EQ(0, inner_position);
771 composition_->GetChunkAt(1, Transliterators::CONVERSION_STRING,
772 &chunk_it, &inner_position);
773 EXPECT_EQ("mo", (*chunk_it)->raw());
774 EXPECT_EQ(1, inner_position);
775 composition_->GetChunkAt(2, Transliterators::CONVERSION_STRING,
776 &chunk_it, &inner_position);
777 EXPECT_EQ("zu", (*chunk_it)->raw());
778 EXPECT_EQ(1, inner_position);
779 composition_->GetChunkAt(3, Transliterators::CONVERSION_STRING,
780 &chunk_it, &inner_position);
781 EXPECT_EQ("ku", (*chunk_it)->raw());
782 EXPECT_EQ(1, inner_position);
783
784 EXPECT_EQ(6,
785 composition_->SetDisplayMode(1,
786 Transliterators::RAW_STRING));
787 EXPECT_EQ(3,
788 composition_->SetDisplayMode(2,
789 Transliterators::CONVERSION_STRING));
790 EXPECT_EQ(6,
791 composition_->SetDisplayMode(2,
792 Transliterators::RAW_STRING));
793 }
794
TEST_F(CompositionTest,GetStringWithTrimMode)795 TEST_F(CompositionTest, GetStringWithTrimMode) {
796 Table table;
797 table.AddRule("ka", "か", "");
798 table.AddRule("n", "ん", "");
799 // This makes the above rule ambiguous.
800 table.AddRule("na", "な", "");
801 composition_->SetTable(&table);
802
803 string output_empty;
804 composition_->GetStringWithTrimMode(TRIM, &output_empty);
805 EXPECT_TRUE(output_empty.empty());
806
807 size_t pos = 0;
808 pos = composition_->InsertAt(pos, "k");
809 pos = composition_->InsertAt(pos, "a");
810 pos = composition_->InsertAt(pos, "n");
811
812 string output_trim;
813 composition_->GetStringWithTrimMode(TRIM, &output_trim);
814 EXPECT_EQ("か", output_trim);
815
816 string output_asis;
817 composition_->GetStringWithTrimMode(ASIS, &output_asis);
818 EXPECT_EQ("かn", output_asis);
819
820 string output_fix;
821 composition_->GetStringWithTrimMode(FIX, &output_asis);
822 EXPECT_EQ("かん", output_asis);
823 }
824
TEST_F(CompositionTest,InsertKeyAndPreeditAt)825 TEST_F(CompositionTest, InsertKeyAndPreeditAt) {
826 Table table;
827 table.AddRule("す゛", "ず", "");
828 table.AddRule("く゛", "ぐ", "");
829 composition_->SetTable(&table);
830
831 size_t pos = 0;
832 pos = composition_->InsertKeyAndPreeditAt(pos, "m", "も");
833 pos = composition_->InsertKeyAndPreeditAt(pos, "r", "す");
834 pos = composition_->InsertKeyAndPreeditAt(pos, "@", "゛");
835 pos = composition_->InsertKeyAndPreeditAt(pos, "h", "く");
836 pos = composition_->InsertKeyAndPreeditAt(pos, "!", "!");
837
838 string comp_str;
839 composition_->GetString(&comp_str);
840 EXPECT_EQ("もずく!", comp_str);
841
842 string comp_ascii_str;
843 composition_->GetStringWithTransliterator(
844 Transliterators::RAW_STRING, &comp_ascii_str);
845 EXPECT_EQ("mr@h!", comp_ascii_str);
846 }
847
TEST_F(CompositionTest,InsertKey_ForN)848 TEST_F(CompositionTest, InsertKey_ForN) {
849 Table table;
850 table.AddRule("a", "[A]", "");
851 table.AddRule("n", "[N]", "");
852 table.AddRule("nn", "[N]", "");
853 table.AddRule("na", "[NA]", "");
854 table.AddRule("nya", "[NYA]", "");
855 table.AddRule("ya", "[YA]", "");
856 table.AddRule("ka", "[KA]", "");
857 composition_->SetTable(&table);
858
859 size_t pos = 0;
860 pos = composition_->InsertAt(pos, "n");
861 pos = composition_->InsertAt(pos, "y");
862 pos = composition_->InsertAt(pos, "n");
863 pos = composition_->InsertAt(pos, "y");
864 pos = composition_->InsertAt(pos, "a");
865
866 string comp_str;
867 composition_->GetString(&comp_str);
868 EXPECT_EQ("ny[NYA]", comp_str);
869 }
870
TEST_F(CompositionTest,GetStringWithDisplayMode_ForKana)871 TEST_F(CompositionTest, GetStringWithDisplayMode_ForKana) {
872 Table table;
873 // Empty table is OK.
874 composition_->SetTable(&table);
875
876 size_t pos = 0;
877 pos = composition_->InsertKeyAndPreeditAt(pos, "m", "も");
878
879 string comp_str;
880 composition_->GetStringWithTransliterator(
881 Transliterators::RAW_STRING, &comp_str);
882 EXPECT_EQ("m", comp_str);
883 }
884
TEST_F(CompositionTest,InputMode)885 TEST_F(CompositionTest, InputMode) {
886 Table table;
887 table.AddRule("a", "あ", "");
888 table.AddRule("ka", "か", "");
889 composition_->SetTable(&table);
890
891 size_t pos = 0;
892 pos = composition_->InsertAt(pos, "k");
893
894 string result;
895 composition_->GetString(&result);
896 EXPECT_EQ("k", result);
897
898 composition_->SetInputMode(Transliterators::FULL_KATAKANA);
899 pos = composition_->InsertAt(pos, "a");
900 composition_->GetString(&result);
901 // If a vowel and a consonant were typed with different
902 // transliterators, these characters should not be combined.
903 EXPECT_EQ("kア", result);
904
905 composition_->SetInputMode(Transliterators::HALF_ASCII);
906 pos = composition_->InsertAt(pos, "k");
907 composition_->GetString(&result);
908 EXPECT_EQ("kアk", result);
909
910 composition_->SetInputMode(Transliterators::HIRAGANA);
911 pos = composition_->InsertAt(pos, "a");
912 composition_->GetString(&result);
913 EXPECT_EQ("kアkあ", result);
914
915 EXPECT_EQ(Transliterators::CONVERSION_STRING,
916 composition_->GetTransliterator(0));
917 EXPECT_EQ(Transliterators::CONVERSION_STRING,
918 composition_->GetTransliterator(1));
919 EXPECT_EQ(Transliterators::FULL_KATAKANA, composition_->GetTransliterator(2));
920 EXPECT_EQ(Transliterators::HALF_ASCII, composition_->GetTransliterator(3));
921 EXPECT_EQ(Transliterators::HIRAGANA, composition_->GetTransliterator(4));
922 EXPECT_EQ(Transliterators::HIRAGANA, composition_->GetTransliterator(5));
923 EXPECT_EQ(Transliterators::HIRAGANA, composition_->GetTransliterator(10));
924 }
925
TEST_F(CompositionTest,SetTable)926 TEST_F(CompositionTest, SetTable) {
927 Table table;
928 table.AddRule("a", "あ", "");
929 table.AddRule("ka", "か", "");
930
931 Table table2;
932 table2.AddRule("a", "あ", "");
933 table2.AddRule("ka", "か", "");
934
935 composition_->SetTable(&table);
936 composition_->SetInputMode(Transliterators::HIRAGANA);
937
938 size_t pos = 0;
939 pos = composition_->InsertAt(pos, "k");
940
941 string result;
942 composition_->GetString(&result);
943 EXPECT_EQ("k", result);
944
945 composition_->SetTable(&table2);
946
947 pos = composition_->InsertAt(pos, "a");
948 composition_->GetString(&result);
949 EXPECT_EQ("kあ", result);
950 }
951
TEST_F(CompositionTest,Transliterator)952 TEST_F(CompositionTest, Transliterator) {
953 Table table;
954 table.AddRule("a", "あ", "");
955 composition_->SetTable(&table);
956
957 // Insert "a" which is converted to "あ".
958 size_t pos = 0;
959 pos = composition_->InsertAt(pos, "a");
960 EXPECT_EQ(1, pos);
961 string result;
962 composition_->GetString(&result);
963 EXPECT_EQ("あ", result);
964
965 // Set transliterator for Half Ascii.
966 composition_->SetTransliterator(0, pos, Transliterators::HALF_ASCII);
967 composition_->GetString(&result);
968 EXPECT_EQ("a", result);
969
970 // Insert "a" again.
971 pos = composition_->InsertAt(pos, "a");
972 EXPECT_EQ(2, pos);
973 result.clear();
974 composition_->GetString(&result);
975 EXPECT_EQ("aあ", result);
976
977 // Set transliterator for Full Katakana.
978 composition_->SetTransliterator(0, pos, Transliterators::FULL_KATAKANA);
979 composition_->GetString(&result);
980 EXPECT_EQ("アア", result);
981 }
982
TEST_F(CompositionTest,HalfAsciiTransliterator)983 TEST_F(CompositionTest, HalfAsciiTransliterator) {
984 Table table;
985 table.AddRule("-", "ー", "");
986 composition_->SetTable(&table);
987 composition_->SetInputMode(Transliterators::HALF_ASCII);
988
989 size_t pos = 0;
990 pos = composition_->InsertKeyAndPreeditAt(pos, "-", "-");
991 EXPECT_EQ(1, pos);
992 EXPECT_EQ("-", GetString(*composition_));
993
994 pos = composition_->InsertKeyAndPreeditAt(pos, "-", "-");
995 EXPECT_EQ(2, pos);
996 EXPECT_EQ("--", GetString(*composition_));
997 }
998
TEST_F(CompositionTest,ShouldCommit)999 TEST_F(CompositionTest, ShouldCommit) {
1000 table_->AddRuleWithAttributes("ka", "[KA]", "", DIRECT_INPUT);
1001 table_->AddRuleWithAttributes("tt", "[X]", "t", DIRECT_INPUT);
1002 table_->AddRuleWithAttributes("ta", "[TA]", "", NO_TABLE_ATTRIBUTE);
1003
1004 size_t pos = 0;
1005
1006 pos = composition_->InsertAt(pos, "k");
1007 EXPECT_FALSE(composition_->ShouldCommit());
1008
1009 pos = composition_->InsertAt(pos, "a");
1010 EXPECT_TRUE(composition_->ShouldCommit());
1011
1012 pos = composition_->InsertAt(pos, "t");
1013 EXPECT_FALSE(composition_->ShouldCommit());
1014
1015 pos = composition_->InsertAt(pos, "t");
1016 EXPECT_FALSE(composition_->ShouldCommit());
1017
1018 pos = composition_->InsertAt(pos, "a");
1019 EXPECT_TRUE(composition_->ShouldCommit());
1020
1021 pos = composition_->InsertAt(pos, "t");
1022 EXPECT_FALSE(composition_->ShouldCommit());
1023
1024 pos = composition_->InsertAt(pos, "a");
1025 EXPECT_FALSE(composition_->ShouldCommit());
1026 EXPECT_EQ("[KA][X][TA][TA]", GetString(*composition_));
1027 }
1028
TEST_F(CompositionTest,Issue2190364)1029 TEST_F(CompositionTest, Issue2190364) {
1030 // This is a unittest against http://b/2190364
1031 Table table;
1032 composition_->SetTable(&table);
1033
1034 size_t pos = 0;
1035
1036 composition_->SetInputMode(Transliterators::FULL_ASCII);
1037 pos = composition_->InsertKeyAndPreeditAt(pos, "a", "ち");
1038 EXPECT_EQ("a", GetString(*composition_));
1039
1040 pos = composition_->InsertAt(pos, " ");
1041 EXPECT_EQ("a ", GetString(*composition_));
1042 }
1043
1044
TEST_F(CompositionTest,Issue1817410)1045 TEST_F(CompositionTest, Issue1817410) {
1046 // This is a unittest against http://b/2190364
1047 Table table;
1048 table.AddRule("ss", "っ", "s");
1049 composition_->SetTable(&table);
1050
1051 size_t pos = 0;
1052 pos = composition_->InsertAt(pos, "s");
1053 pos = composition_->InsertAt(pos, "s");
1054
1055 string preedit;
1056 composition_->GetString(&preedit);
1057 EXPECT_EQ("っs", preedit);
1058
1059 EXPECT_EQ(0, composition_->ConvertPosition(0, Transliterators::LOCAL,
1060 Transliterators::HALF_ASCII));
1061 EXPECT_EQ(1, composition_->ConvertPosition(1, Transliterators::LOCAL,
1062 Transliterators::HALF_ASCII));
1063 EXPECT_EQ(2, composition_->ConvertPosition(2, Transliterators::LOCAL,
1064 Transliterators::HALF_ASCII));
1065
1066 { // "s|s"
1067 CharChunkList::iterator chunk_it;
1068 size_t inner_position;
1069 composition_->GetChunkAt(1, Transliterators::LOCAL,
1070 &chunk_it, &inner_position);
1071 EXPECT_EQ(1, inner_position);
1072 EXPECT_EQ(2, (*chunk_it)->GetLength(Transliterators::LOCAL));
1073
1074 EXPECT_EQ(0, composition_->GetPosition(Transliterators::HALF_ASCII,
1075 chunk_it));
1076 EXPECT_EQ(2, (*chunk_it)->GetLength(Transliterators::HALF_ASCII));
1077 }
1078
1079 { // "ss|"
1080 CharChunkList::iterator chunk_it;
1081 size_t inner_position;
1082 composition_->GetChunkAt(2, Transliterators::LOCAL,
1083 &chunk_it, &inner_position);
1084 EXPECT_EQ(2, inner_position);
1085 EXPECT_EQ(2, (*chunk_it)->GetLength(Transliterators::LOCAL));
1086
1087 EXPECT_EQ(0, composition_->GetPosition(Transliterators::HALF_ASCII,
1088 chunk_it));
1089 EXPECT_EQ(2, (*chunk_it)->GetLength(Transliterators::HALF_ASCII));
1090 }
1091 }
1092
TEST_F(CompositionTest,Issue2209634)1093 TEST_F(CompositionTest, Issue2209634) {
1094 // This is a unittest against http://b/2209634
1095 // "q@" becomes "qた@".
1096 Table table;
1097 table.AddRule("q", "", "た");
1098 table.AddRule("た@", "だ", "");
1099 composition_->SetTable(&table);
1100
1101 composition_->SetInputMode(Transliterators::HALF_ASCII);
1102
1103 size_t pos = 0;
1104 pos = composition_->InsertAt(pos, "q");
1105 pos = composition_->InsertAt(pos, "@");
1106
1107 string preedit;
1108 composition_->GetString(&preedit);
1109 EXPECT_EQ("q@", preedit);
1110 }
1111
TEST_F(CompositionTest,Issue2330530)1112 TEST_F(CompositionTest, Issue2330530) {
1113 // This is a unittest against http://b/2330530
1114 // "Win" + Numpad7 becomes "Win77" instead of "Win7".
1115 Table table;
1116 table.AddRule("wi", "うぃ", "");
1117 table.AddRule("i", "い", "");
1118 table.AddRule("n", "ん", "");
1119 table.AddRule("na", "な", "");
1120 composition_->SetTable(&table);
1121
1122 composition_->SetInputMode(Transliterators::HALF_ASCII);
1123
1124 size_t pos = 0;
1125 pos = composition_->InsertAt(pos, "W");
1126 pos = composition_->InsertAt(pos, "i");
1127 pos = composition_->InsertAt(pos, "n");
1128
1129 string preedit;
1130 composition_->GetString(&preedit);
1131 EXPECT_EQ("Win", preedit);
1132
1133 pos = composition_->InsertKeyAndPreeditAt(pos, "7", "7");
1134 composition_->GetString(&preedit);
1135 EXPECT_EQ("Win7", preedit);
1136 }
1137
TEST_F(CompositionTest,Issue2819580)1138 TEST_F(CompositionTest, Issue2819580) {
1139 // This is a unittest against http://b/2819580.
1140 // 'y' after 'n' disappears.
1141 Table table;
1142 table.AddRule("po", "ぽ", "");
1143 table.AddRule("n", "ん", "");
1144 table.AddRule("na", "な", "");
1145 table.AddRule("ya", "や", "");
1146 table.AddRule("nya", "にゃ", "");
1147 table.AddRule("byo", "びょ", "");
1148
1149 composition_->SetTable(&table);
1150
1151 composition_->SetInputMode(Transliterators::HIRAGANA);
1152
1153 size_t pos = 0;
1154 pos = composition_->InsertAt(pos, "n");
1155 pos = composition_->InsertAt(pos, "y");
1156 {
1157 string output;
1158 composition_->GetStringWithTrimMode(FIX, &output);
1159 EXPECT_EQ("んy", output);
1160
1161 composition_->GetStringWithTrimMode(ASIS, &output);
1162 EXPECT_EQ("ny", output);
1163
1164 composition_->GetStringWithTrimMode(TRIM, &output);
1165 EXPECT_EQ("", output);
1166 }
1167 }
1168
TEST_F(CompositionTest,Issue2990253)1169 TEST_F(CompositionTest, Issue2990253) {
1170 // SplitChunk fails.
1171 // Ambiguous text is left in rhs CharChunk invalidly.
1172 Table table;
1173 table.AddRule("po", "ぽ", "");
1174 table.AddRule("n", "ん", "");
1175 table.AddRule("na", "な", "");
1176 table.AddRule("ya", "や", "");
1177 table.AddRule("nya", "にゃ", "");
1178 table.AddRule("byo", "びょ", "");
1179
1180 composition_->SetTable(&table);
1181
1182 composition_->SetInputMode(Transliterators::HIRAGANA);
1183
1184 size_t pos = 0;
1185 pos = composition_->InsertAt(pos, "n");
1186 pos = composition_->InsertAt(pos, "y");
1187 pos = 1;
1188 pos = composition_->InsertAt(pos, "b");
1189 {
1190 string output;
1191 composition_->GetStringWithTrimMode(FIX, &output);
1192 EXPECT_EQ("んby", output);
1193
1194 composition_->GetStringWithTrimMode(ASIS, &output);
1195 EXPECT_EQ("んby", output);
1196
1197 composition_->GetStringWithTrimMode(TRIM, &output);
1198 // doubtful result. should be "ん"
1199 // May relate to http://b/2990358
1200 EXPECT_EQ("んb", output);
1201 }
1202 }
1203
TEST_F(CompositionTest,InsertionIntoPreeditMakesInvalidText_1)1204 TEST_F(CompositionTest, InsertionIntoPreeditMakesInvalidText_1) {
1205 // http://b/2990358
1206 // Test for mainly Composition::InsertAt()
1207
1208 Table table;
1209 table.AddRule("po", "ぽ", "");
1210 table.AddRule("n", "ん", "");
1211 table.AddRule("na", "な", "");
1212 table.AddRule("ya", "や", "");
1213 table.AddRule("nya", "にゃ", "");
1214 table.AddRule("byo", "びょ", "");
1215
1216 composition_->SetTable(&table);
1217
1218 composition_->SetInputMode(Transliterators::HIRAGANA);
1219
1220 size_t pos = 0;
1221 pos = composition_->InsertAt(pos, "n");
1222 pos = composition_->InsertAt(pos, "y");
1223 pos = 1;
1224 pos = composition_->InsertAt(pos, "b");
1225 pos = 3;
1226 pos = composition_->InsertAt(pos, "o");
1227 {
1228 string output;
1229 composition_->GetStringWithTrimMode(FIX, &output);
1230 EXPECT_EQ("んびょ", output);
1231
1232 composition_->GetStringWithTrimMode(ASIS, &output);
1233 EXPECT_EQ("んびょ", output);
1234
1235 composition_->GetStringWithTrimMode(TRIM, &output);
1236 EXPECT_EQ("んびょ", output);
1237 }
1238 }
1239
TEST_F(CompositionTest,InsertionIntoPreeditMakesInvalidText_2)1240 TEST_F(CompositionTest, InsertionIntoPreeditMakesInvalidText_2) {
1241 // http://b/2990358
1242 // Test for mainly Composition::InsertKeyAndPreeditAt()
1243
1244 Table table;
1245 table.AddRule("す゛", "ず", "");
1246 table.AddRule("く゛", "ぐ", "");
1247 composition_->SetTable(&table);
1248
1249 size_t pos = 0;
1250 pos = composition_->InsertKeyAndPreeditAt(pos, "m", "も");
1251 pos = composition_->InsertKeyAndPreeditAt(pos, "r", "す");
1252 pos = composition_->InsertKeyAndPreeditAt(pos, "h", "く");
1253 pos = composition_->InsertKeyAndPreeditAt(2, "@", "゛");
1254 pos = composition_->InsertKeyAndPreeditAt(5, "!", "!");
1255
1256 string comp_str;
1257 composition_->GetString(&comp_str);
1258 EXPECT_EQ("もずく!", comp_str);
1259
1260 string comp_ascii_str;
1261 composition_->GetStringWithTransliterator(
1262 Transliterators::RAW_STRING, &comp_ascii_str);
1263 EXPECT_EQ("mr@h!", comp_ascii_str);
1264 }
1265
TEST_F(CompositionTest,CombinePendingChunks)1266 TEST_F(CompositionTest, CombinePendingChunks) {
1267 Table table;
1268 table.AddRule("po", "ぽ", "");
1269 table.AddRule("n", "ん", "");
1270 table.AddRule("na", "な", "");
1271 table.AddRule("ya", "や", "");
1272 table.AddRule("nya", "にゃ", "");
1273 table.AddRule("byo", "びょ", "");
1274
1275 {
1276 // empty chunks + "n" -> empty chunks + "n"
1277 Composition comp(&table);
1278 comp.SetInputMode(Transliterators::HIRAGANA);
1279
1280 size_t pos = 0;
1281
1282 CharChunkList::iterator it;
1283 comp.MaybeSplitChunkAt(pos, &it);
1284 CharChunkList::iterator chunk_it = comp.GetInsertionChunk(&it);
1285
1286 CompositionInput input;
1287 SetInput("n", "", false, &input);
1288 comp.CombinePendingChunks(chunk_it, input);
1289 EXPECT_EQ("", (*chunk_it)->pending());
1290 EXPECT_EQ("", (*chunk_it)->conversion());
1291 EXPECT_EQ("", (*chunk_it)->raw());
1292 EXPECT_EQ("", (*chunk_it)->ambiguous());
1293 }
1294 {
1295 // [x] + "n" -> [x] + "n"
1296 // No combination performed.
1297 Composition comp(&table);
1298 comp.SetInputMode(Transliterators::HIRAGANA);
1299
1300 size_t pos = 0;
1301 pos = comp.InsertAt(pos, "x");
1302
1303 CharChunkList::iterator it;
1304 comp.MaybeSplitChunkAt(pos, &it);
1305 CharChunkList::iterator chunk_it = comp.GetInsertionChunk(&it);
1306 CompositionInput input;
1307 SetInput("n", "", false, &input);
1308
1309 comp.CombinePendingChunks(chunk_it, input);
1310 EXPECT_EQ("", (*chunk_it)->pending());
1311 EXPECT_EQ("", (*chunk_it)->conversion());
1312 EXPECT_EQ("", (*chunk_it)->raw());
1313 EXPECT_EQ("", (*chunk_it)->ambiguous());
1314 }
1315 {
1316 // Append "a" to [n][y] -> [ny] + "a"
1317 // Combination performed.
1318 Composition comp(&table);
1319 comp.SetInputMode(Transliterators::HIRAGANA);
1320
1321 size_t pos = 0;
1322 pos = comp.InsertAt(pos, "y");
1323 pos = comp.InsertAt(0, "n");
1324
1325 CharChunkList::iterator it;
1326 comp.MaybeSplitChunkAt(2, &it);
1327 CharChunkList::iterator chunk_it = comp.GetInsertionChunk(&it);
1328 CompositionInput input;
1329 SetInput("a", "", false, &input);
1330
1331 comp.CombinePendingChunks(chunk_it, input);
1332 EXPECT_EQ("ny", (*chunk_it)->pending());
1333 EXPECT_EQ("", (*chunk_it)->conversion());
1334 EXPECT_EQ("ny", (*chunk_it)->raw());
1335 EXPECT_EQ("んy", (*chunk_it)->ambiguous());
1336 }
1337 {
1338 // Append "a" to [x][n][y] -> [x][ny] + "a"
1339 // Combination performed.
1340 Composition comp(&table);
1341 comp.SetTable(&table);
1342 comp.SetInputMode(Transliterators::HIRAGANA);
1343
1344 size_t pos = 0;
1345 pos = comp.InsertAt(pos, "x");
1346 pos = comp.InsertAt(pos, "y");
1347 pos = comp.InsertAt(1, "n");
1348
1349 CharChunkList::iterator it;
1350 comp.MaybeSplitChunkAt(3, &it);
1351 CharChunkList::iterator chunk_it = comp.GetInsertionChunk(&it);
1352 CompositionInput input;
1353 SetInput("a", "", false, &input);
1354
1355 comp.CombinePendingChunks(chunk_it, input);
1356 EXPECT_EQ("ny", (*chunk_it)->pending());
1357 EXPECT_EQ("", (*chunk_it)->conversion());
1358 EXPECT_EQ("ny", (*chunk_it)->raw());
1359 EXPECT_EQ("んy", (*chunk_it)->ambiguous());
1360 }
1361
1362 {
1363 // Append "a" of conversion value to [x][n][y] -> [x][ny] + "a"
1364 // Combination performed. If composition input contains a
1365 // conversion, the conversion is used rather than a raw value.
1366 Composition comp(&table);
1367 comp.SetInputMode(Transliterators::HIRAGANA);
1368
1369 size_t pos = 0;
1370 pos = comp.InsertAt(pos, "x");
1371 pos = comp.InsertAt(pos, "y");
1372 pos = comp.InsertAt(1, "n");
1373
1374 CharChunkList::iterator it;
1375 comp.MaybeSplitChunkAt(3, &it);
1376 CharChunkList::iterator chunk_it = comp.GetInsertionChunk(&it);
1377 CompositionInput input;
1378 SetInput("x", "a", false, &input);
1379
1380 comp.CombinePendingChunks(chunk_it, input);
1381 EXPECT_EQ("ny", (*chunk_it)->pending());
1382 EXPECT_EQ("", (*chunk_it)->conversion());
1383 EXPECT_EQ("ny", (*chunk_it)->raw());
1384 }
1385 }
1386
TEST_F(CompositionTest,NewChunkBehaviors)1387 TEST_F(CompositionTest, NewChunkBehaviors) {
1388 Table table;
1389 table.AddRule("n", "", "ん");
1390 table.AddRule("na", "", "な");
1391 table.AddRuleWithAttributes("a", "", "あ", NEW_CHUNK);
1392 table.AddRule("ん*", "", "猫");
1393 table.AddRule("*", "", "");
1394 table.AddRule("ん#", "", "猫");
1395
1396 composition_->SetTable(&table);
1397
1398 CompositionInput input;
1399 {
1400 size_t pos = 0;
1401 composition_->Erase();
1402 SetInput("n", "", true, &input);
1403 pos = composition_->InsertInput(pos, input);
1404 SetInput("a", "", true, &input);
1405 pos = composition_->InsertInput(pos, input);
1406 EXPECT_EQ("nあ", GetString(*composition_));
1407 }
1408 {
1409 size_t pos = 0;
1410 composition_->Erase();
1411 SetInput("n", "", false, &input);
1412 pos = composition_->InsertInput(pos, input);
1413 SetInput("a", "", false, &input);
1414 pos = composition_->InsertInput(pos, input);
1415 EXPECT_EQ("な", GetString(*composition_));
1416 }
1417
1418 {
1419 size_t pos = 0;
1420 composition_->Erase();
1421 SetInput("n", "", true, &input);
1422 pos = composition_->InsertInput(pos, input);
1423 SetInput("*", "", true, &input);
1424 pos = composition_->InsertInput(pos, input);
1425 EXPECT_EQ("猫", GetString(*composition_));
1426 }
1427 {
1428 size_t pos = 0;
1429 composition_->Erase();
1430 SetInput("n", "", false, &input);
1431 pos = composition_->InsertInput(pos, input);
1432 SetInput("*", "", false, &input);
1433 pos = composition_->InsertInput(pos, input);
1434 EXPECT_EQ("猫", GetString(*composition_));
1435 }
1436
1437 {
1438 size_t pos = 0;
1439 composition_->Erase();
1440 SetInput("n", "", true, &input);
1441 pos = composition_->InsertInput(pos, input);
1442 SetInput("#", "", true, &input);
1443 pos = composition_->InsertInput(pos, input);
1444 EXPECT_EQ("n#", GetString(*composition_));
1445 }
1446 {
1447 size_t pos = 0;
1448 composition_->Erase();
1449 SetInput("n", "", false, &input);
1450 pos = composition_->InsertInput(pos, input);
1451 SetInput("#", "", false, &input);
1452 pos = composition_->InsertInput(pos, input);
1453 EXPECT_EQ("猫", GetString(*composition_));
1454 }
1455
1456 {
1457 size_t pos = 0;
1458 composition_->Erase();
1459 SetInput("n", "", true, &input);
1460 pos = composition_->InsertInput(pos, input);
1461 SetInput("1", "", true, &input);
1462 pos = composition_->InsertInput(pos, input);
1463 EXPECT_EQ("n1", GetString(*composition_));
1464 }
1465 {
1466 size_t pos = 0;
1467 composition_->Erase();
1468 SetInput("n", "", false, &input);
1469 pos = composition_->InsertInput(pos, input);
1470 SetInput("1", "", false, &input);
1471 pos = composition_->InsertInput(pos, input);
1472 EXPECT_EQ("ん""1", GetString(*composition_));
1473 }
1474 }
1475
TEST_F(CompositionTest,TwelveKeysInput)1476 TEST_F(CompositionTest, TwelveKeysInput) {
1477 // Simulates flick + toggle input mode.
1478
1479 Table table;
1480 table.AddRule("n", "", "ん");
1481 table.AddRule("na", "", "な");
1482 table.AddRule("a", "", "あ");
1483 table.AddRule("*", "", "");
1484 table.AddRule("ほ*", "", "ぼ");
1485 table.AddRuleWithAttributes("7", "", "は", NEW_CHUNK);
1486 table.AddRule("は""7", "", "ひ");
1487 table.AddRule("ひ*", "", "び");
1488
1489 composition_->SetTable(&table);
1490
1491 CompositionInput input;
1492 size_t pos = 0;
1493
1494 SetInput("n", "", true, &input);
1495 pos = composition_->InsertInput(pos, input);
1496
1497 SetInput("a", "", false, &input);
1498 pos = composition_->InsertInput(pos, input);
1499
1500 SetInput("7", "ほ", false, &input);
1501 pos = composition_->InsertInput(pos, input);
1502
1503 SetInput("*", "", true, &input);
1504 pos = composition_->InsertInput(pos, input);
1505
1506 SetInput("7", "ひ", false, &input);
1507 pos = composition_->InsertInput(pos, input);
1508
1509 SetInput("7", "", true, &input);
1510 pos = composition_->InsertInput(pos, input);
1511
1512 SetInput("7", "は", false, &input);
1513 pos = composition_->InsertInput(pos, input);
1514
1515 SetInput("7", "", true, &input);
1516 pos = composition_->InsertInput(pos, input);
1517
1518 SetInput("7", "は", false, &input);
1519 pos = composition_->InsertInput(pos, input);
1520
1521 EXPECT_EQ("なぼひはははは", GetString(*composition_));
1522 }
1523
TEST_F(CompositionTest,DifferentRulesForSamePendingWithSpecialKeys)1524 TEST_F(CompositionTest, DifferentRulesForSamePendingWithSpecialKeys) {
1525 table_->AddRule("4", "", "[ta]");
1526 table_->AddRule("[to]4", "", "[x]{#1}");
1527 table_->AddRule("[x]{#1}4", "", "[ta]");
1528
1529 table_->AddRule("*", "", "");
1530 table_->AddRule("[tu]*", "", "[x]{#2}");
1531 table_->AddRule("[x]{#2}*", "", "[tu]");
1532
1533 {
1534 composition_->Erase();
1535 size_t pos = 0;
1536 pos = composition_->InsertAt(pos, "[to]4");
1537 EXPECT_EQ(3, pos);
1538 EXPECT_EQ("[x]", GetString(*composition_));
1539 EXPECT_EQ("[to]4", GetRawString(*composition_));
1540
1541 pos = composition_->InsertAt(pos, "4");
1542 EXPECT_EQ(4, pos);
1543 EXPECT_EQ("[ta]", GetString(*composition_));
1544 EXPECT_EQ("[to]44", GetRawString(*composition_));
1545 }
1546
1547 {
1548 composition_->Erase();
1549 size_t pos = 0;
1550 pos = composition_->InsertAt(pos, "[to]4");
1551 EXPECT_EQ(3, pos);
1552 EXPECT_EQ("[x]", GetString(*composition_));
1553 EXPECT_EQ("[to]4", GetRawString(*composition_));
1554
1555 pos = composition_->InsertAt(pos, "*");
1556 EXPECT_EQ(3, pos);
1557 EXPECT_EQ("[x]", GetString(*composition_));
1558 EXPECT_EQ("[to]4*", GetRawString(*composition_));
1559 }
1560
1561 {
1562 composition_->Erase();
1563 size_t pos = 0;
1564 pos = composition_->InsertAt(pos, "[tu]*");
1565 EXPECT_EQ(3, pos);
1566 EXPECT_EQ("[x]", GetString(*composition_));
1567 EXPECT_EQ("[tu]*", GetRawString(*composition_));
1568
1569 pos = composition_->InsertAt(pos, "*");
1570 EXPECT_EQ(4, pos);
1571 EXPECT_EQ("[tu]", GetString(*composition_));
1572 EXPECT_EQ("[tu]**", GetRawString(*composition_));
1573 }
1574
1575 {
1576 composition_->Erase();
1577 size_t pos = 0;
1578 pos = composition_->InsertAt(pos, "[tu]*");
1579 EXPECT_EQ(3, pos);
1580 EXPECT_EQ("[x]", GetString(*composition_));
1581 EXPECT_EQ("[tu]*", GetRawString(*composition_));
1582
1583 pos = composition_->InsertAt(pos, "*");
1584 EXPECT_EQ(4, pos);
1585 EXPECT_EQ("[tu]", GetString(*composition_));
1586 EXPECT_EQ("[tu]**", GetRawString(*composition_));
1587 }
1588 }
1589
TEST_F(CompositionTest,LoopingRuleFor12KeysWithSpecialKeys)1590 TEST_F(CompositionTest, LoopingRuleFor12KeysWithSpecialKeys) {
1591 table_->AddRule("2", "", "a");
1592 table_->AddRule("a2", "", "b");
1593 table_->AddRule("b2", "", "c");
1594 table_->AddRule("c2", "", "{2}2");
1595 table_->AddRule("{2}22", "", "a");
1596
1597 size_t pos = 0;
1598 pos = composition_->InsertAt(pos, "2");
1599 EXPECT_EQ("a", GetString(*composition_));
1600 EXPECT_EQ("2", GetRawString(*composition_));
1601
1602 pos = composition_->InsertAt(pos, "2");
1603 EXPECT_EQ("b", GetString(*composition_));
1604 EXPECT_EQ("22", GetRawString(*composition_));
1605
1606 pos = composition_->InsertAt(pos, "2");
1607 EXPECT_EQ("c", GetString(*composition_));
1608 EXPECT_EQ("222", GetRawString(*composition_));
1609
1610 pos = composition_->InsertAt(pos, "2");
1611 EXPECT_EQ("2", GetString(*composition_));
1612 EXPECT_EQ("2222", GetRawString(*composition_));
1613
1614 pos = composition_->InsertAt(pos, "2");
1615 EXPECT_EQ("a", GetString(*composition_));
1616 EXPECT_EQ("22222", GetRawString(*composition_));
1617
1618 pos = composition_->InsertAt(pos, "2");
1619 EXPECT_EQ("b", GetString(*composition_));
1620 EXPECT_EQ("222222", GetRawString(*composition_));
1621
1622 pos = composition_->InsertAt(pos, "2");
1623 EXPECT_EQ("c", GetString(*composition_));
1624 EXPECT_EQ("2222222", GetRawString(*composition_));
1625 }
1626
TEST_F(CompositionTest,AlphanumericOfSSH)1627 TEST_F(CompositionTest, AlphanumericOfSSH) {
1628 // This is a unittest against http://b/3199626
1629 // 'ssh' (っsh) + F10 should be 'ssh'.
1630 Table table;
1631 table.AddRule("ss", "っ", "s");
1632 table.AddRule("shi", "し", "");
1633
1634 composition_->SetTable(&table);
1635 composition_->SetInputMode(Transliterators::HIRAGANA);
1636 size_t pos = 0;
1637 pos = composition_->InsertAt(pos, "s");
1638 pos = composition_->InsertAt(pos, "s");
1639 pos = composition_->InsertAt(pos, "h");
1640 EXPECT_EQ(3, pos);
1641
1642 string output;
1643 composition_->GetStringWithTrimMode(FIX, &output);
1644 EXPECT_EQ("っsh", output);
1645 }
1646
TEST_F(CompositionTest,GrassHack)1647 TEST_F(CompositionTest, GrassHack) {
1648 Table table;
1649 table.AddRule("ww", "っ", "w");
1650 table.AddRule("we", "うぇ", "");
1651 table.AddRule("www", "w", "ww");
1652
1653 composition_->SetTable(&table);
1654 composition_->SetInputMode(Transliterators::HIRAGANA);
1655 size_t pos = 0;
1656 pos = composition_->InsertAt(pos, "w");
1657 pos = composition_->InsertAt(pos, "w");
1658 pos = composition_->InsertAt(pos, "w");
1659
1660 EXPECT_EQ("www", GetString(*composition_));
1661
1662 pos = composition_->InsertAt(pos, "e");
1663 EXPECT_EQ("wっうぇ", GetString(*composition_));
1664 }
1665
TEST_F(CompositionTest,RulesForFirstKeyEvents)1666 TEST_F(CompositionTest, RulesForFirstKeyEvents) {
1667 table_->AddRuleWithAttributes("a", "[A]", "", NEW_CHUNK);
1668 table_->AddRule("n", "[N]", "");
1669 table_->AddRule("nn", "[N]", "");
1670 table_->AddRule("na", "[NA]", "");
1671 table_->AddRuleWithAttributes("ni", "[NI]", "", NEW_CHUNK);
1672
1673 CompositionInput input;
1674
1675 {
1676 SetInput("a", "", true, &input);
1677 composition_->InsertInput(0, input);
1678 EXPECT_EQ("[A]", GetString(*composition_));
1679 }
1680
1681 {
1682 composition_->Erase();
1683 CompositionInput input;
1684 SetInput("anaa", "", true, &input);
1685 composition_->InsertInput(0, input);
1686 EXPECT_EQ("[A][NA][A]", GetString(*composition_));
1687 }
1688
1689 {
1690 composition_->Erase();
1691
1692 CompositionInput input;
1693 SetInput("an", "", true, &input);
1694 const size_t position_an = composition_->InsertInput(0, input);
1695
1696 SetInput("a", "", true, &input);
1697 composition_->InsertInput(position_an, input);
1698 EXPECT_EQ("[A]n[A]", GetString(*composition_));
1699
1700 // This input should be treated as a part of "NA".
1701 SetInput("a", "", false, &input);
1702 composition_->InsertInput(position_an, input);
1703 EXPECT_EQ("[A][NA][A]", GetString(*composition_));
1704
1705 string raw_t13n;
1706 composition_->GetStringWithTransliterator(
1707 Transliterators::RAW_STRING, &raw_t13n);
1708 EXPECT_EQ("anaa", raw_t13n);
1709 }
1710
1711 {
1712 composition_->Erase();
1713
1714 CompositionInput input;
1715 SetInput("an", "", true, &input);
1716 const size_t position_an = composition_->InsertInput(0, input);
1717
1718 SetInput("ni", "", true, &input);
1719 composition_->InsertInput(position_an, input);
1720 EXPECT_EQ("[A]n[NI]", GetString(*composition_));
1721
1722 string raw_t13n;
1723 composition_->GetStringWithTransliterator(
1724 Transliterators::RAW_STRING, &raw_t13n);
1725 EXPECT_EQ("anni", raw_t13n);
1726 }
1727 }
1728
TEST_F(CompositionTest,NoTransliteration)1729 TEST_F(CompositionTest, NoTransliteration) {
1730 table_->AddRuleWithAttributes("0", "0", "", NO_TABLE_ATTRIBUTE);
1731 table_->AddRuleWithAttributes("1", "1", "", NO_TRANSLITERATION);
1732 table_->AddRuleWithAttributes("kk", "っ", "k", NO_TABLE_ATTRIBUTE);
1733 table_->AddRuleWithAttributes("ka", "か", "", NO_TRANSLITERATION);
1734 table_->AddRuleWithAttributes("ss", "っ", "s", NO_TRANSLITERATION);
1735 table_->AddRuleWithAttributes("sa", "さ", "", NO_TABLE_ATTRIBUTE);
1736 table_->AddRuleWithAttributes("tt", "っ", "t", NO_TRANSLITERATION);
1737 table_->AddRuleWithAttributes("ta", "た", "", NO_TRANSLITERATION);
1738
1739 composition_->SetInputMode(Transliterators::FULL_KATAKANA);
1740
1741 InsertCharacters("01kkassatta", 0, composition_.get());
1742 EXPECT_EQ("01ッカっさった", GetString(*composition_));
1743 }
1744
TEST_F(CompositionTest,NoTransliteration_Issue3497962)1745 TEST_F(CompositionTest, NoTransliteration_Issue3497962) {
1746 table_->AddRuleWithAttributes("2", "", "a", NEW_CHUNK | NO_TRANSLITERATION);
1747 table_->AddRuleWithAttributes("a2", "", "b", NO_TABLE_ATTRIBUTE);
1748 table_->AddRuleWithAttributes("b2", "", "c", NO_TABLE_ATTRIBUTE);
1749 table_->AddRuleWithAttributes("c2", "", "{2}2", NO_TABLE_ATTRIBUTE);
1750 table_->AddRuleWithAttributes("{2}22", "", "a", NO_TABLE_ATTRIBUTE);
1751
1752 composition_->SetInputMode(Transliterators::HIRAGANA);
1753
1754 int pos = 0;
1755 pos = composition_->InsertAt(pos, "2");
1756 EXPECT_EQ("a", GetString(*composition_));
1757
1758 pos = composition_->InsertAt(pos, "2");
1759 EXPECT_EQ("b", GetString(*composition_));
1760 }
1761
TEST_F(CompositionTest,SetTransliteratorOnEmpty)1762 TEST_F(CompositionTest, SetTransliteratorOnEmpty) {
1763 composition_->SetTransliterator(0, 0, Transliterators::HIRAGANA);
1764 CompositionInput input;
1765 SetInput("a", "", true, &input);
1766 composition_->InsertInput(0, input);
1767 EXPECT_EQ(1, composition_->GetLength());
1768 }
1769
TEST_F(CompositionTest,Clone)1770 TEST_F(CompositionTest, Clone) {
1771 Composition src(table_.get());
1772 src.SetInputMode(Transliterators::FULL_KATAKANA);
1773
1774 AppendChunk("も", "", "mo", &src);
1775 AppendChunk("ず", "", "z", &src);
1776 AppendChunk("く", "", "c", &src);
1777
1778 EXPECT_EQ(table_.get(), src.table());
1779 EXPECT_EQ(Transliterators::FULL_KATAKANA, src.input_t12r());
1780 EXPECT_EQ(3, src.chunks().size());
1781
1782 std::unique_ptr<Composition> dest(src.CloneImpl());
1783 ASSERT_NE(nullptr, dest.get());
1784 EXPECT_EQ(src.table(), dest->table());
1785 EXPECT_EQ(src.input_t12r(), dest->input_t12r());
1786 ASSERT_EQ(src.chunks().size(), dest->chunks().size());
1787
1788 CharChunkList::const_iterator src_it = src.chunks().begin();
1789 CharChunkList::const_iterator dest_it = dest->chunks().begin();
1790 for (; src_it != src.chunks().end(); ++src_it, ++dest_it) {
1791 EXPECT_EQ((*src_it)->raw(), (*dest_it)->raw());
1792 }
1793 }
1794
1795 } // namespace composer
1796 } // namespace mozc
1797