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/single_kanji_rewriter.h"
31
32 #include <cstddef>
33 #include <memory>
34 #include <string>
35
36 #include "base/system_util.h"
37 #include "base/util.h"
38 #include "config/config_handler.h"
39 #include "converter/segments.h"
40 #include "data_manager/testing/mock_data_manager.h"
41 #include "dictionary/pos_matcher.h"
42 #include "protocol/commands.pb.h"
43 #include "request/conversion_request.h"
44 #include "testing/base/public/googletest.h"
45 #include "testing/base/public/gunit.h"
46
47 namespace mozc {
48
49 using dictionary::POSMatcher;
50
51 class SingleKanjiRewriterTest : public ::testing::Test {
52 protected:
SingleKanjiRewriterTest()53 SingleKanjiRewriterTest() {
54 data_manager_.reset(new testing::MockDataManager);
55 pos_matcher_.Set(data_manager_->GetPOSMatcherData());
56 }
57
58 ~SingleKanjiRewriterTest() override = default;
59
SetUp()60 void SetUp() override {
61 SystemUtil::SetUserProfileDirectory(FLAGS_test_tmpdir);
62 }
63
CreateSingleKanjiRewriter() const64 SingleKanjiRewriter *CreateSingleKanjiRewriter() const {
65 return new SingleKanjiRewriter(*data_manager_);
66 }
67
pos_matcher()68 const POSMatcher &pos_matcher() {
69 return pos_matcher_;
70 }
71
72 const ConversionRequest default_request_;
73
74 protected:
75 std::unique_ptr<testing::MockDataManager> data_manager_;
76 POSMatcher pos_matcher_;
77 };
78
TEST_F(SingleKanjiRewriterTest,CapabilityTest)79 TEST_F(SingleKanjiRewriterTest, CapabilityTest) {
80 std::unique_ptr<SingleKanjiRewriter> rewriter(CreateSingleKanjiRewriter());
81
82 ConversionRequest convreq;
83 commands::Request request;
84 convreq.set_request(&request);
85
86 request.set_mixed_conversion(false);
87 EXPECT_EQ(RewriterInterface::CONVERSION, rewriter->capability(convreq));
88 }
89
TEST_F(SingleKanjiRewriterTest,SetKeyTest)90 TEST_F(SingleKanjiRewriterTest, SetKeyTest) {
91 std::unique_ptr<SingleKanjiRewriter> rewriter(CreateSingleKanjiRewriter());
92
93 Segments segments;
94 Segment *segment = segments.add_segment();
95 const string kKey = "あ";
96 segment->set_key(kKey);
97 Segment::Candidate *candidate = segment->add_candidate();
98 // First candidate may be inserted by other rewriters.
99 candidate->Init();
100 candidate->key = "strange key";
101 candidate->content_key = "starnge key";
102 candidate->value = "starnge value";
103 candidate->content_value = "strange value";
104
105 EXPECT_EQ(1, segment->candidates_size());
106 rewriter->Rewrite(default_request_, &segments);
107 EXPECT_GT(segment->candidates_size(), 1);
108 for (size_t i = 1; i < segment->candidates_size(); ++i) {
109 EXPECT_EQ(kKey, segment->candidate(i).key);
110 }
111 }
112
TEST_F(SingleKanjiRewriterTest,MobileEnvironmentTest)113 TEST_F(SingleKanjiRewriterTest, MobileEnvironmentTest) {
114 ConversionRequest convreq;
115 commands::Request request;
116 convreq.set_request(&request);
117 std::unique_ptr<SingleKanjiRewriter> rewriter(CreateSingleKanjiRewriter());
118
119 {
120 request.set_mixed_conversion(true);
121 EXPECT_EQ(RewriterInterface::ALL, rewriter->capability(convreq));
122 }
123
124 {
125 request.set_mixed_conversion(false);
126 EXPECT_EQ(RewriterInterface::CONVERSION, rewriter->capability(convreq));
127 }
128 }
129
TEST_F(SingleKanjiRewriterTest,NounPrefixTest)130 TEST_F(SingleKanjiRewriterTest, NounPrefixTest) {
131 SingleKanjiRewriter rewriter(*data_manager_);
132 Segments segments;
133 Segment *segment1 = segments.add_segment();
134
135 segment1->set_key("み");
136 Segment::Candidate *candidate1 = segment1->add_candidate();
137
138 candidate1->Init();
139 candidate1->key = "み";
140 candidate1->content_key = "見";
141 candidate1->value = "見";
142 candidate1->content_value = "見";
143
144 EXPECT_EQ(1, segment1->candidates_size());
145 rewriter.Rewrite(default_request_, &segments);
146
147 EXPECT_EQ("未", segment1->candidate(0).value);
148
149 Segment *segment2 = segments.add_segment();
150
151 segment2->set_key("こうたい");
152 Segment::Candidate *candidate2 = segment2->add_candidate();
153
154 candidate2->Init();
155 candidate2->key = "こうたい";
156 candidate2->content_key = "後退";
157 candidate2->value = "後退";
158
159 candidate2->lid = pos_matcher().GetContentWordWithConjugationId();
160 candidate2->rid = pos_matcher().GetContentWordWithConjugationId();
161
162 candidate1 = segment1->mutable_candidate(0);
163 candidate1->Init();
164 candidate1->key = "み";
165 candidate1->content_key = "見";
166 candidate1->value = "見";
167 candidate1->content_value = "見";
168
169 rewriter.Rewrite(default_request_, &segments);
170 EXPECT_EQ("見", segment1->candidate(0).value);
171
172 // Only applied when right word's POS is noun.
173 candidate2->lid = pos_matcher().GetContentNounId();
174 candidate2->rid = pos_matcher().GetContentNounId();
175
176 rewriter.Rewrite(default_request_, &segments);
177 EXPECT_EQ("未", segment1->candidate(0).value);
178
179 EXPECT_EQ(pos_matcher().GetNounPrefixId(), segment1->candidate(0).lid);
180 EXPECT_EQ(pos_matcher().GetNounPrefixId(), segment1->candidate(0).rid);
181 }
182
TEST_F(SingleKanjiRewriterTest,InsertionPositionTest)183 TEST_F(SingleKanjiRewriterTest, InsertionPositionTest) {
184 SingleKanjiRewriter rewriter(*data_manager_);
185 Segments segments;
186 Segment *segment = segments.add_segment();
187
188 segment->set_key("あ");
189 for (int i = 0; i < 10; ++i) {
190 Segment::Candidate *candidate = segment->add_candidate();
191 candidate->Init();
192 candidate->key = segment->key();
193 candidate->content_key = segment->key();
194 candidate->value = Util::StringPrintf("cand%d", i);
195 candidate->content_value = candidate->value;
196 }
197
198 EXPECT_EQ(10, segment->candidates_size());
199 EXPECT_TRUE(rewriter.Rewrite(default_request_, &segments));
200 EXPECT_LT(10, segment->candidates_size()); // Some candidates were inserted.
201
202 for (int i = 0; i < 10; ++i) {
203 // First 10 candidates have not changed.
204 const Segment::Candidate &candidate = segment->candidate(i);
205 EXPECT_EQ(Util::StringPrintf("cand%d", i), candidate.value);
206 }
207 }
208
TEST_F(SingleKanjiRewriterTest,AddDescriptionTest)209 TEST_F(SingleKanjiRewriterTest, AddDescriptionTest) {
210 SingleKanjiRewriter rewriter(*data_manager_);
211 Segments segments;
212 Segment *segment = segments.add_segment();
213
214 segment->set_key("あ");
215 {
216 Segment::Candidate *candidate = segment->add_candidate();
217 candidate->Init();
218 candidate->key = segment->key();
219 candidate->content_key = segment->key();
220 candidate->value = "亞"; // variant of "亜".
221 candidate->content_value = candidate->value;
222 }
223
224 EXPECT_EQ(1, segment->candidates_size());
225 EXPECT_TRUE(segment->candidate(0).description.empty());
226 EXPECT_TRUE(rewriter.Rewrite(default_request_, &segments));
227 EXPECT_LT(1, segment->candidates_size()); // Some candidates were inserted.
228 EXPECT_EQ("亜の旧字体", segment->candidate(0).description);
229 }
230
231 } // namespace mozc
232