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 "rewriter/emoji_rewriter.h"
31
32 #include <cstddef>
33 #include <memory>
34 #include <string>
35 #include <vector>
36
37 #include "base/logging.h"
38 #include "base/string_piece.h"
39 #include "base/serialized_string_array.h"
40 #include "base/util.h"
41 #include "config/config_handler.h"
42 #include "converter/segments.h"
43 #include "data_manager/testing/mock_data_manager.h"
44 #include "dictionary/pos_matcher.h"
45 #include "protocol/commands.pb.h"
46 #include "protocol/config.pb.h"
47 #include "request/conversion_request.h"
48 #include "rewriter/variants_rewriter.h"
49 #include "testing/base/public/gunit.h"
50 #include "testing/base/public/mozctest.h"
51 #include "usage_stats/usage_stats.h"
52 #include "usage_stats/usage_stats_testing_util.h"
53
54 namespace mozc {
55 namespace {
56
57 using mozc::commands::Request;
58
59 const char kEmoji[] = "えもじ";
60
61 // Makes |segments| to have only a segment with a key-value paired candidate.
SetSegment(const string & key,const string & value,Segments * segments)62 void SetSegment(const string &key, const string &value, Segments *segments) {
63 segments->Clear();
64 Segment *seg = segments->push_back_segment();
65 seg->set_key(key);
66 Segment::Candidate *candidate = seg->add_candidate();
67 candidate->Init();
68 candidate->value = key;
69 candidate->content_key = key;
70 candidate->content_value = value;
71 }
72
73 // Counts the number of enumerated emoji candidates in the segments.
CountEmojiCandidates(const Segments & segments)74 int CountEmojiCandidates(const Segments &segments) {
75 int emoji_size = 0;
76 for (size_t i = 0; i < segments.segments_size(); ++i) {
77 const Segment &segment = segments.segment(i);
78 for (size_t j = 0; j < segment.candidates_size(); ++j) {
79 if (EmojiRewriter::IsEmojiCandidate(segment.candidate(j))) {
80 ++emoji_size;
81 }
82 }
83 }
84 return emoji_size;
85 }
86
87 // Checks if the first segment has a specific candidate.
HasExpectedCandidate(const Segments & segments,const string & expect_value)88 bool HasExpectedCandidate(const Segments &segments,
89 const string &expect_value) {
90 CHECK_LE(1, segments.segments_size());
91 const Segment &segment = segments.segment(0);
92 for (size_t i = 0; i < segment.candidates_size(); ++i) {
93 const Segment::Candidate &candidate = segment.candidate(i);
94 if (candidate.value == expect_value) {
95 return true;
96 }
97 }
98 return false;
99 }
100
101 // Replaces an emoji candidate into the 0-th index, as the Mozc converter
102 // does with a committed candidate.
ChooseEmojiCandidate(Segments * segments)103 void ChooseEmojiCandidate(Segments *segments) {
104 CHECK_LE(1, segments->segments_size());
105 Segment *segment = segments->mutable_segment(0);
106 for (size_t i = 0; i < segment->candidates_size(); ++i) {
107 if (EmojiRewriter::IsEmojiCandidate(segment->candidate(i))) {
108 segment->move_candidate(i, 0);
109 break;
110 }
111 }
112 segment->set_segment_type(Segment::FIXED_VALUE);
113 }
114
115 struct EmojiData {
116 const char *key;
117 const char *unicode;
118 const uint32 android_pua;
119 const char *description_unicode;
120 const char *description_docomo;
121 const char *description_softbank;
122 const char *description_kddi;
123 };
124
125 // Elements must be sorted lexicographically by key (first string).
126 const EmojiData kTestEmojiList[] = {
127 // An actual emoji character
128 {"Emoji", "", 0, "nezumi picture", "", "", ""},
129
130 // Meta candidates.
131 {"Inu", "DOG", 0, "inu", "", "", ""},
132 {"Neko", "CAT", 0, "neko", "", "", ""},
133 {"Nezumi", "MOUSE", 0, "nezumi", "", "", ""},
134 {"Nezumi", "RAT", 0, "nezumi", "", "", ""},
135
136 // Test data for carrier.
137 {"X", "COW", 0xFE001, "ushi", "", "", ""},
138 {"X", "TIGER", 0xFE002, "tora", "docomo", "", ""},
139 {"X", "RABIT", 0xFE003, "usagi", "", "softbank", ""},
140 {"X", "DRAGON", 0xFE004, "ryu", "", "", "kddi"},
141
142 // No unicode available.
143 {"X", "", 0xFE011, "", "docomo", "", ""},
144 {"X", "", 0xFE012, "", "", "softbank", ""},
145 {"X", "", 0xFE013, "", "", "", "kddi"},
146
147 // Multiple carriers available.
148 {"X", "", 0xFE021, "", "docomo", "softbank", ""},
149 {"X", "", 0xFE022, "", "docomo", "", "kddi"},
150 {"X", "", 0xFE023, "", "", "softbank", "kddi"},
151 {"X", "", 0xFE024, "", "docomo", "softbank", "kddi"},
152 };
153
154 // This data manager overrides GetEmojiRewriterData() to return the above test
155 // data for EmojiRewriter.
156 class TestDataManager : public testing::MockDataManager {
157 public:
TestDataManager()158 TestDataManager() {
159 // Collect all the strings and temporarily assing 0 as index.
160 std::map<string, size_t> string_index;
161 for (const EmojiData &data : kTestEmojiList) {
162 string_index[data.key] = 0;
163 string_index[data.unicode] = 0;
164 string_index[data.description_unicode] = 0;
165 string_index[data.description_docomo] = 0;
166 string_index[data.description_softbank] = 0;
167 string_index[data.description_kddi] = 0;
168 }
169
170 // Set index.
171 std::vector<StringPiece> strings;
172 size_t index = 0;
173 for (auto &iter : string_index) {
174 strings.push_back(iter.first);
175 iter.second = index++;
176 }
177
178 // Create token array.
179 for (const EmojiData &data : kTestEmojiList) {
180 token_array_.push_back(string_index[data.key]);
181 token_array_.push_back(string_index[data.unicode]);
182 token_array_.push_back(data.android_pua);
183 token_array_.push_back(string_index[data.description_unicode]);
184 token_array_.push_back(string_index[data.description_docomo]);
185 token_array_.push_back(string_index[data.description_softbank]);
186 token_array_.push_back(string_index[data.description_kddi]);
187 }
188
189 // Create string array.
190 string_array_data_ =
191 SerializedStringArray::SerializeToBuffer(strings, &string_array_buf_);
192 }
193
GetEmojiRewriterData(StringPiece * token_array_data,StringPiece * string_array_data) const194 void GetEmojiRewriterData(StringPiece *token_array_data,
195 StringPiece *string_array_data) const override {
196 *token_array_data =
197 StringPiece(reinterpret_cast<const char *>(token_array_.data()),
198 token_array_.size() * sizeof(uint32));
199 *string_array_data = string_array_data_;
200 }
201
202 private:
203 std::vector<uint32> token_array_;
204 StringPiece string_array_data_;
205 std::unique_ptr<uint32[]> string_array_buf_;
206 };
207
ToAndroidPuaString(int pua)208 string ToAndroidPuaString(int pua) {
209 string str;
210 Util::UCS4ToUTF8(pua, &str);
211 return str;
212 }
213
214 class EmojiRewriterTest : public ::testing::Test {
215 protected:
EmojiRewriterTest()216 EmojiRewriterTest() {
217 convreq_.set_request(&request_);
218 convreq_.set_config(&config_);
219 }
220
SetUp()221 void SetUp() override {
222 // Enable emoji conversion
223 config::ConfigHandler::GetDefaultConfig(&config_);
224 config_.set_use_emoji_conversion(true);
225
226 mozc::usage_stats::UsageStats::ClearAllStatsForTest();
227
228 rewriter_.reset(new EmojiRewriter(test_data_manager_));
229 full_data_rewriter_.reset(new EmojiRewriter(mock_data_manager_));
230 }
231
TearDown()232 void TearDown() override {
233 mozc::usage_stats::UsageStats::ClearAllStatsForTest();
234 }
235
236 ConversionRequest convreq_;
237 commands::Request request_;
238 config::Config config_;
239 std::unique_ptr<EmojiRewriter> rewriter_;
240 std::unique_ptr<EmojiRewriter> full_data_rewriter_;
241
242 private:
243 const testing::ScopedTmpUserProfileDirectory scoped_tmp_profile_dir_;
244 const testing::MockDataManager mock_data_manager_;
245 const TestDataManager test_data_manager_;
246 usage_stats::scoped_usage_stats_enabler usage_stats_enabler_;
247 };
248
TEST_F(EmojiRewriterTest,Capability)249 TEST_F(EmojiRewriterTest, Capability) {
250 request_.set_emoji_rewriter_capability(Request::NOT_AVAILABLE);
251 EXPECT_EQ(RewriterInterface::NOT_AVAILABLE,
252 rewriter_->capability(convreq_));
253
254 request_.set_emoji_rewriter_capability(Request::CONVERSION);
255 EXPECT_EQ(RewriterInterface::CONVERSION,
256 rewriter_->capability(convreq_));
257
258 request_.set_emoji_rewriter_capability(Request::PREDICTION);
259 EXPECT_EQ(RewriterInterface::PREDICTION,
260 rewriter_->capability(convreq_));
261
262 request_.set_emoji_rewriter_capability(Request::SUGGESTION);
263 EXPECT_EQ(RewriterInterface::SUGGESTION,
264 rewriter_->capability(convreq_));
265
266 request_.set_emoji_rewriter_capability(Request::ALL);
267 EXPECT_EQ(RewriterInterface::ALL,
268 rewriter_->capability(convreq_));
269 }
270
TEST_F(EmojiRewriterTest,ConvertedSegmentsHasEmoji)271 TEST_F(EmojiRewriterTest, ConvertedSegmentsHasEmoji) {
272 // This test runs an EmojiRewriter with a few strings, and checks
273 // - no conversion occur with unknown string,
274 // - expected characters are added in a conversion with a string,
275 // - all emojis are added with a specific string.
276
277 Segments segments;
278 SetSegment("neko", "test", &segments);
279 EXPECT_FALSE(rewriter_->Rewrite(convreq_, &segments));
280 EXPECT_EQ(0, CountEmojiCandidates(segments));
281
282 SetSegment("Neko", "test", &segments);
283 EXPECT_TRUE(rewriter_->Rewrite(convreq_, &segments));
284 EXPECT_EQ(1, CountEmojiCandidates(segments));
285 EXPECT_TRUE(HasExpectedCandidate(segments, "CAT"));
286
287 SetSegment("Nezumi", "test", &segments);
288 EXPECT_TRUE(rewriter_->Rewrite(convreq_, &segments));
289 EXPECT_EQ(2, CountEmojiCandidates(segments));
290 EXPECT_TRUE(HasExpectedCandidate(segments, "MOUSE"));
291 EXPECT_TRUE(HasExpectedCandidate(segments, "RAT"));
292
293 SetSegment(kEmoji, "test", &segments);
294 EXPECT_TRUE(rewriter_->Rewrite(convreq_, &segments));
295 EXPECT_EQ(9, CountEmojiCandidates(segments));
296 }
297
TEST_F(EmojiRewriterTest,CarrierEmojiSelectionEmpty)298 TEST_F(EmojiRewriterTest, CarrierEmojiSelectionEmpty) {
299 Segments segments;
300 SetSegment("X", "test", &segments);
301 request_.set_available_emoji_carrier(0); // Disable emoji rewriting.
302 ASSERT_FALSE(rewriter_->Rewrite(convreq_, &segments));
303 ASSERT_EQ(0, CountEmojiCandidates(segments));
304 }
305
TEST_F(EmojiRewriterTest,CarrierEmojiSelectionUnicode)306 TEST_F(EmojiRewriterTest, CarrierEmojiSelectionUnicode) {
307 Segments segments;
308 SetSegment("X", "test", &segments);
309 request_.set_available_emoji_carrier(Request::UNICODE_EMOJI);
310 ASSERT_TRUE(rewriter_->Rewrite(convreq_, &segments));
311 ASSERT_EQ(4, CountEmojiCandidates(segments));
312 EXPECT_TRUE(HasExpectedCandidate(segments, "COW"));
313 EXPECT_TRUE(HasExpectedCandidate(segments, "TIGER"));
314 EXPECT_TRUE(HasExpectedCandidate(segments, "RABIT"));
315 EXPECT_TRUE(HasExpectedCandidate(segments, "DRAGON"));
316 }
317
TEST_F(EmojiRewriterTest,CarrierEmojiSelectionDocomo)318 TEST_F(EmojiRewriterTest, CarrierEmojiSelectionDocomo) {
319 Segments segments;
320 SetSegment("X", "test", &segments);
321 request_.set_available_emoji_carrier(Request::DOCOMO_EMOJI);
322 ASSERT_TRUE(rewriter_->Rewrite(convreq_, &segments));
323 ASSERT_EQ(5, CountEmojiCandidates(segments));
324 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE002)));
325 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE011)));
326 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE021)));
327 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE022)));
328 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE024)));
329 }
330
TEST_F(EmojiRewriterTest,CarrierEmojiSelectionSoftbank)331 TEST_F(EmojiRewriterTest, CarrierEmojiSelectionSoftbank) {
332 Segments segments;
333 SetSegment("X", "test", &segments);
334 request_.set_available_emoji_carrier(Request::SOFTBANK_EMOJI);
335 ASSERT_TRUE(rewriter_->Rewrite(convreq_, &segments));
336 ASSERT_EQ(5, CountEmojiCandidates(segments));
337 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE003)));
338 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE012)));
339 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE021)));
340 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE023)));
341 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE024)));
342 }
343
TEST_F(EmojiRewriterTest,CarrierEmojiSelectionKddi)344 TEST_F(EmojiRewriterTest, CarrierEmojiSelectionKddi) {
345 Segments segments;
346 SetSegment("X", "test", &segments);
347 request_.set_available_emoji_carrier(Request::KDDI_EMOJI);
348 ASSERT_TRUE(rewriter_->Rewrite(convreq_, &segments));
349 ASSERT_EQ(5, CountEmojiCandidates(segments));
350 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE004)));
351 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE013)));
352 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE022)));
353 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE023)));
354 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE024)));
355 }
356
357 // The combination of unicode and android carrier dependent emoji.
TEST_F(EmojiRewriterTest,CarrierEmojiSelectionDocomoUnicode)358 TEST_F(EmojiRewriterTest, CarrierEmojiSelectionDocomoUnicode) {
359 Segments segments;
360 SetSegment("X", "test", &segments);
361 request_.set_available_emoji_carrier(
362 Request::DOCOMO_EMOJI | Request::UNICODE_EMOJI);
363 ASSERT_TRUE(rewriter_->Rewrite(convreq_, &segments));
364 ASSERT_EQ(9, CountEmojiCandidates(segments));
365 EXPECT_TRUE(HasExpectedCandidate(segments, "COW"));
366 EXPECT_TRUE(HasExpectedCandidate(segments, "TIGER"));
367 EXPECT_TRUE(HasExpectedCandidate(segments, "RABIT"));
368 EXPECT_TRUE(HasExpectedCandidate(segments, "DRAGON"));
369 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE002)));
370 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE011)));
371 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE021)));
372 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE022)));
373 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE024)));
374 }
375
TEST_F(EmojiRewriterTest,CarrierEmojiSelectionSoftbankUnicode)376 TEST_F(EmojiRewriterTest, CarrierEmojiSelectionSoftbankUnicode) {
377 Segments segments;
378 SetSegment("X", "test", &segments);
379 request_.set_available_emoji_carrier(
380 Request::SOFTBANK_EMOJI | Request::UNICODE_EMOJI);
381 ASSERT_TRUE(rewriter_->Rewrite(convreq_, &segments));
382 ASSERT_EQ(9, CountEmojiCandidates(segments));
383 EXPECT_TRUE(HasExpectedCandidate(segments, "COW"));
384 EXPECT_TRUE(HasExpectedCandidate(segments, "TIGER"));
385 EXPECT_TRUE(HasExpectedCandidate(segments, "RABIT"));
386 EXPECT_TRUE(HasExpectedCandidate(segments, "DRAGON"));
387 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE003)));
388 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE012)));
389 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE021)));
390 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE023)));
391 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE024)));
392 }
393
TEST_F(EmojiRewriterTest,CarrierEmojiSelectionKddiUnicode)394 TEST_F(EmojiRewriterTest, CarrierEmojiSelectionKddiUnicode) {
395 Segments segments;
396 SetSegment("X", "test", &segments);
397 request_.set_available_emoji_carrier(
398 Request::KDDI_EMOJI | Request::UNICODE_EMOJI);
399 ASSERT_TRUE(rewriter_->Rewrite(convreq_, &segments));
400 ASSERT_EQ(9, CountEmojiCandidates(segments));
401 EXPECT_TRUE(HasExpectedCandidate(segments, "COW"));
402 EXPECT_TRUE(HasExpectedCandidate(segments, "TIGER"));
403 EXPECT_TRUE(HasExpectedCandidate(segments, "RABIT"));
404 EXPECT_TRUE(HasExpectedCandidate(segments, "DRAGON"));
405 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE004)));
406 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE013)));
407 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE022)));
408 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE023)));
409 EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE024)));
410 }
411
TEST_F(EmojiRewriterTest,NoConversionWithDisabledSettings)412 TEST_F(EmojiRewriterTest, NoConversionWithDisabledSettings) {
413 // This test checks no emoji conversion occur if emoji convrsion is disabled
414 // in settings. Same segments are tested with ConvertedSegmentsHasEmoji test.
415
416 // Disable emoji conversion in settings
417 config_.set_use_emoji_conversion(false);
418
419 Segments segments;
420 SetSegment("test", "test", &segments);
421 EXPECT_FALSE(rewriter_->Rewrite(convreq_, &segments));
422 EXPECT_EQ(0, CountEmojiCandidates(segments));
423
424 SetSegment("Neko", "test", &segments);
425 EXPECT_FALSE(rewriter_->Rewrite(convreq_, &segments));
426 EXPECT_EQ(0, CountEmojiCandidates(segments));
427 EXPECT_FALSE(HasExpectedCandidate(segments, "CAT"));
428
429 SetSegment("Nezumi", "test", &segments);
430 EXPECT_FALSE(rewriter_->Rewrite(convreq_, &segments));
431 EXPECT_EQ(0, CountEmojiCandidates(segments));
432 EXPECT_FALSE(HasExpectedCandidate(segments, "MOUSE"));
433 EXPECT_FALSE(HasExpectedCandidate(segments, "RAT"));
434
435 SetSegment(kEmoji, "test", &segments);
436 EXPECT_FALSE(rewriter_->Rewrite(convreq_, &segments));
437 EXPECT_EQ(0, CountEmojiCandidates(segments));
438 }
439
TEST_F(EmojiRewriterTest,CheckDescription)440 TEST_F(EmojiRewriterTest, CheckDescription) {
441 const testing::MockDataManager data_manager;
442 Segments segments;
443 VariantsRewriter variants_rewriter(
444 dictionary::POSMatcher(data_manager.GetPOSMatcherData()));
445
446 SetSegment("Emoji", "test", &segments);
447 EXPECT_TRUE(rewriter_->Rewrite(convreq_, &segments));
448 EXPECT_TRUE(variants_rewriter.Rewrite(convreq_, &segments));
449 ASSERT_LT(0, CountEmojiCandidates(segments));
450 const Segment &segment = segments.segment(0);
451 for (int i = 0; i < segment.candidates_size(); ++i) {
452 const Segment::Candidate &candidate = segment.candidate(i);
453 const string &description = candidate.description;
454 // Skip non emoji candidates.
455 if (!EmojiRewriter::IsEmojiCandidate(candidate)) {
456 continue;
457 }
458 EXPECT_NE(string::npos, description.find("<機種依存文字>"))
459 << "for \"" << candidate.value << "\" : \"" << description << "\"";
460 EXPECT_EQ(string::npos, description.find("[全]"))
461 << "for \"" << candidate.value << "\" : \"" << description << "\"";
462 }
463 }
464
TEST_F(EmojiRewriterTest,CheckInsertPosition)465 TEST_F(EmojiRewriterTest, CheckInsertPosition) {
466 // This test checks if emoji candidates are inserted into the expected
467 // position.
468
469 // |kExpectPosition| has the same number with |kDefaultInsertPos| defined in
470 // emoji_rewriter.cc.
471 const int kExpectPosition = 6;
472
473 Segments segments;
474 {
475 Segment *segment = segments.push_back_segment();
476 segment->set_key("Neko");
477 for (int i = 0; i < kExpectPosition * 2; ++i) {
478 string value = "candidate" + std::to_string(i);
479 Segment::Candidate *candidate = segment->add_candidate();
480 candidate->Init();
481 candidate->value = value;
482 candidate->content_key = "Neko";
483 candidate->content_value = value;
484 }
485 }
486 EXPECT_TRUE(rewriter_->Rewrite(convreq_, &segments));
487
488 ASSERT_EQ(1, segments.segments_size());
489 const Segment& segment = segments.segment(0);
490 ASSERT_LE(kExpectPosition, segment.candidates_size());
491 for (int i = 0; i < kExpectPosition; ++i) {
492 EXPECT_FALSE(EmojiRewriter::IsEmojiCandidate(segment.candidate(i)));
493 }
494 const Segment::Candidate &candidate = segment.candidate(kExpectPosition);
495 EXPECT_TRUE(EmojiRewriter::IsEmojiCandidate(candidate));
496 EXPECT_EQ("CAT", candidate.value);
497 }
498
TEST_F(EmojiRewriterTest,CheckUsageStats)499 TEST_F(EmojiRewriterTest, CheckUsageStats) {
500 // This test checks the data stored in usage stats for EmojiRewriter.
501
502 const char kStatsKey[] = "CommitEmoji";
503 Segments segments;
504
505 // No use, no registered keys
506 EXPECT_STATS_NOT_EXIST(kStatsKey);
507
508 // Converting non-emoji candidates does not matter.
509 SetSegment("test", "test", &segments);
510 EXPECT_FALSE(rewriter_->Rewrite(convreq_, &segments));
511 rewriter_->Finish(convreq_, &segments);
512 EXPECT_STATS_NOT_EXIST(kStatsKey);
513
514 // Converting an emoji candidate.
515 SetSegment("Nezumi", "test", &segments);
516 EXPECT_TRUE(rewriter_->Rewrite(convreq_, &segments));
517 ChooseEmojiCandidate(&segments);
518 rewriter_->Finish(convreq_, &segments);
519 EXPECT_COUNT_STATS(kStatsKey, 1);
520 SetSegment(kEmoji, "test", &segments);
521 EXPECT_TRUE(rewriter_->Rewrite(convreq_, &segments));
522 ChooseEmojiCandidate(&segments);
523 rewriter_->Finish(convreq_, &segments);
524 EXPECT_COUNT_STATS(kStatsKey, 2);
525
526 // Converting non-emoji keeps the previous usage stats.
527 SetSegment("test", "test", &segments);
528 EXPECT_FALSE(rewriter_->Rewrite(convreq_, &segments));
529 rewriter_->Finish(convreq_, &segments);
530 EXPECT_COUNT_STATS(kStatsKey, 2);
531 }
532
TEST_F(EmojiRewriterTest,QueryNormalization)533 TEST_F(EmojiRewriterTest, QueryNormalization) {
534 {
535 Segments segments;
536 SetSegment("Neko", "Neko", &segments);
537 EXPECT_TRUE(rewriter_->Rewrite(convreq_, &segments));
538 }
539 {
540 Segments segments;
541 SetSegment("Neko", "Neko", &segments);
542 EXPECT_TRUE(rewriter_->Rewrite(convreq_, &segments));
543 }
544 }
545
TEST_F(EmojiRewriterTest,FullDataTest)546 TEST_F(EmojiRewriterTest, FullDataTest) {
547 // U+1F646 (FACE WITH OK GESTURE)
548 {
549 Segments segments;
550 SetSegment("OK", "OK", &segments);
551 EXPECT_TRUE(full_data_rewriter_->Rewrite(convreq_, &segments));
552 }
553 {
554 Segments segments;
555 SetSegment("OK", "OK", &segments);
556 EXPECT_TRUE(full_data_rewriter_->Rewrite(convreq_, &segments));
557 }
558 // U+2795 (HEAVY PLUS SIGN)
559 {
560 Segments segments;
561 SetSegment("+", "+", &segments);
562 EXPECT_TRUE(full_data_rewriter_->Rewrite(convreq_, &segments));
563 }
564 {
565 Segments segments;
566 SetSegment("+", "+", &segments);
567 EXPECT_TRUE(full_data_rewriter_->Rewrite(convreq_, &segments));
568 }
569 // U+1F522 (INPUT SYMBOL FOR NUMBERS)
570 {
571 Segments segments;
572 SetSegment("1234", "1234", &segments);
573 EXPECT_TRUE(full_data_rewriter_->Rewrite(convreq_, &segments));
574 }
575 {
576 Segments segments;
577 SetSegment("1234", "1234", &segments);
578 EXPECT_TRUE(full_data_rewriter_->Rewrite(convreq_, &segments));
579 }
580 // U+1F552 (CLOCK FACE THREE OCLOCK)
581 {
582 Segments segments;
583 SetSegment("3じ", "3ji", &segments);
584 EXPECT_TRUE(full_data_rewriter_->Rewrite(convreq_, &segments));
585 }
586 {
587 Segments segments;
588 SetSegment("3じ", "3ji", &segments);
589 EXPECT_TRUE(full_data_rewriter_->Rewrite(convreq_, &segments));
590 }
591 // U+31 U+20E3 (KEYCAP 1)
592 // Since emoji_rewriter does not support multi-codepoint characters,
593 // Rewrite function returns false though ideally it should be supported.
594 {
595 Segments segments;
596 SetSegment("1", "1", &segments);
597 EXPECT_FALSE(full_data_rewriter_->Rewrite(convreq_, &segments));
598 }
599 {
600 Segments segments;
601 SetSegment("1", "1", &segments);
602 EXPECT_FALSE(full_data_rewriter_->Rewrite(convreq_, &segments));
603 }
604 }
605
606 } // namespace
607 } // namespace mozc
608