// Copyright 2010-2016, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rewriter/emoji_rewriter.h"
#include <cstddef>
#include <memory>
#include <string>
#include <vector>
#include "base/logging.h"
#include "base/number_util.h"
#include "base/string_piece.h"
#include "base/serialized_string_array.h"
#include "base/util.h"
#include "config/config_handler.h"
#include "converter/segments.h"
#include "data_manager/testing/mock_data_manager.h"
#include "dictionary/pos_matcher.h"
#include "protocol/commands.pb.h"
#include "protocol/config.pb.h"
#include "request/conversion_request.h"
#include "rewriter/variants_rewriter.h"
#include "testing/base/public/gunit.h"
#include "testing/base/public/mozctest.h"
#include "usage_stats/usage_stats.h"
#include "usage_stats/usage_stats_testing_util.h"
namespace mozc {
namespace {
using mozc::commands::Request;
// "えもじ"
const char kEmoji[] = "\xE3\x81\x88\xE3\x82\x82\xE3\x81\x98";
// Makes |segments| to have only a segment with a key-value paired candidate.
void SetSegment(const string &key, const string &value, Segments *segments) {
segments->Clear();
Segment *seg = segments->push_back_segment();
seg->set_key(key);
Segment::Candidate *candidate = seg->add_candidate();
candidate->Init();
candidate->value = key;
candidate->content_key = key;
candidate->content_value = value;
}
// Counts the number of enumerated emoji candidates in the segments.
int CountEmojiCandidates(const Segments &segments) {
int emoji_size = 0;
for (size_t i = 0; i < segments.segments_size(); ++i) {
const Segment &segment = segments.segment(i);
for (size_t j = 0; j < segment.candidates_size(); ++j) {
if (EmojiRewriter::IsEmojiCandidate(segment.candidate(j))) {
++emoji_size;
}
}
}
return emoji_size;
}
// Checks if the first segment has a specific candidate.
bool HasExpectedCandidate(const Segments &segments,
const string &expect_value) {
CHECK_LE(1, segments.segments_size());
const Segment &segment = segments.segment(0);
for (size_t i = 0; i < segment.candidates_size(); ++i) {
const Segment::Candidate &candidate = segment.candidate(i);
if (candidate.value == expect_value) {
return true;
}
}
return false;
}
// Replaces an emoji candidate into the 0-th index, as the Mozc converter
// does with a commited candidate.
void ChooseEmojiCandidate(Segments *segments) {
CHECK_LE(1, segments->segments_size());
Segment *segment = segments->mutable_segment(0);
for (size_t i = 0; i < segment->candidates_size(); ++i) {
if (EmojiRewriter::IsEmojiCandidate(segment->candidate(i))) {
segment->move_candidate(i, 0);
break;
}
}
segment->set_segment_type(Segment::FIXED_VALUE);
}
struct EmojiData {
const char *key;
const char *unicode;
const uint32 android_pua;
const char *description_unicode;
const char *description_docomo;
const char *description_softbank;
const char *description_kddi;
};
// Elements must be sorted lexicographically by key (first string).
const EmojiData kTestEmojiList[] = {
// An actual emoji character
{"Emoji", "\xF0\x9F\x90\xAD", 0, "nezumi picture", "", "", ""},
// Meta candidates.
{"Inu", "DOG", 0, "inu", "", "", ""},
{"Neko", "CAT", 0, "neko", "", "", ""},
{"Nezumi", "MOUSE", 0, "nezumi", "", "", ""},
{"Nezumi", "RAT", 0, "nezumi", "", "", ""},
// Test data for carrier.
{"X", "COW", 0xFE001, "ushi", "", "", ""},
{"X", "TIGER", 0xFE002, "tora", "docomo", "", ""},
{"X", "RABIT", 0xFE003, "usagi", "", "softbank", ""},
{"X", "DRAGON", 0xFE004, "ryu", "", "", "kddi"},
// No unicode available.
{"X", "", 0xFE011, "", "docomo", "", ""},
{"X", "", 0xFE012, "", "", "softbank", ""},
{"X", "", 0xFE013, "", "", "", "kddi"},
// Multiple carriers available.
{"X", "", 0xFE021, "", "docomo", "softbank", ""},
{"X", "", 0xFE022, "", "docomo", "", "kddi"},
{"X", "", 0xFE023, "", "", "softbank", "kddi"},
{"X", "", 0xFE024, "", "docomo", "softbank", "kddi"},
};
// This data manager overrides GetEmojiRewriterData() to return the above test
// data for EmojiRewriter.
class TestDataManager : public testing::MockDataManager {
public:
TestDataManager() {
// Collect all the strings and temporarily assing 0 as index.
std::map<string, size_t> string_index;
for (const EmojiData &data : kTestEmojiList) {
string_index[data.key] = 0;
string_index[data.unicode] = 0;
string_index[data.description_unicode] = 0;
string_index[data.description_docomo] = 0;
string_index[data.description_softbank] = 0;
string_index[data.description_kddi] = 0;
}
// Set index.
std::vector<StringPiece> strings;
size_t index = 0;
for (auto &iter : string_index) {
strings.push_back(iter.first);
iter.second = index++;
}
// Create token array.
for (const EmojiData &data : kTestEmojiList) {
token_array_.push_back(string_index[data.key]);
token_array_.push_back(string_index[data.unicode]);
token_array_.push_back(data.android_pua);
token_array_.push_back(string_index[data.description_unicode]);
token_array_.push_back(string_index[data.description_docomo]);
token_array_.push_back(string_index[data.description_softbank]);
token_array_.push_back(string_index[data.description_kddi]);
}
// Create string array.
string_array_data_ =
SerializedStringArray::SerializeToBuffer(strings, &string_array_buf_);
}
void GetEmojiRewriterData(StringPiece *token_array_data,
StringPiece *string_array_data) const override {
token_array_data->set(reinterpret_cast<const char*>(token_array_.data()),
token_array_.size() * sizeof(uint32));
*string_array_data = string_array_data_;
}
private:
std::vector<uint32> token_array_;
StringPiece string_array_data_;
std::unique_ptr<uint32[]> string_array_buf_;
};
string ToAndroidPuaString(int pua) {
string str;
Util::UCS4ToUTF8(pua, &str);
return str;
}
class EmojiRewriterTest : public ::testing::Test {
protected:
EmojiRewriterTest() {
convreq_.set_request(&request_);
convreq_.set_config(&config_);
}
void SetUp() override {
// Enable emoji conversion
config::ConfigHandler::GetDefaultConfig(&config_);
config_.set_use_emoji_conversion(true);
mozc::usage_stats::UsageStats::ClearAllStatsForTest();
rewriter_.reset(new EmojiRewriter(test_data_manager_));
full_data_rewriter_.reset(new EmojiRewriter(mock_data_manager_));
}
void TearDown() override {
mozc::usage_stats::UsageStats::ClearAllStatsForTest();
}
ConversionRequest convreq_;
commands::Request request_;
config::Config config_;
std::unique_ptr<EmojiRewriter> rewriter_;
std::unique_ptr<EmojiRewriter> full_data_rewriter_;
private:
const testing::ScopedTmpUserProfileDirectory scoped_tmp_profile_dir_;
const testing::MockDataManager mock_data_manager_;
const TestDataManager test_data_manager_;
usage_stats::scoped_usage_stats_enabler usage_stats_enabler_;
};
TEST_F(EmojiRewriterTest, Capability) {
request_.set_emoji_rewriter_capability(Request::NOT_AVAILABLE);
EXPECT_EQ(RewriterInterface::NOT_AVAILABLE,
rewriter_->capability(convreq_));
request_.set_emoji_rewriter_capability(Request::CONVERSION);
EXPECT_EQ(RewriterInterface::CONVERSION,
rewriter_->capability(convreq_));
request_.set_emoji_rewriter_capability(Request::PREDICTION);
EXPECT_EQ(RewriterInterface::PREDICTION,
rewriter_->capability(convreq_));
request_.set_emoji_rewriter_capability(Request::SUGGESTION);
EXPECT_EQ(RewriterInterface::SUGGESTION,
rewriter_->capability(convreq_));
request_.set_emoji_rewriter_capability(Request::ALL);
EXPECT_EQ(RewriterInterface::ALL,
rewriter_->capability(convreq_));
}
TEST_F(EmojiRewriterTest, ConvertedSegmentsHasEmoji) {
// This test runs an EmojiRewriter with a few strings, and checks
// - no conversion occur with unknown string,
// - expected characters are added in a conversion with a string,
// - all emojis are added with a specific string.
Segments segments;
SetSegment("neko", "test", &segments);
EXPECT_FALSE(rewriter_->Rewrite(convreq_, &segments));
EXPECT_EQ(0, CountEmojiCandidates(segments));
SetSegment("Neko", "test", &segments);
EXPECT_TRUE(rewriter_->Rewrite(convreq_, &segments));
EXPECT_EQ(1, CountEmojiCandidates(segments));
EXPECT_TRUE(HasExpectedCandidate(segments, "CAT"));
SetSegment("Nezumi", "test", &segments);
EXPECT_TRUE(rewriter_->Rewrite(convreq_, &segments));
EXPECT_EQ(2, CountEmojiCandidates(segments));
EXPECT_TRUE(HasExpectedCandidate(segments, "MOUSE"));
EXPECT_TRUE(HasExpectedCandidate(segments, "RAT"));
SetSegment(kEmoji, "test", &segments);
EXPECT_TRUE(rewriter_->Rewrite(convreq_, &segments));
EXPECT_EQ(9, CountEmojiCandidates(segments));
}
TEST_F(EmojiRewriterTest, CarrierEmojiSelectionEmpty) {
Segments segments;
SetSegment("X", "test", &segments);
request_.set_available_emoji_carrier(0); // Disable emoji rewriting.
ASSERT_FALSE(rewriter_->Rewrite(convreq_, &segments));
ASSERT_EQ(0, CountEmojiCandidates(segments));
}
TEST_F(EmojiRewriterTest, CarrierEmojiSelectionUnicode) {
Segments segments;
SetSegment("X", "test", &segments);
request_.set_available_emoji_carrier(Request::UNICODE_EMOJI);
ASSERT_TRUE(rewriter_->Rewrite(convreq_, &segments));
ASSERT_EQ(4, CountEmojiCandidates(segments));
EXPECT_TRUE(HasExpectedCandidate(segments, "COW"));
EXPECT_TRUE(HasExpectedCandidate(segments, "TIGER"));
EXPECT_TRUE(HasExpectedCandidate(segments, "RABIT"));
EXPECT_TRUE(HasExpectedCandidate(segments, "DRAGON"));
}
TEST_F(EmojiRewriterTest, CarrierEmojiSelectionDocomo) {
Segments segments;
SetSegment("X", "test", &segments);
request_.set_available_emoji_carrier(Request::DOCOMO_EMOJI);
ASSERT_TRUE(rewriter_->Rewrite(convreq_, &segments));
ASSERT_EQ(5, CountEmojiCandidates(segments));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE002)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE011)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE021)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE022)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE024)));
}
TEST_F(EmojiRewriterTest, CarrierEmojiSelectionSoftbank) {
Segments segments;
SetSegment("X", "test", &segments);
request_.set_available_emoji_carrier(Request::SOFTBANK_EMOJI);
ASSERT_TRUE(rewriter_->Rewrite(convreq_, &segments));
ASSERT_EQ(5, CountEmojiCandidates(segments));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE003)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE012)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE021)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE023)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE024)));
}
TEST_F(EmojiRewriterTest, CarrierEmojiSelectionKddi) {
Segments segments;
SetSegment("X", "test", &segments);
request_.set_available_emoji_carrier(Request::KDDI_EMOJI);
ASSERT_TRUE(rewriter_->Rewrite(convreq_, &segments));
ASSERT_EQ(5, CountEmojiCandidates(segments));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE004)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE013)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE022)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE023)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE024)));
}
// The combination of unicode and android carrier dependent emoji.
TEST_F(EmojiRewriterTest, CarrierEmojiSelectionDocomoUnicode) {
Segments segments;
SetSegment("X", "test", &segments);
request_.set_available_emoji_carrier(
Request::DOCOMO_EMOJI | Request::UNICODE_EMOJI);
ASSERT_TRUE(rewriter_->Rewrite(convreq_, &segments));
ASSERT_EQ(9, CountEmojiCandidates(segments));
EXPECT_TRUE(HasExpectedCandidate(segments, "COW"));
EXPECT_TRUE(HasExpectedCandidate(segments, "TIGER"));
EXPECT_TRUE(HasExpectedCandidate(segments, "RABIT"));
EXPECT_TRUE(HasExpectedCandidate(segments, "DRAGON"));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE002)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE011)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE021)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE022)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE024)));
}
TEST_F(EmojiRewriterTest, CarrierEmojiSelectionSoftbankUnicode) {
Segments segments;
SetSegment("X", "test", &segments);
request_.set_available_emoji_carrier(
Request::SOFTBANK_EMOJI | Request::UNICODE_EMOJI);
ASSERT_TRUE(rewriter_->Rewrite(convreq_, &segments));
ASSERT_EQ(9, CountEmojiCandidates(segments));
EXPECT_TRUE(HasExpectedCandidate(segments, "COW"));
EXPECT_TRUE(HasExpectedCandidate(segments, "TIGER"));
EXPECT_TRUE(HasExpectedCandidate(segments, "RABIT"));
EXPECT_TRUE(HasExpectedCandidate(segments, "DRAGON"));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE003)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE012)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE021)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE023)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE024)));
}
TEST_F(EmojiRewriterTest, CarrierEmojiSelectionKddiUnicode) {
Segments segments;
SetSegment("X", "test", &segments);
request_.set_available_emoji_carrier(
Request::KDDI_EMOJI | Request::UNICODE_EMOJI);
ASSERT_TRUE(rewriter_->Rewrite(convreq_, &segments));
ASSERT_EQ(9, CountEmojiCandidates(segments));
EXPECT_TRUE(HasExpectedCandidate(segments, "COW"));
EXPECT_TRUE(HasExpectedCandidate(segments, "TIGER"));
EXPECT_TRUE(HasExpectedCandidate(segments, "RABIT"));
EXPECT_TRUE(HasExpectedCandidate(segments, "DRAGON"));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE004)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE013)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE022)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE023)));
EXPECT_TRUE(HasExpectedCandidate(segments, ToAndroidPuaString(0xFE024)));
}
TEST_F(EmojiRewriterTest, NoConversionWithDisabledSettings) {
// This test checks no emoji conversion occur if emoji convrsion is disabled
// in settings. Same segments are tested with ConvertedSegmentsHasEmoji test.
// Disable emoji conversion in settings
config_.set_use_emoji_conversion(false);
Segments segments;
SetSegment("test", "test", &segments);
EXPECT_FALSE(rewriter_->Rewrite(convreq_, &segments));
EXPECT_EQ(0, CountEmojiCandidates(segments));
SetSegment("Neko", "test", &segments);
EXPECT_FALSE(rewriter_->Rewrite(convreq_, &segments));
EXPECT_EQ(0, CountEmojiCandidates(segments));
EXPECT_FALSE(HasExpectedCandidate(segments, "CAT"));
SetSegment("Nezumi", "test", &segments);
EXPECT_FALSE(rewriter_->Rewrite(convreq_, &segments));
EXPECT_EQ(0, CountEmojiCandidates(segments));
EXPECT_FALSE(HasExpectedCandidate(segments, "MOUSE"));
EXPECT_FALSE(HasExpectedCandidate(segments, "RAT"));
SetSegment(kEmoji, "test", &segments);
EXPECT_FALSE(rewriter_->Rewrite(convreq_, &segments));
EXPECT_EQ(0, CountEmojiCandidates(segments));
}
TEST_F(EmojiRewriterTest, CheckDescription) {
const testing::MockDataManager data_manager;
Segments segments;
VariantsRewriter variants_rewriter(
dictionary::POSMatcher(data_manager.GetPOSMatcherData()));
SetSegment("Emoji", "test", &segments);
EXPECT_TRUE(rewriter_->Rewrite(convreq_, &segments));
EXPECT_TRUE(variants_rewriter.Rewrite(convreq_, &segments));
ASSERT_LT(0, CountEmojiCandidates(segments));
const Segment &segment = segments.segment(0);
for (int i = 0; i < segment.candidates_size(); ++i) {
const Segment::Candidate &candidate = segment.candidate(i);
const string &description = candidate.description;
// Skip non emoji candidates.
if (!EmojiRewriter::IsEmojiCandidate(candidate)) {
continue;
}
// "<機種依存文字>"
EXPECT_NE(string::npos, description.find("<"
"\xE6\xA9\x9F\xE7\xA8\xAE\xE4\xBE\x9D\xE5\xAD\x98"
"\xE6\x96\x87\xE5\xAD\x97" ">"))
<< "for \"" << candidate.value << "\" : \"" << description << "\"";
// "[全]"
EXPECT_EQ(string::npos, description.find("[" "\xE5\x85\xA8" "]"))
<< "for \"" << candidate.value << "\" : \"" << description << "\"";
}
}
TEST_F(EmojiRewriterTest, CheckInsertPosition) {
// This test checks if emoji candidates are inserted into the expected
// position.
// |kExpectPosition| has the same number with |kDefaultInsertPos| defined in
// emoji_rewriter.cc.
const int kExpectPosition = 6;
Segments segments;
{
Segment *segment = segments.push_back_segment();
segment->set_key("Neko");
for (int i = 0; i < kExpectPosition * 2; ++i) {
string value = "candidate" + NumberUtil::SimpleItoa(i);
Segment::Candidate *candidate = segment->add_candidate();
candidate->Init();
candidate->value = value;
candidate->content_key = "Neko";
candidate->content_value = value;
}
}
EXPECT_TRUE(rewriter_->Rewrite(convreq_, &segments));
ASSERT_EQ(1, segments.segments_size());
const Segment& segment = segments.segment(0);
ASSERT_LE(kExpectPosition, segment.candidates_size());
for (int i = 0; i < kExpectPosition; ++i) {
EXPECT_FALSE(EmojiRewriter::IsEmojiCandidate(segment.candidate(i)));
}
const Segment::Candidate &candidate = segment.candidate(kExpectPosition);
EXPECT_TRUE(EmojiRewriter::IsEmojiCandidate(candidate));
EXPECT_EQ("CAT", candidate.value);
}
TEST_F(EmojiRewriterTest, CheckUsageStats) {
// This test checks the data stored in usage stats for EmojiRewriter.
const char kStatsKey[] = "CommitEmoji";
Segments segments;
// No use, no registered keys
EXPECT_STATS_NOT_EXIST(kStatsKey);
// Converting non-emoji candidates does not matter.
SetSegment("test", "test", &segments);
EXPECT_FALSE(rewriter_->Rewrite(convreq_, &segments));
rewriter_->Finish(convreq_, &segments);
EXPECT_STATS_NOT_EXIST(kStatsKey);
// Converting an emoji candidate.
SetSegment("Nezumi", "test", &segments);
EXPECT_TRUE(rewriter_->Rewrite(convreq_, &segments));
ChooseEmojiCandidate(&segments);
rewriter_->Finish(convreq_, &segments);
EXPECT_COUNT_STATS(kStatsKey, 1);
SetSegment(kEmoji, "test", &segments);
EXPECT_TRUE(rewriter_->Rewrite(convreq_, &segments));
ChooseEmojiCandidate(&segments);
rewriter_->Finish(convreq_, &segments);
EXPECT_COUNT_STATS(kStatsKey, 2);
// Converting non-emoji keeps the previous usage stats.
SetSegment("test", "test", &segments);
EXPECT_FALSE(rewriter_->Rewrite(convreq_, &segments));
rewriter_->Finish(convreq_, &segments);
EXPECT_COUNT_STATS(kStatsKey, 2);
}
TEST_F(EmojiRewriterTest, QueryNormalization) {
{
Segments segments;
// "Neko"
SetSegment("\xEF\xBC\xAE\xEF\xBD\x85\xEF\xBD\x8B\xEF\xBD\x8F", "Neko",
&segments);
EXPECT_TRUE(rewriter_->Rewrite(convreq_, &segments));
}
{
Segments segments;
SetSegment("Neko", "Neko", &segments);
EXPECT_TRUE(rewriter_->Rewrite(convreq_, &segments));
}
}
TEST_F(EmojiRewriterTest, FullDataTest) {
// U+1F646 (FACE WITH OK GESTURE)
{
Segments segments;
// "OK"
SetSegment("\xEF\xBC\xAF\xEF\xBC\xAB", "OK", &segments);
EXPECT_TRUE(full_data_rewriter_->Rewrite(convreq_, &segments));
}
{
Segments segments;
SetSegment("OK", "OK", &segments);
EXPECT_TRUE(full_data_rewriter_->Rewrite(convreq_, &segments));
}
// U+2795 (HEAVY PLUS SIGN)
{
Segments segments;
// "+"
SetSegment("\xEF\xBC\x8B", "+", &segments);
EXPECT_TRUE(full_data_rewriter_->Rewrite(convreq_, &segments));
}
{
Segments segments;
SetSegment("+", "+", &segments);
EXPECT_TRUE(full_data_rewriter_->Rewrite(convreq_, &segments));
}
// U+1F522 (INPUT SYMBOL FOR NUMBERS)
{
Segments segments;
// "1234"
SetSegment("\xEF\xBC\x91\xEF\xBC\x92\xEF\xBC\x93\xEF\xBC\x94", "1234",
&segments);
EXPECT_TRUE(full_data_rewriter_->Rewrite(convreq_, &segments));
}
{
Segments segments;
SetSegment("1234", "1234", &segments);
EXPECT_TRUE(full_data_rewriter_->Rewrite(convreq_, &segments));
}
// U+1F552 (CLOCK FACE THREE OCLOCK)
{
Segments segments;
// "3じ"
SetSegment("\xEF\xBC\x93\xE3\x81\x98", "3ji", &segments);
EXPECT_TRUE(full_data_rewriter_->Rewrite(convreq_, &segments));
}
{
Segments segments;
SetSegment("\x33\xE3\x81\x98", "3ji", &segments);
EXPECT_TRUE(full_data_rewriter_->Rewrite(convreq_, &segments));
}
// U+31 U+20E3 (KEYCAP 1)
// Since emoji_rewriter does not support multi-codepoint characters,
// Rewrite function returns false though ideally it should be supported.
{
Segments segments;
// "1"
SetSegment("\xEF\xBC\x91", "1", &segments);
EXPECT_FALSE(full_data_rewriter_->Rewrite(convreq_, &segments));
}
{
Segments segments;
SetSegment("1", "1", &segments);
EXPECT_FALSE(full_data_rewriter_->Rewrite(convreq_, &segments));
}
}
} // namespace
} // namespace mozc