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