More removals of GET_CONFIG.
This CL is a preparation of Singleton<Config> removal.
GET_CONFIG relies on process global Singleton<Config>, which has caused
many troubles. With this CL, many conversion-related methods will be
refactored to receive ConversionRequest to access settings.
Hopefully this can help to address or at least mitigate test flakiness
like #317.
BUG=#317
TEST=unittest
REF_BUG=19010851,19188911
REF_CL=87318105
Hiroyuki Komatsu authored 8 years ago
Yohei Yukawa committed 8 years ago
134 | 134 | } |
135 | 135 | KeyCorrectedNodeListBuilder builder(pos, key, key_corrector, |
136 | 136 | lattice->node_allocator()); |
137 | dictionary->LookupPrefix( | |
138 | StringPiece(str, length), | |
139 | request.IsKanaModifierInsensitiveConversion(), | |
140 | &builder); | |
137 | dictionary->LookupPrefix(StringPiece(str, length), request, &builder); | |
141 | 138 | if (builder.tail() != NULL) { |
142 | 139 | builder.tail()->bnext = NULL; |
143 | 140 | } |
775 | 772 | BaseNodeListBuilder builder( |
776 | 773 | lattice->node_allocator(), |
777 | 774 | lattice->node_allocator()->max_nodes_size()); |
778 | dictionary_->LookupReverse(StringPiece(begin, len), &builder); | |
775 | dictionary_->LookupReverse(StringPiece(begin, len), request, &builder); | |
779 | 776 | result_node = builder.result(); |
780 | 777 | } else { |
781 | 778 | if (is_prediction) { |
782 | 779 | NodeListBuilderWithCacheEnabled builder( |
783 | 780 | lattice->node_allocator(), |
784 | 781 | lattice->cache_info(begin_pos) + 1); |
785 | dictionary_->LookupPrefix( | |
786 | StringPiece(begin, len), | |
787 | request.IsKanaModifierInsensitiveConversion(), | |
788 | &builder); | |
782 | dictionary_->LookupPrefix(StringPiece(begin, len), request, &builder); | |
789 | 783 | result_node = builder.result(); |
790 | 784 | lattice->SetCacheInfo(begin_pos, len); |
791 | 785 | } else { |
793 | 787 | BaseNodeListBuilder builder( |
794 | 788 | lattice->node_allocator(), |
795 | 789 | lattice->node_allocator()->max_nodes_size()); |
796 | dictionary_->LookupPrefix( | |
797 | StringPiece(begin, len), | |
798 | request.IsKanaModifierInsensitiveConversion(), | |
799 | &builder); | |
790 | dictionary_->LookupPrefix(StringPiece(begin, len), request, &builder); | |
800 | 791 | result_node = builder.result(); |
801 | 792 | } |
802 | 793 | } |
1103 | 1094 | // Note that, the average number of lid/rid variation is less than 30 in |
1104 | 1095 | // most cases. So, in order to avoid too many allocations for internal |
1105 | 1096 | // nodes of std::map, we use vector of key-value pairs. |
1106 | typedef vector<pair<int, pair<int, Node*> > > BestMap; | |
1097 | typedef vector<pair<int, pair<int, Node*>>> BestMap; | |
1107 | 1098 | typedef OrderBy<FirstKey, Less> OrderByFirst; |
1108 | 1099 | BestMap lbest, rbest; |
1109 | 1100 | lbest.reserve(128); |
1266 | 1257 | lattice->node_allocator()->max_nodes_size(), |
1267 | 1258 | pos_matcher_); |
1268 | 1259 | suffix_dictionary_->LookupPredictive( |
1269 | StringPiece(key.data() + pos, key.size() - pos), | |
1270 | request.IsKanaModifierInsensitiveConversion(), &builder); | |
1260 | StringPiece(key.data() + pos, key.size() - pos), request, &builder); | |
1271 | 1261 | if (builder.result() != NULL) { |
1272 | 1262 | lattice->Insert(pos, builder.result()); |
1273 | 1263 | } |
1297 | 1287 | lattice->node_allocator()->max_nodes_size(), |
1298 | 1288 | pos_matcher_); |
1299 | 1289 | dictionary_->LookupPredictive( |
1300 | StringPiece(key.data() + pos, key.size() - pos), | |
1301 | request.IsKanaModifierInsensitiveConversion(), &builder); | |
1290 | StringPiece(key.data() + pos, key.size() - pos), request, &builder); | |
1302 | 1291 | if (builder.result() != NULL) { |
1303 | 1292 | lattice->Insert(pos, builder.result()); |
1304 | 1293 | } |
1583 | 1572 | std::unique_ptr<KeyCorrector> key_corrector; |
1584 | 1573 | if (is_conversion && !segments.resized()) { |
1585 | 1574 | KeyCorrector::InputMode mode = KeyCorrector::ROMAN; |
1586 | if (GET_CONFIG(preedit_method) != config::Config::ROMAN) { | |
1575 | if (request.config().preedit_method() != config::Config::ROMAN) { | |
1587 | 1576 | mode = KeyCorrector::KANA; |
1588 | 1577 | } |
1589 | 1578 | key_corrector.reset(new KeyCorrector(key, mode, history_key.size())); |
175 | 175 | |
176 | 176 | } // namespace |
177 | 177 | |
178 | class ImmutableConverterTest : public ::testing::Test { | |
179 | protected: | |
180 | virtual void SetUp() { | |
181 | SystemUtil::SetUserProfileDirectory(FLAGS_test_tmpdir); | |
182 | config::ConfigHandler::GetDefaultConfig(&default_config_); | |
183 | config::ConfigHandler::SetConfig(default_config_); | |
184 | } | |
185 | ||
186 | virtual void TearDown() { | |
187 | config::ConfigHandler::SetConfig(default_config_); | |
188 | } | |
189 | ||
190 | private: | |
191 | config::Config default_config_; | |
192 | }; | |
193 | ||
194 | TEST_F(ImmutableConverterTest, KeepKeyForPrediction) { | |
178 | TEST(ImmutableConverterTest, KeepKeyForPrediction) { | |
195 | 179 | std::unique_ptr<MockDataAndImmutableConverter> data_and_converter( |
196 | 180 | new MockDataAndImmutableConverter); |
197 | 181 | Segments segments; |
209 | 193 | EXPECT_EQ(kRequestKey, segments.segment(0).key()); |
210 | 194 | } |
211 | 195 | |
212 | TEST_F(ImmutableConverterTest, DummyCandidatesCost) { | |
196 | TEST(ImmutableConverterTest, DummyCandidatesCost) { | |
213 | 197 | std::unique_ptr<MockDataAndImmutableConverter> data_and_converter( |
214 | 198 | new MockDataAndImmutableConverter); |
215 | 199 | Segment segment; |
221 | 205 | EXPECT_LT(segment.candidate(0).wcost, segment.candidate(2).wcost); |
222 | 206 | } |
223 | 207 | |
224 | TEST_F(ImmutableConverterTest, DummyCandidatesInnerSegmentBoundary) { | |
208 | TEST(ImmutableConverterTest, DummyCandidatesInnerSegmentBoundary) { | |
225 | 209 | std::unique_ptr<MockDataAndImmutableConverter> data_and_converter( |
226 | 210 | new MockDataAndImmutableConverter); |
227 | 211 | Segment segment; |
251 | 235 | virtual bool HasValue(StringPiece value) const { return false; } |
252 | 236 | |
253 | 237 | virtual void LookupPredictive( |
254 | StringPiece key, bool use_kana_modifier_insensitive_looukp, | |
238 | StringPiece key, | |
239 | const ConversionRequest &convreq, | |
255 | 240 | Callback *callback) const { |
256 | 241 | if (key == target_query_) { |
257 | 242 | received_target_query_ = true; |
260 | 245 | |
261 | 246 | virtual void LookupPrefix( |
262 | 247 | StringPiece key, |
263 | bool use_kana_modifier_insensitive_looukp, | |
248 | const ConversionRequest &convreq, | |
264 | 249 | Callback *callback) const { |
265 | 250 | // No check |
266 | 251 | } |
267 | 252 | |
268 | virtual void LookupExact(StringPiece key, Callback *callback) const { | |
253 | virtual void LookupExact(StringPiece key, | |
254 | const ConversionRequest &convreq, | |
255 | Callback *callback) const { | |
269 | 256 | // No check |
270 | 257 | } |
271 | 258 | |
272 | virtual void LookupReverse(StringPiece str, Callback *callback) const { | |
259 | virtual void LookupReverse(StringPiece str, | |
260 | const ConversionRequest &convreq, | |
261 | Callback *callback) const { | |
273 | 262 | // No check |
274 | 263 | } |
275 | 264 | |
283 | 272 | }; |
284 | 273 | } // namespace |
285 | 274 | |
286 | TEST_F(ImmutableConverterTest, PredictiveNodesOnlyForConversionKey) { | |
275 | TEST(ImmutableConverterTest, PredictiveNodesOnlyForConversionKey) { | |
287 | 276 | Segments segments; |
288 | 277 | { |
289 | 278 | Segment *segment = segments.add_segment(); |
326 | 315 | EXPECT_FALSE(dictionary->received_target_query()); |
327 | 316 | } |
328 | 317 | |
329 | TEST_F(ImmutableConverterTest, AddPredictiveNodes) { | |
318 | TEST(ImmutableConverterTest, AddPredictiveNodes) { | |
330 | 319 | Segments segments; |
331 | 320 | { |
332 | 321 | Segment *segment = segments.add_segment(); |
355 | 344 | EXPECT_TRUE(dictionary->received_target_query()); |
356 | 345 | } |
357 | 346 | |
358 | TEST_F(ImmutableConverterTest, InnerSegmenBoundaryForPrediction) { | |
347 | TEST(ImmutableConverterTest, InnerSegmenBoundaryForPrediction) { | |
359 | 348 | std::unique_ptr<MockDataAndImmutableConverter> data_and_converter( |
360 | 349 | new MockDataAndImmutableConverter); |
361 | 350 | Segments segments; |
408 | 397 | EXPECT_EQ("\xe4\xb8\xad\xe3\x83\x8e", content_values[2]); |
409 | 398 | } |
410 | 399 | |
411 | TEST_F(ImmutableConverterTest, NoInnerSegmenBoundaryForConversion) { | |
400 | TEST(ImmutableConverterTest, NoInnerSegmenBoundaryForConversion) { | |
412 | 401 | std::unique_ptr<MockDataAndImmutableConverter> data_and_converter( |
413 | 402 | new MockDataAndImmutableConverter); |
414 | 403 | Segments segments; |
429 | 418 | } |
430 | 419 | } |
431 | 420 | |
432 | TEST_F(ImmutableConverterTest, NotConnectedTest) { | |
421 | TEST(ImmutableConverterTest, NotConnectedTest) { | |
433 | 422 | std::unique_ptr<MockDataAndImmutableConverter> data_and_converter( |
434 | 423 | new MockDataAndImmutableConverter); |
435 | 424 | ImmutableConverterImpl *converter = data_and_converter->GetConverter(); |
477 | 466 | EXPECT_TRUE(tested); |
478 | 467 | } |
479 | 468 | |
480 | TEST_F(ImmutableConverterTest, HistoryKeyLengthIsVeryLong) { | |
469 | TEST(ImmutableConverterTest, HistoryKeyLengthIsVeryLong) { | |
481 | 470 | // "あ..." (100 times) |
482 | 471 | const string kA100 = |
483 | 472 | "\xE3\x81\x82\xE3\x81\x82\xE3\x81\x82\xE3\x81\x82\xE3\x81\x82" |
562 | 551 | } |
563 | 552 | } // namespace |
564 | 553 | |
565 | TEST_F(ImmutableConverterTest, EnableAutoPartialSuggestion) { | |
554 | TEST(ImmutableConverterTest, EnableAutoPartialSuggestion) { | |
566 | 555 | const commands::Request request; |
567 | ConversionRequest conversion_request(NULL, &request); | |
556 | ConversionRequest conversion_request; | |
557 | conversion_request.set_request(&request); | |
568 | 558 | conversion_request.set_create_partial_candidates(true); |
569 | 559 | |
570 | 560 | EXPECT_TRUE(AutoPartialSuggestionTestHelper(conversion_request)); |
571 | 561 | } |
572 | 562 | |
573 | TEST_F(ImmutableConverterTest, DisableAutoPartialSuggestion) { | |
563 | TEST(ImmutableConverterTest, DisableAutoPartialSuggestion) { | |
574 | 564 | const commands::Request request; |
575 | ConversionRequest conversion_request(NULL, &request); | |
565 | ConversionRequest conversion_request; | |
566 | conversion_request.set_request(&request); | |
576 | 567 | conversion_request.set_create_partial_candidates(false); |
577 | 568 | |
578 | 569 | EXPECT_FALSE(AutoPartialSuggestionTestHelper(conversion_request)); |
579 | 570 | } |
580 | 571 | |
581 | TEST_F(ImmutableConverterTest, AutoPartialSuggestionDefault) { | |
572 | TEST(ImmutableConverterTest, AutoPartialSuggestionDefault) { | |
582 | 573 | const commands::Request request; |
583 | ConversionRequest conversion_request(NULL, &request); | |
574 | ConversionRequest conversion_request; | |
575 | conversion_request.set_request(&request); | |
584 | 576 | |
585 | 577 | EXPECT_FALSE(AutoPartialSuggestionTestHelper(conversion_request)); |
586 | 578 | } |
587 | 579 | |
588 | TEST_F(ImmutableConverterTest, AutoPartialSuggestionForSingleSegment) { | |
580 | TEST(ImmutableConverterTest, AutoPartialSuggestionForSingleSegment) { | |
589 | 581 | const commands::Request request; |
590 | ConversionRequest conversion_request(NULL, &request); | |
582 | ConversionRequest conversion_request; | |
583 | conversion_request.set_request(&request); | |
591 | 584 | conversion_request.set_create_partial_candidates(true); |
592 | 585 | |
593 | 586 | std::unique_ptr<MockDataAndImmutableConverter> data_and_converter( |
33 | 33 | #include "base/logging.h" |
34 | 34 | #include "base/string_piece.h" |
35 | 35 | #include "base/util.h" |
36 | #include "config/config_handler.h" | |
37 | 36 | #include "dictionary/dictionary_interface.h" |
38 | 37 | #include "dictionary/dictionary_token.h" |
39 | 38 | #include "dictionary/pos_matcher.h" |
146 | 145 | |
147 | 146 | void DictionaryImpl::LookupPredictive( |
148 | 147 | StringPiece key, |
149 | bool use_kana_modifier_insensitive_lookup, | |
150 | Callback *callback) const { | |
151 | CallbackWithFilter callback_with_filter( | |
152 | GET_CONFIG(use_spelling_correction), | |
153 | GET_CONFIG(use_zip_code_conversion), | |
154 | GET_CONFIG(use_t13n_conversion), | |
148 | const ConversionRequest &conversion_request, | |
149 | Callback *callback) const { | |
150 | CallbackWithFilter callback_with_filter( | |
151 | conversion_request.config().use_spelling_correction(), | |
152 | conversion_request.config().use_zip_code_conversion(), | |
153 | conversion_request.config().use_t13n_conversion(), | |
155 | 154 | pos_matcher_, |
156 | 155 | suppression_dictionary_, |
157 | 156 | callback); |
158 | 157 | for (size_t i = 0; i < dics_.size(); ++i) { |
159 | 158 | dics_[i]->LookupPredictive( |
160 | key, use_kana_modifier_insensitive_lookup, &callback_with_filter); | |
159 | key, | |
160 | conversion_request, | |
161 | &callback_with_filter); | |
161 | 162 | } |
162 | 163 | } |
163 | 164 | |
164 | 165 | void DictionaryImpl::LookupPrefix( |
165 | 166 | StringPiece key, |
166 | bool use_kana_modifier_insensitive_lookup, | |
167 | Callback *callback) const { | |
168 | CallbackWithFilter callback_with_filter( | |
169 | GET_CONFIG(use_spelling_correction), | |
170 | GET_CONFIG(use_zip_code_conversion), | |
171 | GET_CONFIG(use_t13n_conversion), | |
167 | const ConversionRequest &conversion_request, | |
168 | Callback *callback) const { | |
169 | CallbackWithFilter callback_with_filter( | |
170 | conversion_request.config().use_spelling_correction(), | |
171 | conversion_request.config().use_zip_code_conversion(), | |
172 | conversion_request.config().use_t13n_conversion(), | |
172 | 173 | pos_matcher_, |
173 | 174 | suppression_dictionary_, |
174 | 175 | callback); |
175 | 176 | for (size_t i = 0; i < dics_.size(); ++i) { |
176 | 177 | dics_[i]->LookupPrefix( |
177 | key, use_kana_modifier_insensitive_lookup, &callback_with_filter); | |
178 | } | |
179 | } | |
180 | ||
181 | void DictionaryImpl::LookupExact(StringPiece key, Callback *callback) const { | |
182 | CallbackWithFilter callback_with_filter( | |
183 | GET_CONFIG(use_spelling_correction), | |
184 | GET_CONFIG(use_zip_code_conversion), | |
185 | GET_CONFIG(use_t13n_conversion), | |
186 | pos_matcher_, | |
187 | suppression_dictionary_, | |
188 | callback); | |
189 | for (size_t i = 0; i < dics_.size(); ++i) { | |
190 | dics_[i]->LookupExact(key, &callback_with_filter); | |
191 | } | |
192 | } | |
193 | ||
194 | void DictionaryImpl::LookupReverse(StringPiece str, | |
195 | Callback *callback) const { | |
196 | CallbackWithFilter callback_with_filter( | |
197 | GET_CONFIG(use_spelling_correction), | |
198 | GET_CONFIG(use_zip_code_conversion), | |
199 | GET_CONFIG(use_t13n_conversion), | |
200 | pos_matcher_, | |
201 | suppression_dictionary_, | |
202 | callback); | |
203 | for (size_t i = 0; i < dics_.size(); ++i) { | |
204 | dics_[i]->LookupReverse(str, &callback_with_filter); | |
178 | key, | |
179 | conversion_request, | |
180 | &callback_with_filter); | |
181 | } | |
182 | } | |
183 | ||
184 | void DictionaryImpl::LookupExact( | |
185 | StringPiece key, | |
186 | const ConversionRequest &conversion_request, | |
187 | Callback *callback) const { | |
188 | CallbackWithFilter callback_with_filter( | |
189 | conversion_request.config().use_spelling_correction(), | |
190 | conversion_request.config().use_zip_code_conversion(), | |
191 | conversion_request.config().use_t13n_conversion(), | |
192 | pos_matcher_, | |
193 | suppression_dictionary_, | |
194 | callback); | |
195 | for (size_t i = 0; i < dics_.size(); ++i) { | |
196 | dics_[i]->LookupExact(key, conversion_request, &callback_with_filter); | |
197 | } | |
198 | } | |
199 | ||
200 | void DictionaryImpl::LookupReverse( | |
201 | StringPiece str, | |
202 | const ConversionRequest &conversion_request, | |
203 | Callback *callback) const { | |
204 | CallbackWithFilter callback_with_filter( | |
205 | conversion_request.config().use_spelling_correction(), | |
206 | conversion_request.config().use_zip_code_conversion(), | |
207 | conversion_request.config().use_t13n_conversion(), | |
208 | pos_matcher_, | |
209 | suppression_dictionary_, | |
210 | callback); | |
211 | for (size_t i = 0; i < dics_.size(); ++i) { | |
212 | dics_[i]->LookupReverse(str, conversion_request, &callback_with_filter); | |
205 | 213 | } |
206 | 214 | } |
207 | 215 | |
208 | 216 | bool DictionaryImpl::LookupComment(StringPiece key, StringPiece value, |
217 | const ConversionRequest &conversion_request, | |
209 | 218 | string *comment) const { |
210 | 219 | // TODO(komatsu): UserDictionary should be treated as the highest priority. |
211 | 220 | // In the current implementation, UserDictionary is the last node of dics_, |
212 | 221 | // but the only dictionary which may return true. |
213 | 222 | for (size_t i = 0; i < dics_.size(); ++i) { |
214 | if (dics_[i]->LookupComment(key, value, comment)) { | |
223 | if (dics_[i]->LookupComment(key, value, conversion_request, comment)) { | |
215 | 224 | return true; |
216 | 225 | } |
217 | 226 | } |
62 | 62 | |
63 | 63 | virtual bool HasKey(StringPiece key) const; |
64 | 64 | virtual bool HasValue(StringPiece value) const; |
65 | virtual void LookupPredictive( | |
66 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
67 | Callback *callback) const; | |
68 | virtual void LookupPrefix( | |
69 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
70 | Callback *callback) const; | |
71 | virtual void LookupExact(StringPiece key, Callback *callback) const; | |
72 | virtual void LookupReverse(StringPiece str, Callback *callback) const; | |
65 | virtual void LookupPredictive(StringPiece key, | |
66 | const ConversionRequest &conversion_request, | |
67 | Callback *callback) const; | |
68 | virtual void LookupPrefix(StringPiece key, | |
69 | const ConversionRequest &conversion_request, | |
70 | Callback *callback) const; | |
71 | ||
72 | virtual void LookupExact(StringPiece key, | |
73 | const ConversionRequest &conversion_request, | |
74 | Callback *callback) const; | |
75 | ||
76 | virtual void LookupReverse(StringPiece str, | |
77 | const ConversionRequest &conversion_request, | |
78 | Callback *callback) const; | |
79 | ||
73 | 80 | virtual bool LookupComment(StringPiece key, StringPiece value, |
81 | const ConversionRequest &conversion_request, | |
74 | 82 | string *comment) const; |
75 | 83 | virtual bool Reload(); |
76 | 84 | virtual void PopulateReverseLookupCache(StringPiece str) const; |
36 | 36 | #include "base/system_util.h" |
37 | 37 | #include "base/util.h" |
38 | 38 | #include "config/config_handler.h" |
39 | #include "request/conversion_request.h" | |
39 | 40 | #include "converter/node_allocator.h" |
40 | 41 | #include "data_manager/testing/mock_data_manager.h" |
41 | 42 | #include "dictionary/dictionary_interface.h" |
193 | 194 | // Pair of DictionaryInterface's lookup method and query text. |
194 | 195 | struct LookupMethodAndQuery { |
195 | 196 | void (DictionaryInterface::*lookup_method)( |
196 | StringPiece, bool, DictionaryInterface::Callback *) const; | |
197 | StringPiece, | |
198 | const ConversionRequest &, | |
199 | DictionaryInterface::Callback *) const; | |
197 | 200 | const char *query; |
198 | 201 | }; |
202 | ||
203 | ConversionRequest convreq_; | |
199 | 204 | }; |
200 | 205 | |
201 | 206 | TEST_F(DictionaryImplTest, WordSuppressionTest) { |
225 | 230 | s->UnLock(); |
226 | 231 | for (size_t i = 0; i < arraysize(kTestPair); ++i) { |
227 | 232 | CheckKeyValueExistenceCallback callback(kKey, kValue); |
228 | (d->*kTestPair[i].lookup_method)(kTestPair[i].query, false, &callback); | |
233 | (d->*kTestPair[i].lookup_method)(kTestPair[i].query, convreq_, &callback); | |
229 | 234 | EXPECT_FALSE(callback.found()); |
230 | 235 | } |
231 | 236 | |
235 | 240 | s->UnLock(); |
236 | 241 | for (size_t i = 0; i < arraysize(kTestPair); ++i) { |
237 | 242 | CheckKeyValueExistenceCallback callback(kKey, kValue); |
238 | (d->*kTestPair[i].lookup_method)(kTestPair[i].query, false, &callback); | |
243 | (d->*kTestPair[i].lookup_method)(kTestPair[i].query, convreq_, &callback); | |
239 | 244 | EXPECT_TRUE(callback.found()); |
240 | 245 | } |
241 | 246 | } |
262 | 267 | config::ConfigHandler::SetConfig(config); |
263 | 268 | for (size_t i = 0; i < arraysize(kTestPair); ++i) { |
264 | 269 | CheckSpellingExistenceCallback callback(kKey, kValue); |
265 | (d->*kTestPair[i].lookup_method)(kTestPair[i].query, false, &callback); | |
270 | (d->*kTestPair[i].lookup_method)(kTestPair[i].query, convreq_, &callback); | |
266 | 271 | EXPECT_TRUE(callback.found()); |
267 | 272 | } |
268 | 273 | |
271 | 276 | config::ConfigHandler::SetConfig(config);; |
272 | 277 | for (size_t i = 0; i < arraysize(kTestPair); ++i) { |
273 | 278 | CheckSpellingExistenceCallback callback(kKey, kValue); |
274 | (d->*kTestPair[i].lookup_method)(kTestPair[i].query, false, &callback); | |
279 | (d->*kTestPair[i].lookup_method)(kTestPair[i].query, convreq_, &callback); | |
275 | 280 | EXPECT_FALSE(callback.found()); |
276 | 281 | } |
277 | 282 | } |
297 | 302 | config::ConfigHandler::SetConfig(config); |
298 | 303 | for (size_t i = 0; i < arraysize(kTestPair); ++i) { |
299 | 304 | CheckZipCodeExistenceCallback callback(kKey, kValue, data->pos_matcher); |
300 | (d->*kTestPair[i].lookup_method)(kTestPair[i].query, false, &callback); | |
305 | (d->*kTestPair[i].lookup_method)(kTestPair[i].query, convreq_, &callback); | |
301 | 306 | EXPECT_TRUE(callback.found()); |
302 | 307 | } |
303 | 308 | |
306 | 311 | config::ConfigHandler::SetConfig(config);; |
307 | 312 | for (size_t i = 0; i < arraysize(kTestPair); ++i) { |
308 | 313 | CheckZipCodeExistenceCallback callback(kKey, kValue, data->pos_matcher); |
309 | (d->*kTestPair[i].lookup_method)(kTestPair[i].query, false, &callback); | |
314 | (d->*kTestPair[i].lookup_method)(kTestPair[i].query, convreq_, &callback); | |
310 | 315 | EXPECT_FALSE(callback.found()); |
311 | 316 | } |
312 | 317 | } |
334 | 339 | config::ConfigHandler::SetConfig(config); |
335 | 340 | for (size_t i = 0; i < arraysize(kTestPair); ++i) { |
336 | 341 | CheckEnglishT13nCallback callback(kKey, kValue); |
337 | (d->*kTestPair[i].lookup_method)(kTestPair[i].query, false, &callback); | |
342 | (d->*kTestPair[i].lookup_method)(kTestPair[i].query, convreq_, &callback); | |
338 | 343 | EXPECT_TRUE(callback.found()); |
339 | 344 | } |
340 | 345 | |
343 | 348 | config::ConfigHandler::SetConfig(config);; |
344 | 349 | for (size_t i = 0; i < arraysize(kTestPair); ++i) { |
345 | 350 | CheckEnglishT13nCallback callback(kKey, kValue); |
346 | (d->*kTestPair[i].lookup_method)(kTestPair[i].query, false, &callback); | |
351 | (d->*kTestPair[i].lookup_method)(kTestPair[i].query, convreq_, &callback); | |
347 | 352 | EXPECT_FALSE(callback.found()); |
348 | 353 | } |
349 | 354 | } |
354 | 359 | NodeAllocator allocator; |
355 | 360 | |
356 | 361 | string comment; |
357 | EXPECT_FALSE(d->LookupComment("key", "value", &comment)); | |
362 | EXPECT_FALSE(d->LookupComment("key", "value", convreq_, &comment)); | |
358 | 363 | EXPECT_TRUE(comment.empty()); |
359 | 364 | |
360 | 365 | // If key or value is "comment", UserDictionaryStub returns |
361 | 366 | // "UserDictionaryStub" as comment. |
362 | EXPECT_TRUE(d->LookupComment("key", "comment", &comment)); | |
367 | EXPECT_TRUE(d->LookupComment("key", "comment", convreq_, &comment)); | |
363 | 368 | EXPECT_EQ("UserDictionaryStub", comment); |
364 | 369 | } |
365 | 370 |
35 | 35 | #include "base/port.h" |
36 | 36 | #include "base/string_piece.h" |
37 | 37 | #include "dictionary/dictionary_token.h" |
38 | #include "request/conversion_request.h" | |
38 | 39 | |
39 | 40 | namespace mozc { |
40 | 41 | namespace dictionary { |
114 | 115 | // Returns true if the dictionary has an entry for the given value. |
115 | 116 | virtual bool HasValue(StringPiece value) const = 0; |
116 | 117 | |
117 | virtual void LookupPredictive( | |
118 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
119 | Callback *callback) const = 0; | |
118 | virtual void LookupPredictive(StringPiece key, | |
119 | const ConversionRequest &conversion_request, | |
120 | Callback *callback) const = 0; | |
120 | 121 | |
121 | virtual void LookupPrefix( | |
122 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
123 | Callback *callback) const = 0; | |
122 | virtual void LookupPrefix(StringPiece key, | |
123 | const ConversionRequest &conversion_request, | |
124 | Callback *callback) const = 0; | |
124 | 125 | |
125 | virtual void LookupExact(StringPiece key, Callback *callback) const = 0; | |
126 | virtual void LookupExact(StringPiece key, | |
127 | const ConversionRequest &conversion_request, | |
128 | Callback *callback) const = 0; | |
126 | 129 | |
127 | 130 | // For reverse lookup, the reading is stored in Token::value and the word |
128 | 131 | // is stored in Token::key. |
129 | virtual void LookupReverse(StringPiece str, Callback *callback) const = 0; | |
132 | virtual void LookupReverse(StringPiece str, | |
133 | const ConversionRequest &conversion_request, | |
134 | Callback *callback) const = 0; | |
130 | 135 | |
131 | 136 | // Looks up a user comment from a pair of key and value. When (key, value) |
132 | 137 | // doesn't exist in this dictionary or user comment is empty, bool is |
133 | 138 | // returned and string is kept as-is. |
134 | 139 | virtual bool LookupComment(StringPiece key, StringPiece value, |
140 | const ConversionRequest &conversion_request, | |
135 | 141 | string *comment) const { return false; } |
136 | 142 | |
137 | 143 | // Populates cache for LookupReverse(). |
47 | 47 | |
48 | 48 | bool HasKeyInternal(const map<string, vector<Token *>> &dic, StringPiece key) { |
49 | 49 | typedef vector<Token *> TokenPtrVector; |
50 | for (map<string, vector<Token *> >::const_iterator map_it = dic.begin(); | |
50 | for (map<string, vector<Token *>>::const_iterator map_it = dic.begin(); | |
51 | 51 | map_it != dic.end(); ++map_it) { |
52 | 52 | const TokenPtrVector &v = map_it->second; |
53 | 53 | for (TokenPtrVector::const_iterator it = v.begin(); it != v.end(); ++it) { |
62 | 62 | bool HasValueInternal(const map<string, vector<Token *>> &dic, |
63 | 63 | StringPiece value) { |
64 | 64 | typedef vector<Token *> TokenPtrVector; |
65 | for (map<string, vector<Token *> >::const_iterator map_it = dic.begin(); | |
65 | for (map<string, vector<Token *>>::const_iterator map_it = dic.begin(); | |
66 | 66 | map_it != dic.end(); ++map_it) { |
67 | 67 | const TokenPtrVector &v = map_it->second; |
68 | 68 | for (TokenPtrVector::const_iterator it = v.begin(); it != v.end(); ++it) { |
86 | 86 | return token.release(); |
87 | 87 | } |
88 | 88 | |
89 | void DeletePtrs(map<string, vector<Token *> > *m) { | |
90 | for (map<string, vector<Token *> >::iterator iter = m->begin(); | |
89 | void DeletePtrs(map<string, vector<Token *>> *m) { | |
90 | for (map<string, vector<Token *>>::iterator iter = m->begin(); | |
91 | 91 | iter != m->end(); ++iter) { |
92 | 92 | STLDeleteElements(&iter->second); |
93 | 93 | } |
122 | 122 | |
123 | 123 | void DictionaryMock::LookupPredictive( |
124 | 124 | StringPiece key, |
125 | bool, // use_kana_modifier_insensitive_lookup | |
126 | Callback *callback) const { | |
127 | map<string, vector<Token *> >::const_iterator vector_iter = | |
125 | const ConversionRequest &conversion_request, | |
126 | Callback *callback) const { | |
127 | map<string, vector<Token *>>::const_iterator vector_iter = | |
128 | 128 | predictive_dictionary_.find(key.as_string()); |
129 | 129 | if (vector_iter == predictive_dictionary_.end()) { |
130 | 130 | return; |
143 | 143 | |
144 | 144 | void DictionaryMock::LookupPrefix( |
145 | 145 | StringPiece key, |
146 | bool, // use_kana_modifier_insensitive_lookup | |
146 | const ConversionRequest &conversion_request, | |
147 | 147 | Callback *callback) const { |
148 | 148 | CHECK(!key.empty()); |
149 | 149 | |
150 | 150 | string prefix; |
151 | 151 | for (size_t len = 1; len <= key.size(); ++len) { |
152 | 152 | key.substr(0, len).CopyToString(&prefix); |
153 | map<string, vector<Token *> >::const_iterator iter = | |
153 | map<string, vector<Token *>>::const_iterator iter = | |
154 | 154 | prefix_dictionary_.find(prefix); |
155 | 155 | if (iter == prefix_dictionary_.end()) { |
156 | 156 | continue; |
187 | 187 | } |
188 | 188 | } |
189 | 189 | |
190 | void DictionaryMock::LookupExact(StringPiece key, Callback *callback) const { | |
191 | map<string, vector<Token *> >::const_iterator iter = | |
190 | void DictionaryMock::LookupExact( | |
191 | StringPiece key, | |
192 | const ConversionRequest &conversion_request, | |
193 | Callback *callback) const { | |
194 | map<string, vector<Token *>>::const_iterator iter = | |
192 | 195 | exact_dictionary_.find(key.as_string()); |
193 | 196 | if (iter == exact_dictionary_.end()) { |
194 | 197 | return; |
205 | 208 | } |
206 | 209 | } |
207 | 210 | |
208 | void DictionaryMock::LookupReverse(StringPiece str, Callback *callback) const { | |
211 | void DictionaryMock::LookupReverse( | |
212 | StringPiece str, | |
213 | const ConversionRequest &conversion_request, | |
214 | Callback *callback) const { | |
209 | 215 | CHECK(!str.empty()); |
210 | 216 | |
211 | 217 | for (int i = 1; i <= str.size(); ++i) { |
212 | 218 | StringPiece prefix = str.substr(0, i); |
213 | 219 | |
214 | map<string, vector<Token *> >::const_iterator iter = | |
220 | map<string, vector<Token *>>::const_iterator iter = | |
215 | 221 | reverse_dictionary_.find(prefix.as_string()); |
216 | 222 | if (iter == reverse_dictionary_.end()) { |
217 | 223 | continue; |
59 | 59 | #include "base/string_piece.h" |
60 | 60 | #include "dictionary/dictionary_interface.h" |
61 | 61 | #include "dictionary/dictionary_token.h" |
62 | #include "request/conversion_request.h" | |
62 | 63 | |
63 | 64 | namespace mozc { |
64 | 65 | namespace dictionary { |
75 | 76 | // DictionaryMock doesn't support a limitation. Note also that only the |
76 | 77 | // tokens whose keys exactly match the registered key are looked up; see the |
77 | 78 | // comment of AddLookupPredictive. |
78 | virtual void LookupPredictive( | |
79 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
80 | Callback *callback) const; | |
79 | virtual void LookupPredictive(StringPiece key, | |
80 | const ConversionRequest &conversion_request, | |
81 | Callback *callback) const; | |
81 | 82 | |
82 | virtual void LookupPrefix( | |
83 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
84 | Callback *callback) const; | |
83 | virtual void LookupPrefix(StringPiece key, | |
84 | const ConversionRequest &conversion_request, | |
85 | Callback *callback) const; | |
85 | 86 | |
86 | virtual void LookupExact(StringPiece key, Callback *callback) const; | |
87 | virtual void LookupExact(StringPiece key, | |
88 | const ConversionRequest &conversion_request, | |
89 | Callback *callback) const; | |
87 | 90 | |
88 | 91 | // For reverse lookup, the reading is stored in Token::value and the word |
89 | 92 | // is stored in Token::key. |
90 | virtual void LookupReverse(StringPiece str, Callback *callback) const; | |
93 | virtual void LookupReverse(StringPiece str, | |
94 | const ConversionRequest &conversion_request, | |
95 | Callback *callback) const; | |
91 | 96 | |
92 | 97 | // Adds a string-result pair to the predictive search result. |
93 | 98 | // LookupPrefix will return the result only when the search key exactly |
120 | 125 | Token::AttributesBitfield token_attributes); |
121 | 126 | |
122 | 127 | private: |
123 | map<string, vector<Token *> > reverse_dictionary_; | |
124 | map<string, vector<Token *> > prefix_dictionary_; | |
125 | map<string, vector<Token *> > exact_dictionary_; | |
126 | map<string, vector<Token *> > predictive_dictionary_; | |
128 | map<string, vector<Token *>> reverse_dictionary_; | |
129 | map<string, vector<Token *>> prefix_dictionary_; | |
130 | map<string, vector<Token *>> exact_dictionary_; | |
131 | map<string, vector<Token *>> predictive_dictionary_; | |
127 | 132 | |
128 | 133 | DISALLOW_COPY_AND_ASSIGN(DictionaryMock); |
129 | 134 | }; |
34 | 34 | |
35 | 35 | #include "base/logging.h" |
36 | 36 | #include "base/util.h" |
37 | #include "request/conversion_request.h" | |
37 | 38 | #include "dictionary/dictionary_test_util.h" |
38 | 39 | #include "dictionary/dictionary_token.h" |
39 | 40 | #include "testing/base/public/gunit.h" |
63 | 64 | const vector<Token> &tokens); |
64 | 65 | |
65 | 66 | unique_ptr<DictionaryMock> mock_; |
67 | ConversionRequest convreq_; | |
66 | 68 | }; |
67 | 69 | |
68 | 70 | bool DictionaryMockTest::SearchMatchingToken(const string &key, |
136 | 138 | dic->AddLookupPrefix(t1->key, t1->key, t1->value, Token::NONE); |
137 | 139 | |
138 | 140 | CollectTokenCallback callback; |
139 | dic->LookupPrefix(t0->key, false, &callback); | |
141 | dic->LookupPrefix(t0->key, convreq_, &callback); | |
140 | 142 | ASSERT_EQ(1, callback.tokens().size()); |
141 | 143 | EXPECT_TOKEN_EQ(*t0, callback.tokens()[0]); |
142 | 144 | |
143 | 145 | callback.Clear(); |
144 | dic->LookupPrefix(t1->key, false, &callback); | |
146 | dic->LookupPrefix(t1->key, convreq_, &callback); | |
145 | 147 | ASSERT_EQ(2, callback.tokens().size()); |
146 | 148 | EXPECT_TOKEN_EQ(*t0, callback.tokens()[0]); |
147 | 149 | EXPECT_TOKEN_EQ(*t1, callback.tokens()[1]); |
148 | 150 | |
149 | 151 | callback.Clear(); |
150 | dic->LookupPrefix("google", false, &callback); | |
152 | dic->LookupPrefix("google", convreq_, &callback); | |
151 | 153 | EXPECT_TRUE(callback.tokens().empty()); |
152 | 154 | } |
153 | 155 | |
174 | 176 | } |
175 | 177 | |
176 | 178 | CollectTokenCallback callback; |
177 | dic->LookupReverse(k1, &callback); | |
179 | dic->LookupReverse(k1, convreq_, &callback); | |
178 | 180 | const vector<Token> &result_tokens = callback.tokens(); |
179 | 181 | EXPECT_TRUE(SearchMatchingToken(t0->key, t0->value, 0, result_tokens)) |
180 | 182 | << "Failed to find: " << t0->key; |
203 | 205 | } |
204 | 206 | |
205 | 207 | CollectTokenCallback callback; |
206 | dic->LookupPredictive(k0, false, &callback); | |
208 | dic->LookupPredictive(k0, convreq_, &callback); | |
207 | 209 | ASSERT_EQ(2, callback.tokens().size()); |
208 | 210 | EXPECT_TOKEN_EQ(*t1, callback.tokens()[0]); |
209 | 211 | EXPECT_TOKEN_EQ(*t2, callback.tokens()[1]); |
221 | 223 | GetMock()->AddLookupExact(t1->key, t1->key, t1->value, Token::NONE); |
222 | 224 | |
223 | 225 | CollectTokenCallback callback; |
224 | dic->LookupExact(kKey, &callback); | |
226 | dic->LookupExact(kKey, convreq_, &callback); | |
225 | 227 | ASSERT_EQ(2, callback.tokens().size()); |
226 | 228 | EXPECT_TOKEN_EQ(*t0, callback.tokens()[0]); |
227 | 229 | EXPECT_TOKEN_EQ(*t1, callback.tokens()[1]); |
228 | 230 | |
229 | 231 | callback.Clear(); |
230 | dic->LookupExact("hoge", &callback); | |
232 | dic->LookupExact("hoge", convreq_, &callback); | |
231 | 233 | EXPECT_TRUE(callback.tokens().empty()); |
232 | 234 | |
233 | 235 | callback.Clear(); |
234 | 236 | dic->LookupExact("\xE3\x81\xBB", // "ほ" |
237 | convreq_, | |
235 | 238 | &callback); |
236 | 239 | EXPECT_TRUE(callback.tokens().empty()); |
237 | 240 | } |
90 | 90 | |
91 | 91 | void SuffixDictionary::LookupPredictive( |
92 | 92 | StringPiece key, |
93 | bool, // use_kana_modifier_insensitive_lookup | |
93 | const ConversionRequest &conversion_request, | |
94 | 94 | Callback *callback) const { |
95 | 95 | typedef IteratorAdapter<const SuffixToken *, SuffixTokenKeyAdapter> Iter; |
96 | 96 | pair<Iter, Iter> range = std::equal_range( |
126 | 126 | } |
127 | 127 | } |
128 | 128 | |
129 | void SuffixDictionary::LookupPrefix(StringPiece key, | |
130 | bool use_kana_modifier_insensitive_lookup, | |
131 | Callback *callback) const { | |
129 | void SuffixDictionary::LookupPrefix( | |
130 | StringPiece key, | |
131 | const ConversionRequest &conversion_request, | |
132 | Callback *callback) const { | |
132 | 133 | } |
133 | 134 | |
134 | void SuffixDictionary::LookupReverse(StringPiece str, | |
135 | Callback *callback) const { | |
135 | void SuffixDictionary::LookupExact( | |
136 | StringPiece key, | |
137 | const ConversionRequest &conversion_request, | |
138 | Callback *callback) const { | |
136 | 139 | } |
137 | 140 | |
138 | void SuffixDictionary::LookupExact(StringPiece key, Callback *callback) const { | |
141 | void SuffixDictionary::LookupReverse( | |
142 | StringPiece key, | |
143 | const ConversionRequest &conversion_request, | |
144 | Callback *callback) const { | |
139 | 145 | } |
140 | 146 | |
141 | 147 | } // namespace dictionary |
59 | 59 | virtual bool HasValue(StringPiece value) const; |
60 | 60 | |
61 | 61 | // Kana modifier insensitive lookup is not supported. |
62 | virtual void LookupPredictive( | |
63 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
64 | Callback *callback) const; | |
62 | virtual void LookupPredictive(StringPiece key, | |
63 | const ConversionRequest &conversion_request, | |
64 | Callback *callback) const; | |
65 | 65 | |
66 | 66 | // SuffixDictionary doesn't support Prefix/Revese/Exact Lookup. |
67 | virtual void LookupPrefix( | |
68 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
69 | Callback *callback) const; | |
70 | virtual void LookupReverse(StringPiece str, Callback *callback) const; | |
71 | virtual void LookupExact(StringPiece key, Callback *callback) const; | |
67 | virtual void LookupPrefix(StringPiece key, | |
68 | const ConversionRequest &conversion_request, | |
69 | Callback *callback) const; | |
70 | ||
71 | virtual void LookupExact(StringPiece key, | |
72 | const ConversionRequest &conversion_request, | |
73 | Callback *callback) const; | |
74 | ||
75 | virtual void LookupReverse(StringPiece str, | |
76 | const ConversionRequest &conversion_request, | |
77 | Callback *callback) const; | |
72 | 78 | |
73 | 79 | private: |
74 | 80 | const SuffixToken *const suffix_tokens_; |
35 | 35 | #include "dictionary/dictionary_interface.h" |
36 | 36 | #include "dictionary/dictionary_test_util.h" |
37 | 37 | #include "dictionary/suffix_dictionary_token.h" |
38 | #include "request/conversion_request.h" | |
38 | 39 | #include "testing/base/public/gunit.h" |
39 | 40 | |
40 | 41 | namespace mozc { |
43 | 44 | TEST(SuffixDictionaryTest, LookupPredictive) { |
44 | 45 | // Test SuffixDictionary with mock data. |
45 | 46 | std::unique_ptr<const SuffixDictionary> dic; |
47 | ConversionRequest convreq; | |
46 | 48 | { |
47 | 49 | const testing::MockDataManager manager; |
48 | 50 | const SuffixToken *tokens = NULL; |
56 | 58 | // Lookup with empty key. All tokens are looked up. Here, just verify the |
57 | 59 | // result is nonempty and each token has valid data. |
58 | 60 | CollectTokenCallback callback; |
59 | dic->LookupPredictive("", false, &callback); | |
61 | dic->LookupPredictive("", convreq, &callback); | |
60 | 62 | EXPECT_FALSE(callback.tokens().empty()); |
61 | 63 | for (size_t i = 0; i < callback.tokens().size(); ++i) { |
62 | 64 | const Token &token = callback.tokens()[i]; |
71 | 73 | // Non-empty prefix. |
72 | 74 | const string kPrefix = "\xE3\x81\x9F"; // "た" |
73 | 75 | CollectTokenCallback callback; |
74 | dic->LookupPredictive(kPrefix, false, &callback); | |
76 | dic->LookupPredictive(kPrefix, convreq, &callback); | |
75 | 77 | EXPECT_FALSE(callback.tokens().empty()); |
76 | 78 | for (size_t i = 0; i < callback.tokens().size(); ++i) { |
77 | 79 | const Token &token = callback.tokens()[i]; |
654 | 654 | } |
655 | 655 | |
656 | 656 | void SystemDictionary::LookupPredictive( |
657 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
657 | StringPiece key, | |
658 | const ConversionRequest &conversion_request, | |
658 | 659 | Callback *callback) const { |
659 | 660 | // Do nothing for empty key, although looking up all the entries with empty |
660 | 661 | // string seems natural. |
668 | 669 | return; |
669 | 670 | } |
670 | 671 | |
671 | const KeyExpansionTable &table = use_kana_modifier_insensitive_lookup | |
672 | ? hiragana_expansion_table_ | |
673 | : KeyExpansionTable::GetDefaultInstance(); | |
672 | const KeyExpansionTable &table = | |
673 | conversion_request.IsKanaModifierInsensitiveConversion() ? | |
674 | hiragana_expansion_table_ : KeyExpansionTable::GetDefaultInstance(); | |
674 | 675 | |
675 | 676 | // TODO(noriyukit): Lookup limit should be implemented at caller side by using |
676 | 677 | // callback mechanism. This hard-coding limits the capability and generality |
965 | 966 | |
966 | 967 | void SystemDictionary::LookupPrefix( |
967 | 968 | StringPiece key, |
968 | bool use_kana_modifier_insensitive_lookup, | |
969 | const ConversionRequest &conversion_request, | |
969 | 970 | Callback *callback) const { |
970 | 971 | string encoded_key; |
971 | 972 | codec_->EncodeKey(key, &encoded_key); |
972 | 973 | |
973 | if (!use_kana_modifier_insensitive_lookup) { | |
974 | if (!conversion_request.IsKanaModifierInsensitiveConversion()) { | |
974 | 975 | RunCallbackOnEachPrefix(key_trie_, value_trie_, token_array_, codec_, |
975 | 976 | frequent_pos_, key.data(), encoded_key, callback, |
976 | 977 | SelectAllTokens()); |
986 | 987 | actual_key_buffer, &actual_prefix); |
987 | 988 | } |
988 | 989 | |
989 | void SystemDictionary::LookupExact(StringPiece key, Callback *callback) const { | |
990 | void SystemDictionary::LookupExact( | |
991 | StringPiece key, | |
992 | const ConversionRequest &conversion_request, | |
993 | Callback *callback) const { | |
990 | 994 | // Find the key in the key trie. |
991 | 995 | string encoded_key; |
992 | 996 | codec_->EncodeKey(key, &encoded_key); |
1009 | 1013 | } |
1010 | 1014 | } |
1011 | 1015 | |
1012 | void SystemDictionary::LookupReverse(StringPiece str, | |
1013 | Callback *callback) const { | |
1016 | void SystemDictionary::LookupReverse( | |
1017 | StringPiece str, | |
1018 | const ConversionRequest &conversion_request, | |
1019 | Callback *callback) const { | |
1014 | 1020 | // 1st step: Hiragana/Katakana are not in the value trie |
1015 | 1021 | // 2nd step: Reverse lookup in value trie |
1016 | 1022 | ReverseLookupCallbackWrapper callback_wrapper(callback); |
55 | 55 | ], |
56 | 56 | 'dependencies': [ |
57 | 57 | '../../base/base.gyp:base_core', |
58 | '../../request/request.gyp:conversion_request', | |
58 | 59 | '../../storage/louds/louds.gyp:bit_vector_based_array', |
59 | 60 | '../../storage/louds/louds.gyp:louds_trie', |
60 | 61 | '../dictionary_base.gyp:text_dictionary_loader', |
98 | 98 | // Implementation of DictionaryInterface. |
99 | 99 | virtual bool HasKey(StringPiece key) const; |
100 | 100 | virtual bool HasValue(StringPiece value) const; |
101 | virtual void LookupPredictive( | |
102 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
103 | Callback *callback) const; | |
104 | virtual void LookupPrefix( | |
105 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
106 | Callback *callback) const; | |
107 | virtual void LookupExact(StringPiece key, Callback *callback) const; | |
108 | virtual void LookupReverse(StringPiece str, Callback *callback) const; | |
101 | ||
102 | virtual void LookupPredictive(StringPiece key, | |
103 | const ConversionRequest &converter_request, | |
104 | Callback *callback) const; | |
105 | ||
106 | virtual void LookupPrefix(StringPiece key, | |
107 | const ConversionRequest &converter_request, | |
108 | Callback *callback) const; | |
109 | ||
110 | virtual void LookupExact(StringPiece key, | |
111 | const ConversionRequest &converter_request, | |
112 | Callback *callback) const; | |
113 | ||
114 | virtual void LookupReverse(StringPiece str, | |
115 | const ConversionRequest &converter_request, | |
116 | Callback *callback) const; | |
117 | ||
109 | 118 | virtual void PopulateReverseLookupCache(StringPiece str) const; |
110 | 119 | virtual void ClearReverseLookupCache() const; |
111 | 120 |
41 | 41 | #include "base/stl_util.h" |
42 | 42 | #include "base/system_util.h" |
43 | 43 | #include "base/util.h" |
44 | #include "config/config_handler.h" | |
44 | 45 | #include "data_manager/user_pos_manager.h" |
45 | 46 | #include "dictionary/dictionary_test_util.h" |
46 | 47 | #include "dictionary/dictionary_token.h" |
48 | 49 | #include "dictionary/system/codec_interface.h" |
49 | 50 | #include "dictionary/system/system_dictionary_builder.h" |
50 | 51 | #include "dictionary/text_dictionary_loader.h" |
52 | #include "protocol/commands.pb.h" | |
53 | #include "protocol/config.pb.h" | |
54 | #include "request/conversion_request.h" | |
51 | 55 | #include "testing/base/public/googletest.h" |
52 | 56 | #include "testing/base/public/gunit.h" |
53 | 57 | |
87 | 91 | |
88 | 92 | namespace { |
89 | 93 | |
90 | const bool kEnableKanaModiferInsensitiveLookup = true; | |
91 | const bool kDisableKanaModiferInsensitiveLookup = false; | |
92 | ||
94 | // This function will be removed soon in the following change, which | |
95 | // enables to inject config to ConversionRequest. | |
96 | void config_set_use_kana_modifier_insensitive_conversion(bool is_enable) { | |
97 | config::Config config; | |
98 | config::ConfigHandler::GetDefaultConfig(&config); | |
99 | config.set_use_kana_modifier_insensitive_conversion(is_enable); | |
100 | config::ConfigHandler::SetConfig(config); | |
101 | } | |
93 | 102 | } // namespace |
94 | 103 | |
95 | 104 | class SystemDictionaryTest : public testing::Test { |
101 | 110 | const string dic_path = FileUtil::JoinPath(FLAGS_test_srcdir, |
102 | 111 | FLAGS_dictionary_source); |
103 | 112 | text_dict_->LoadWithLineLimit(dic_path, "", FLAGS_dictionary_test_size); |
113 | ||
114 | convreq_.set_request(&request_); | |
104 | 115 | } |
105 | 116 | |
106 | 117 | virtual void SetUp() { |
110 | 121 | original_flags_min_key_length_to_use_small_cost_encoding_ = |
111 | 122 | FLAGS_min_key_length_to_use_small_cost_encoding; |
112 | 123 | FLAGS_min_key_length_to_use_small_cost_encoding = kint32max; |
124 | ||
125 | request_.Clear(); | |
126 | ||
127 | // This config initialization will be removed once ConversionRequest can | |
128 | // take config as an injected argument. | |
129 | config::Config config; | |
130 | config::ConfigHandler::GetDefaultConfig(&config); | |
131 | config::ConfigHandler::SetConfig(config); | |
113 | 132 | } |
114 | 133 | |
115 | 134 | virtual void TearDown() { |
116 | 135 | FLAGS_min_key_length_to_use_small_cost_encoding = |
117 | 136 | original_flags_min_key_length_to_use_small_cost_encoding_; |
137 | ||
138 | // This config initialization will be removed once ConversionRequest can | |
139 | // take config as an injected argument. | |
140 | config::Config config; | |
141 | config::ConfigHandler::GetDefaultConfig(&config); | |
142 | config::ConfigHandler::SetConfig(config); | |
118 | 143 | } |
119 | 144 | |
120 | 145 | void BuildSystemDictionary(const vector <Token *>& tokens, |
124 | 149 | bool reverse) const; |
125 | 150 | |
126 | 151 | unique_ptr<TextDictionaryLoader> text_dict_; |
152 | ||
153 | ConversionRequest convreq_; | |
154 | commands::Request request_; | |
127 | 155 | const string dic_fn_; |
128 | 156 | int original_flags_min_key_length_to_use_small_cost_encoding_; |
129 | 157 | }; |
305 | 333 | CollectTokenCallback callback; |
306 | 334 | |
307 | 335 | // Look up by exact key. |
308 | system_dic->LookupPrefix(t0->key, false, &callback); | |
336 | system_dic->LookupPrefix(t0->key, convreq_, &callback); | |
309 | 337 | ASSERT_EQ(1, callback.tokens().size()); |
310 | 338 | EXPECT_TOKEN_EQ(*t0, callback.tokens().front()); |
311 | 339 | |
313 | 341 | callback.Clear(); |
314 | 342 | system_dic->LookupPrefix( |
315 | 343 | "\xE3\x81\x82\xE3\x81\x84\xE3\x81\x86", // "あいう" |
316 | false, &callback); | |
344 | convreq_, &callback); | |
317 | 345 | ASSERT_EQ(1, callback.tokens().size()); |
318 | 346 | EXPECT_TOKEN_EQ(*t0, callback.tokens().front()); |
319 | 347 | |
321 | 349 | callback.Clear(); |
322 | 350 | system_dic->LookupPrefix( |
323 | 351 | "\xE3\x81\x8B\xE3\x81\x8D\xE3\x81\x8F", // "かきく" |
324 | false, &callback); | |
352 | convreq_, &callback); | |
325 | 353 | EXPECT_TRUE(callback.tokens().empty()); |
326 | 354 | } |
327 | 355 | |
366 | 394 | // All the tokens should be looked up. |
367 | 395 | CollectTokenCallback callback; |
368 | 396 | system_dic->LookupPrefix("\xe3\x81\x82", // "あ" |
369 | false, &callback); | |
397 | convreq_, &callback); | |
370 | 398 | EXPECT_TOKENS_EQ_UNORDERED(source_tokens, callback.tokens()); |
371 | 399 | } |
372 | 400 | |
382 | 410 | // All the tokens should be looked up. |
383 | 411 | for (size_t i = 0; i < source_tokens.size(); ++i) { |
384 | 412 | CheckTokenExistenceCallback callback(source_tokens[i]); |
385 | system_dic->LookupPrefix(source_tokens[i]->key, false, &callback); | |
413 | system_dic->LookupPrefix(source_tokens[i]->key, convreq_, &callback); | |
386 | 414 | EXPECT_TRUE(callback.found()) |
387 | 415 | << "Token was not found: " << PrintToken(*source_tokens[i]); |
388 | 416 | } |
410 | 438 | |
411 | 439 | // |t0| should be looked up from |k1|. |
412 | 440 | CheckTokenExistenceCallback callback(t0.get()); |
413 | system_dic->LookupPrefix(k1, false, &callback); | |
441 | system_dic->LookupPrefix(k1, convreq_, &callback); | |
414 | 442 | EXPECT_TRUE(callback.found()); |
415 | 443 | } |
416 | 444 | |
435 | 463 | return TRAVERSE_CONTINUE; |
436 | 464 | } |
437 | 465 | |
438 | const set<pair<string, string> > &result() const { | |
466 | const set<pair<string, string>> &result() const { | |
439 | 467 | return result_; |
440 | 468 | } |
441 | 469 | |
442 | 470 | private: |
443 | set<pair<string, string> > result_; | |
471 | set<pair<string, string>> result_; | |
444 | 472 | }; |
445 | 473 | |
446 | 474 | } // namespace |
520 | 548 | { |
521 | 549 | LookupPrefixTestCallback callback; |
522 | 550 | system_dic->LookupPrefix("\xE3\x81\x82\xE3\x81\x84", // "あい" |
523 | false, &callback); | |
524 | const set<pair<string, string> > &result = callback.result(); | |
551 | convreq_, &callback); | |
552 | const set<pair<string, string>> &result = callback.result(); | |
525 | 553 | // "あ" -- "あい" should be found. |
526 | 554 | for (size_t i = 0; i < 5; ++i) { |
527 | 555 | const pair<string, string> entry( |
542 | 570 | LookupPrefixTestCallback callback; |
543 | 571 | system_dic->LookupPrefix( |
544 | 572 | "\xE3\x81\x8B\xE3\x81\x8D\xE3\x81\x8F", //"かきく" |
545 | false, | |
573 | convreq_, | |
546 | 574 | &callback); |
547 | const set<pair<string, string> > &result = callback.result(); | |
575 | const set<pair<string, string>> &result = callback.result(); | |
548 | 576 | // Only "か" should be found as the callback doesn't traverse the subtree of |
549 | 577 | // "かき" due to culling request from LookupPrefixTestCallback::OnKey(). |
550 | 578 | for (size_t i = 0; i < kKeyValuesSize; ++i) { |
560 | 588 | LookupPrefixTestCallback callback; |
561 | 589 | system_dic->LookupPrefix( |
562 | 590 | "\xE3\x81\x95\xE3\x81\x97\xE3\x81\x99", // "さしす" |
563 | false, | |
591 | convreq_, | |
564 | 592 | &callback); |
565 | const set<pair<string, string> > &result = callback.result(); | |
593 | const set<pair<string, string>> &result = callback.result(); | |
566 | 594 | // Only "さし" should be found as tokens for "さ" is skipped (see |
567 | 595 | // LookupPrefixTestCallback::OnKey()). |
568 | 596 | for (size_t i = 0; i < kKeyValuesSize; ++i) { |
578 | 606 | LookupPrefixTestCallback callback; |
579 | 607 | system_dic->LookupPrefix( |
580 | 608 | "\xE3\x81\x9F\xE3\x81\xA1\xE3\x81\xA4", // "たちつ" |
581 | false, | |
609 | convreq_, | |
582 | 610 | &callback); |
583 | const set<pair<string, string> > &result = callback.result(); | |
611 | const set<pair<string, string>> &result = callback.result(); | |
584 | 612 | // Nothing should be found as the traversal is immediately done after seeing |
585 | 613 | // "た"; see LookupPrefixTestCallback::OnKey(). |
586 | 614 | EXPECT_TRUE(result.empty()); |
589 | 617 | // Test for prefix lookup with key expansion. |
590 | 618 | { |
591 | 619 | LookupPrefixTestCallback callback; |
620 | // Use kana modifier insensitive lookup | |
621 | request_.set_kana_modifier_insensitive_conversion(true); | |
622 | config_set_use_kana_modifier_insensitive_conversion(true); | |
592 | 623 | system_dic->LookupPrefix( |
593 | 624 | "\xE3\x81\xAF\xE3\x81\xB2", // "はひ" |
594 | true, // Use kana modifier insensitive lookup | |
625 | convreq_, | |
595 | 626 | &callback); |
596 | const set<pair<string, string> > &result = callback.result(); | |
627 | const set<pair<string, string>> &result = callback.result(); | |
597 | 628 | const char *kExpectedKeys[] = { |
598 | 629 | "\xE3\x81\xAF", // "は" |
599 | 630 | "\xE3\x81\xB0", // "ば" |
616 | 647 | |
617 | 648 | TEST_F(SystemDictionaryTest, LookupPredictive) { |
618 | 649 | vector<Token *> tokens; |
619 | ScopedElementsDeleter<vector<Token *> > deleter(&tokens); | |
650 | ScopedElementsDeleter<vector<Token *>> deleter(&tokens); | |
620 | 651 | |
621 | 652 | // "まみむめもや" -> "value0" |
622 | 653 | tokens.push_back(CreateToken("\xe3\x81\xbe\xe3\x81\xbf\xe3\x82\x80" |
642 | 673 | const char *kMamimumemo = |
643 | 674 | "\xe3\x81\xbe\xe3\x81\xbf\xe3\x82\x80\xe3\x82\x81\xe3\x82\x82"; |
644 | 675 | CheckMultiTokensExistenceCallback callback(tokens); |
645 | system_dic->LookupPredictive(kMamimumemo, false, &callback); | |
676 | system_dic->LookupPredictive(kMamimumemo, convreq_, &callback); | |
646 | 677 | EXPECT_TRUE(callback.AreAllFound()); |
647 | 678 | } |
648 | 679 | |
649 | 680 | TEST_F(SystemDictionaryTest, LookupPredictive_KanaModifierInsensitiveLookup) { |
650 | 681 | vector<Token *> tokens; |
651 | ScopedElementsDeleter<vector<Token *> > deleter(&tokens); | |
682 | ScopedElementsDeleter<vector<Token *>> deleter(&tokens); | |
652 | 683 | |
653 | 684 | // "がっこう" -> "学校" |
654 | 685 | tokens.push_back(CreateToken( |
670 | 701 | |
671 | 702 | // Without Kana modifier insensitive lookup flag, nothing is looked up. |
672 | 703 | CollectTokenCallback callback; |
673 | system_dic->LookupPredictive(kKey, false, &callback); | |
704 | request_.set_kana_modifier_insensitive_conversion(false); | |
705 | config_set_use_kana_modifier_insensitive_conversion(false); | |
706 | system_dic->LookupPredictive(kKey, convreq_, &callback); | |
674 | 707 | EXPECT_TRUE(callback.tokens().empty()); |
675 | 708 | |
676 | 709 | // With Kana modifier insensitive lookup flag, every token is looked up. |
677 | 710 | callback.Clear(); |
678 | system_dic->LookupPredictive(kKey, true, &callback); | |
711 | request_.set_kana_modifier_insensitive_conversion(true); | |
712 | config_set_use_kana_modifier_insensitive_conversion(true); | |
713 | system_dic->LookupPredictive(kKey, convreq_, &callback); | |
679 | 714 | EXPECT_TOKENS_EQ_UNORDERED(tokens, callback.tokens()); |
680 | 715 | } |
681 | 716 | |
682 | 717 | TEST_F(SystemDictionaryTest, LookupPredictive_CutOffEmulatingBFS) { |
683 | 718 | vector<Token *> tokens; |
684 | ScopedElementsDeleter<vector<Token *> > deleter(&tokens); | |
719 | ScopedElementsDeleter<vector<Token *>> deleter(&tokens); | |
685 | 720 | |
686 | 721 | // "あい" -> "ai" |
687 | 722 | tokens.push_back(CreateToken("\xe3\x81\x82\xe3\x81\x84", "ai")); |
705 | 740 | // mechanism. However, "あい" is looked up as it's short. |
706 | 741 | CheckMultiTokensExistenceCallback callback(tokens); |
707 | 742 | system_dic->LookupPredictive("\xe3\x81\x82", // "あ" |
708 | false, &callback); | |
743 | convreq_, &callback); | |
709 | 744 | EXPECT_TRUE(callback.IsFound(tokens[0])); |
710 | 745 | EXPECT_FALSE(callback.IsFound(tokens[1])); |
711 | 746 | } |
733 | 768 | |
734 | 769 | // |t0| should not be looked up from |k1|. |
735 | 770 | CheckTokenExistenceCallback callback0(t0.get()); |
736 | system_dic->LookupExact(k1, &callback0); | |
771 | system_dic->LookupExact(k1, convreq_, &callback0); | |
737 | 772 | EXPECT_FALSE(callback0.found()); |
738 | 773 | // But |t1| should be found. |
739 | 774 | CheckTokenExistenceCallback callback1(t1.get()); |
740 | system_dic->LookupExact(k1, &callback1); | |
775 | system_dic->LookupExact(k1, convreq_, &callback1); | |
741 | 776 | EXPECT_TRUE(callback1.found()); |
742 | 777 | |
743 | 778 | // Nothing should be found from "hoge". |
744 | 779 | CollectTokenCallback callback_hoge; |
745 | system_dic->LookupExact("hoge", &callback_hoge); | |
780 | system_dic->LookupExact("hoge", convreq_, &callback_hoge); | |
746 | 781 | EXPECT_TRUE(callback_hoge.tokens().empty()); |
747 | 782 | } |
748 | 783 | |
847 | 882 | for (size_t source_index = 0; source_index < test_size; ++source_index) { |
848 | 883 | const Token &source_token = *source_tokens[source_index]; |
849 | 884 | CollectTokenCallback callback; |
850 | system_dic->LookupReverse(source_token.value, &callback); | |
885 | system_dic->LookupReverse(source_token.value, convreq_, &callback); | |
851 | 886 | const vector<Token> &tokens = callback.tokens(); |
852 | 887 | |
853 | 888 | bool found = false; |
886 | 921 | // append "が" |
887 | 922 | const string key = t7->value + "\xe3\x81\x8c"; |
888 | 923 | CollectTokenCallback callback; |
889 | system_dic->LookupReverse(key, &callback); | |
924 | system_dic->LookupReverse(key, convreq_, &callback); | |
890 | 925 | const vector<Token> &tokens = callback.tokens(); |
891 | 926 | bool found = false; |
892 | 927 | for (size_t i = 0; i < tokens.size(); ++i) { |
922 | 957 | size > 0 && it != source_tokens.end(); ++it, --size) { |
923 | 958 | const Token &t = **it; |
924 | 959 | CollectTokenCallback callback1, callback2; |
925 | system_dic_without_index->LookupReverse(t.value, &callback1); | |
926 | system_dic_with_index->LookupReverse(t.value, &callback2); | |
960 | system_dic_without_index->LookupReverse(t.value, convreq_, &callback1); | |
961 | system_dic_with_index->LookupReverse(t.value, convreq_, &callback2); | |
927 | 962 | |
928 | 963 | const vector<Token> &tokens1 = callback1.tokens(); |
929 | 964 | const vector<Token> &tokens2 = callback2.tokens(); |
961 | 996 | << "Failed to open dictionary source:" << dic_fn_; |
962 | 997 | system_dic->PopulateReverseLookupCache(kDoraemon); |
963 | 998 | CheckTokenExistenceCallback callback(&target_token); |
964 | system_dic->LookupReverse(kDoraemon, &callback); | |
999 | system_dic->LookupReverse(kDoraemon, convreq_, &callback); | |
965 | 1000 | EXPECT_TRUE(callback.found()) |
966 | 1001 | << "Could not find " << PrintToken(source_token); |
967 | 1002 | system_dic->ClearReverseLookupCache(); |
1014 | 1049 | |
1015 | 1050 | for (size_t i = 0; i < source_tokens.size(); ++i) { |
1016 | 1051 | CheckTokenExistenceCallback callback(source_tokens[i]); |
1017 | system_dic->LookupPrefix(source_tokens[i]->key, false, &callback); | |
1052 | system_dic->LookupPrefix(source_tokens[i]->key, convreq_, &callback); | |
1018 | 1053 | EXPECT_TRUE(callback.found()) |
1019 | 1054 | << "Token " << i << " was not found: " << PrintToken(*source_tokens[i]); |
1020 | 1055 | } |
1051 | 1086 | ASSERT_TRUE(system_dic.get() != NULL) |
1052 | 1087 | << "Failed to open dictionary source:" << dic_fn_; |
1053 | 1088 | |
1089 | request_.set_kana_modifier_insensitive_conversion(true); | |
1090 | config_set_use_kana_modifier_insensitive_conversion(true); | |
1091 | ||
1054 | 1092 | // Prefix search |
1055 | 1093 | for (size_t i = 0; i < arraysize(tokens); ++i) { |
1056 | 1094 | CheckTokenExistenceCallback callback(tokens[i].get()); |
1057 | 1095 | // "かつこう" -> "かつ", "かっこ", "かつこう", "かっこう" and "がっこう" |
1058 | system_dic->LookupPrefix( | |
1059 | k2, kEnableKanaModiferInsensitiveLookup, &callback); | |
1096 | system_dic->LookupPrefix(k2, convreq_, &callback); | |
1060 | 1097 | EXPECT_TRUE(callback.found()) |
1061 | 1098 | << "Token " << i << " was not found: " << PrintToken(*tokens[i]); |
1062 | 1099 | } |
1069 | 1106 | expected.push_back(tokens[i].get()); |
1070 | 1107 | } |
1071 | 1108 | CheckMultiTokensExistenceCallback callback(expected); |
1072 | system_dic->LookupPredictive( | |
1073 | k0, kEnableKanaModiferInsensitiveLookup, &callback); | |
1109 | system_dic->LookupPredictive(k0, convreq_, &callback); | |
1074 | 1110 | EXPECT_TRUE(callback.AreAllFound()); |
1075 | 1111 | } |
1076 | 1112 | { |
1080 | 1116 | expected.push_back(tokens[3].get()); |
1081 | 1117 | expected.push_back(tokens[4].get()); |
1082 | 1118 | CheckMultiTokensExistenceCallback callback(expected); |
1083 | system_dic->LookupPredictive( | |
1084 | k1, kEnableKanaModiferInsensitiveLookup, &callback); | |
1119 | system_dic->LookupPredictive(k1, convreq_, &callback); | |
1085 | 1120 | EXPECT_TRUE(callback.AreAllFound()); |
1086 | 1121 | } |
1087 | 1122 | } |
1113 | 1148 | // Lookup |t0| from "ていすていんぐ" |
1114 | 1149 | const string k = "\xe3\x81\xa6\xe3\x81\x84\xe3\x81\x99\xe3\x81\xa6" |
1115 | 1150 | "\xe3\x81\x84\xe3\x82\x93\xe3\x81\x90"; |
1151 | request_.set_kana_modifier_insensitive_conversion(true); | |
1152 | config_set_use_kana_modifier_insensitive_conversion(true); | |
1116 | 1153 | CheckTokenExistenceCallback callback(t0.get()); |
1117 | system_dic->LookupPrefix(k, kEnableKanaModiferInsensitiveLookup, | |
1118 | &callback); | |
1154 | system_dic->LookupPrefix(k, convreq_, &callback); | |
1119 | 1155 | EXPECT_TRUE(callback.found()) << "Not found: " << PrintToken(*t0); |
1120 | 1156 | } |
1121 | 1157 | |
1151 | 1187 | SystemDictionary::Builder(dic_fn_).Build()); |
1152 | 1188 | ASSERT_TRUE(system_dic.get() != NULL) |
1153 | 1189 | << "Failed to open dictionary source:" << dic_fn_; |
1190 | ||
1191 | request_.set_kana_modifier_insensitive_conversion(false); | |
1192 | config_set_use_kana_modifier_insensitive_conversion(true); | |
1154 | 1193 | |
1155 | 1194 | // Prefix search |
1156 | 1195 | { |
1164 | 1203 | not_to_be_looked_up.push_back(t4.get()); |
1165 | 1204 | for (size_t i = 0; i < to_be_looked_up.size(); ++i) { |
1166 | 1205 | CheckTokenExistenceCallback callback(to_be_looked_up[i]); |
1167 | system_dic->LookupPrefix( | |
1168 | k3, kDisableKanaModiferInsensitiveLookup, &callback); | |
1206 | system_dic->LookupPrefix(k3, convreq_, &callback); | |
1169 | 1207 | EXPECT_TRUE(callback.found()) |
1170 | 1208 | << "Token is not found: " << PrintToken(*to_be_looked_up[i]); |
1171 | 1209 | } |
1172 | 1210 | for (size_t i = 0; i < not_to_be_looked_up.size(); ++i) { |
1173 | 1211 | CheckTokenExistenceCallback callback(not_to_be_looked_up[i]); |
1174 | system_dic->LookupPrefix( | |
1175 | k3, kDisableKanaModiferInsensitiveLookup, &callback); | |
1212 | system_dic->LookupPrefix(k3, convreq_, &callback); | |
1176 | 1213 | EXPECT_FALSE(callback.found()) |
1177 | 1214 | << "Token should not be found: " |
1178 | 1215 | << PrintToken(*not_to_be_looked_up[i]); |
1191 | 1228 | not_to_be_looked_up.push_back(t4.get()); |
1192 | 1229 | for (size_t i = 0; i < to_be_looked_up.size(); ++i) { |
1193 | 1230 | CheckTokenExistenceCallback callback(to_be_looked_up[i]); |
1194 | system_dic->LookupPredictive( | |
1195 | k1, kDisableKanaModiferInsensitiveLookup, &callback); | |
1231 | system_dic->LookupPredictive(k1, convreq_, &callback); | |
1196 | 1232 | EXPECT_TRUE(callback.found()) |
1197 | 1233 | << "Token is not found: " << PrintToken(*to_be_looked_up[i]); |
1198 | 1234 | } |
1199 | 1235 | for (size_t i = 0; i < not_to_be_looked_up.size(); ++i) { |
1200 | 1236 | CheckTokenExistenceCallback callback(not_to_be_looked_up[i]); |
1201 | system_dic->LookupPredictive( | |
1202 | k3, kDisableKanaModiferInsensitiveLookup, &callback); | |
1237 | system_dic->LookupPredictive(k3, convreq_, &callback); | |
1203 | 1238 | EXPECT_FALSE(callback.found()) |
1204 | 1239 | << "Token should not be found: " |
1205 | 1240 | << PrintToken(*not_to_be_looked_up[i]); |
64 | 64 | ], |
65 | 65 | 'dependencies': [ |
66 | 66 | '../../base/base.gyp:base_core', |
67 | '../../config/config.gyp:config_handler', | |
67 | 68 | '../../data_manager/data_manager.gyp:user_pos_manager', |
69 | '../../request/request.gyp:conversion_request', | |
68 | 70 | '../../session/session_base.gyp:request_test_util', |
69 | 71 | '../../testing/testing.gyp:gtest_main', |
70 | 72 | '../dictionary.gyp:dictionary_test_util', |
85 | 87 | 'dependencies': [ |
86 | 88 | '../../base/base.gyp:base_core', |
87 | 89 | '../../data_manager/data_manager.gyp:user_pos_manager', |
90 | '../../request/request.gyp:conversion_request', | |
88 | 91 | '../../testing/testing.gyp:gtest_main', |
89 | 92 | '../dictionary.gyp:dictionary_test_util', |
90 | 93 | 'system_dictionary.gyp:system_dictionary_builder', |
163 | 163 | |
164 | 164 | void ValueDictionary::LookupPredictive( |
165 | 165 | StringPiece key, |
166 | bool, // use_kana_modifier_insensitive_lookup | |
166 | const ConversionRequest &conversion_request, | |
167 | 167 | Callback *callback) const { |
168 | 168 | // Do nothing for empty key, although looking up all the entries with empty |
169 | 169 | // string seems natural. |
213 | 213 | } |
214 | 214 | |
215 | 215 | void ValueDictionary::LookupPrefix( |
216 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
216 | StringPiece key, | |
217 | const ConversionRequest &conversion_request, | |
217 | 218 | Callback *callback) const {} |
218 | 219 | |
219 | void ValueDictionary::LookupExact(StringPiece key, Callback *callback) const { | |
220 | void ValueDictionary::LookupExact( | |
221 | StringPiece key, | |
222 | const ConversionRequest &conversion_request, | |
223 | Callback *callback) const { | |
220 | 224 | if (key.empty()) { |
221 | 225 | // For empty string, return nothing for compatibility reason; see the |
222 | 226 | // comment above. |
236 | 240 | callback->OnToken(key, key, token); |
237 | 241 | } |
238 | 242 | |
239 | void ValueDictionary::LookupReverse(StringPiece str, | |
240 | Callback *callback) const {} | |
243 | void ValueDictionary::LookupReverse( | |
244 | StringPiece str, | |
245 | const ConversionRequest &conversion_request, | |
246 | Callback *callback) const { | |
247 | } | |
241 | 248 | |
242 | 249 | } // namespace dictionary |
243 | 250 | } // namespace mozc |
61 | 61 | // Implementation of DictionaryInterface |
62 | 62 | virtual bool HasKey(StringPiece key) const; |
63 | 63 | virtual bool HasValue(StringPiece value) const; |
64 | virtual void LookupPredictive( | |
65 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
66 | Callback *callback) const; | |
67 | virtual void LookupPrefix( | |
68 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
69 | Callback *callback) const; | |
70 | virtual void LookupExact(StringPiece key, Callback *callback) const; | |
71 | virtual void LookupReverse(StringPiece str, Callback *callback) const; | |
64 | virtual void LookupPredictive(StringPiece key, | |
65 | const ConversionRequest &conversion_request, | |
66 | Callback *callback) const; | |
67 | virtual void LookupPrefix(StringPiece key, | |
68 | const ConversionRequest &conversion_request, | |
69 | Callback *callback) const; | |
70 | virtual void LookupExact(StringPiece key, | |
71 | const ConversionRequest &conversion_request, | |
72 | Callback *callback) const; | |
73 | virtual void LookupReverse(StringPiece str, | |
74 | const ConversionRequest &conversion_request, | |
75 | Callback *callback) const; | |
72 | 76 | |
73 | 77 | private: |
74 | 78 | explicit ValueDictionary(const POSMatcher& pos_matcher); |
40 | 40 | #include "dictionary/dictionary_token.h" |
41 | 41 | #include "dictionary/pos_matcher.h" |
42 | 42 | #include "dictionary/system/system_dictionary_builder.h" |
43 | #include "request/conversion_request.h" | |
43 | 44 | #include "testing/base/public/googletest.h" |
44 | 45 | #include "testing/base/public/gunit.h" |
45 | 46 | |
88 | 89 | |
89 | 90 | const string dict_name_; |
90 | 91 | const POSMatcher *pos_matcher_; |
92 | ConversionRequest convreq_; | |
91 | 93 | |
92 | 94 | private: |
93 | 95 | vector<Token *> tokens_; |
146 | 148 | |
147 | 149 | { |
148 | 150 | CollectTokenCallback callback; |
149 | dictionary->LookupPredictive("", false, &callback); | |
151 | dictionary->LookupPredictive("", convreq_, &callback); | |
150 | 152 | EXPECT_TRUE(callback.tokens().empty()); |
151 | 153 | } |
152 | 154 | { |
153 | 155 | CollectTokenCallback callback; |
154 | dictionary->LookupPredictive("w", false, &callback); | |
156 | dictionary->LookupPredictive("w", convreq_, &callback); | |
155 | 157 | vector<Token *> expected; |
156 | 158 | expected.push_back(&token_we); |
157 | 159 | expected.push_back(&token_war); |
161 | 163 | } |
162 | 164 | { |
163 | 165 | CollectTokenCallback callback; |
164 | dictionary->LookupPredictive("wo", false, &callback); | |
166 | dictionary->LookupPredictive("wo", convreq_, &callback); | |
165 | 167 | vector<Token *> expected; |
166 | 168 | expected.push_back(&token_word); |
167 | 169 | expected.push_back(&token_world); |
169 | 171 | } |
170 | 172 | { |
171 | 173 | CollectTokenCallback callback; |
172 | dictionary->LookupPredictive("ho", false, &callback); | |
174 | dictionary->LookupPredictive("ho", convreq_, &callback); | |
173 | 175 | EXPECT_TRUE(callback.tokens().empty()); |
174 | 176 | } |
175 | 177 | } |
187 | 189 | ValueDictionary::CreateValueDictionaryFromFile(*pos_matcher_, |
188 | 190 | dict_name_)); |
189 | 191 | CollectTokenCallback callback; |
190 | dictionary->LookupExact("war", &callback); | |
192 | dictionary->LookupExact("war", convreq_, &callback); | |
191 | 193 | ASSERT_EQ(1, callback.tokens().size()); |
192 | 194 | EXPECT_EQ("war", callback.tokens()[0].value); |
193 | 195 | } |
42 | 42 | #include "base/stl_util.h" |
43 | 43 | #include "base/thread.h" |
44 | 44 | #include "base/util.h" |
45 | #include "config/config_handler.h" | |
46 | 45 | #include "dictionary/dictionary_token.h" |
47 | 46 | #include "dictionary/pos_matcher.h" |
48 | 47 | #include "dictionary/suppression_dictionary.h" |
309 | 308 | |
310 | 309 | void UserDictionary::LookupPredictive( |
311 | 310 | StringPiece key, |
312 | bool, // use_kana_modifier_insensitive_lookup | |
311 | const ConversionRequest &conversion_request, | |
313 | 312 | Callback *callback) const { |
314 | 313 | scoped_reader_lock l(mutex_.get()); |
315 | 314 | |
320 | 319 | if (tokens_->empty()) { |
321 | 320 | return; |
322 | 321 | } |
323 | if (GET_CONFIG(incognito_mode)) { | |
322 | if (conversion_request.config().incognito_mode()) { | |
324 | 323 | return; |
325 | 324 | } |
326 | 325 | |
358 | 357 | |
359 | 358 | // UserDictionary doesn't support kana modifier insensitive lookup. |
360 | 359 | void UserDictionary::LookupPrefix( |
361 | StringPiece key, bool /*use_kana_modifier_insensitive_lookup*/, | |
360 | StringPiece key, | |
361 | const ConversionRequest &conversion_request, | |
362 | 362 | Callback *callback) const { |
363 | 363 | scoped_reader_lock l(mutex_.get()); |
364 | 364 | |
369 | 369 | if (tokens_->empty()) { |
370 | 370 | return; |
371 | 371 | } |
372 | if (GET_CONFIG(incognito_mode)) { | |
372 | if (conversion_request.config().incognito_mode()) { | |
373 | 373 | return; |
374 | 374 | } |
375 | 375 | |
414 | 414 | } |
415 | 415 | } |
416 | 416 | |
417 | void UserDictionary::LookupExact(StringPiece key, Callback *callback) const { | |
417 | void UserDictionary::LookupExact( | |
418 | StringPiece key, | |
419 | const ConversionRequest &conversion_request, | |
420 | Callback *callback) const { | |
418 | 421 | scoped_reader_lock l(mutex_.get()); |
419 | if (key.empty() || tokens_->empty() || GET_CONFIG(incognito_mode)) { | |
422 | if (key.empty() || tokens_->empty() || | |
423 | conversion_request.config().incognito_mode()) { | |
420 | 424 | return; |
421 | 425 | } |
422 | 426 | UserPOS::Token key_token; |
444 | 448 | } |
445 | 449 | } |
446 | 450 | |
447 | void UserDictionary::LookupReverse(StringPiece str, | |
448 | Callback *callback) const { | |
449 | if (GET_CONFIG(incognito_mode)) { | |
450 | return; | |
451 | } | |
451 | void UserDictionary::LookupReverse( | |
452 | StringPiece key, | |
453 | const ConversionRequest &conversion_request, | |
454 | Callback *callback) const { | |
452 | 455 | } |
453 | 456 | |
454 | 457 | bool UserDictionary::LookupComment(StringPiece key, StringPiece value, |
458 | const ConversionRequest &conversion_request, | |
455 | 459 | string *comment) const { |
456 | if (key.empty() || GET_CONFIG(incognito_mode)) { | |
460 | if (key.empty() || conversion_request.config().incognito_mode()) { | |
457 | 461 | return false; |
458 | 462 | } |
459 | 463 | |
519 | 523 | |
520 | 524 | bool UserDictionary::AddToAutoRegisteredDictionary( |
521 | 525 | const string &key, const string &value, |
526 | const ConversionRequest &conversion_request, | |
522 | 527 | user_dictionary::UserDictionary::PosType pos) { |
523 | 528 | if (reloader_->IsRunning()) { |
524 | 529 | return false; |
525 | 530 | } |
526 | 531 | |
527 | 532 | FindValueCallback callback(value); |
528 | LookupExact(key, &callback); | |
533 | LookupExact(key, conversion_request, &callback); | |
529 | 534 | if (callback.found()) { |
530 | 535 | // Already registered. |
531 | 536 | return false; |
58 | 58 | virtual bool HasValue(StringPiece value) const; |
59 | 59 | // Lookup methods don't support kana modifier insensitive lookup, i.e., |
60 | 60 | // Callback::OnActualKey() is never called. |
61 | virtual void LookupPredictive( | |
62 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
63 | Callback *callback) const; | |
64 | virtual void LookupPrefix( | |
65 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
66 | Callback *callback) const; | |
67 | virtual void LookupExact(StringPiece key, Callback *callback) const; | |
68 | virtual void LookupReverse(StringPiece str, Callback *callback) const; | |
61 | virtual void LookupPredictive(StringPiece key, | |
62 | const ConversionRequest &conversion_request, | |
63 | Callback *callback) const; | |
64 | ||
65 | virtual void LookupPrefix(StringPiece key, | |
66 | const ConversionRequest &conversion_request, | |
67 | Callback *callback) const; | |
68 | ||
69 | virtual void LookupExact(StringPiece key, | |
70 | const ConversionRequest &conversion_request, | |
71 | Callback *callback) const; | |
72 | ||
73 | virtual void LookupReverse(StringPiece str, | |
74 | const ConversionRequest &conversion_request, | |
75 | Callback *callback) const; | |
69 | 76 | |
70 | 77 | // Looks up a user comment from a pair of key and value. When (key, value) |
71 | 78 | // doesn't exist in this dictionary or user comment is empty, bool is |
72 | 79 | // returned and string is kept as-is. |
73 | 80 | virtual bool LookupComment(StringPiece key, StringPiece value, |
81 | const ConversionRequest &conversion_request, | |
74 | 82 | string *comment) const; |
75 | 83 | |
76 | 84 | // Loads dictionary from UserDictionaryStorage. |
91 | 99 | // is executed synchronously with user input. |
92 | 100 | bool AddToAutoRegisteredDictionary( |
93 | 101 | const string &key, const string &value, |
102 | const ConversionRequest &conversion_request, | |
94 | 103 | user_dictionary::UserDictionary::PosType pos); |
95 | 104 | |
96 | 105 | // Sets user dicitonary filename for unittesting |
44 | 44 | } |
45 | 45 | |
46 | 46 | virtual void LookupPredictive( |
47 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
47 | StringPiece key, | |
48 | const ConversionRequest &conversion_request, | |
48 | 49 | Callback *callback) const {} |
49 | 50 | |
50 | 51 | virtual void LookupPrefix( |
51 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
52 | StringPiece key, | |
53 | const ConversionRequest &conversion_request, | |
52 | 54 | Callback *callback) const {} |
53 | 55 | |
54 | virtual void LookupExact(StringPiece key, Callback *callback) const {} | |
56 | virtual void LookupExact( | |
57 | StringPiece key, | |
58 | const ConversionRequest &conversion_request, | |
59 | Callback *callback) const {} | |
55 | 60 | |
56 | virtual void LookupReverse(StringPiece str, Callback *callback) const {} | |
61 | virtual void LookupReverse( | |
62 | StringPiece str, | |
63 | const ConversionRequest &conversion_request, | |
64 | Callback *callback) const {} | |
57 | 65 | |
58 | virtual bool LookupComment(StringPiece key, StringPiece value, | |
59 | string *comment) const { | |
66 | virtual bool LookupComment( | |
67 | StringPiece key, | |
68 | StringPiece value, | |
69 | const ConversionRequest &conversion_request, | |
70 | string *comment) const { | |
60 | 71 | if (key == "comment" || value == "comment") { |
61 | 72 | comment->assign("UserDictionaryStub"); |
62 | 73 | return true; |
52 | 52 | #include "dictionary/user_pos.h" |
53 | 53 | #include "dictionary/user_pos_interface.h" |
54 | 54 | #include "protocol/config.pb.h" |
55 | #include "request/conversion_request.h" | |
55 | 56 | #include "testing/base/public/googletest.h" |
56 | 57 | #include "testing/base/public/gunit.h" |
57 | 58 | #include "usage_stats/usage_stats.h" |
188 | 189 | return result; |
189 | 190 | } |
190 | 191 | |
192 | // This function will be removed soon in the following change, which | |
193 | // enables to inject config to ConversionRequest. | |
194 | void config_set_incognito_mode(bool is_enabled) { | |
195 | config::Config config; | |
196 | config::ConfigHandler::GetDefaultConfig(&config); | |
197 | config.set_incognito_mode(is_enabled); | |
198 | config::ConfigHandler::SetConfig(config); | |
199 | } | |
200 | ||
191 | 201 | class UserDictionaryTest : public ::testing::Test { |
192 | 202 | protected: |
193 | 203 | virtual void SetUp() { |
195 | 205 | suppression_dictionary_.reset(new SuppressionDictionary); |
196 | 206 | |
197 | 207 | mozc::usage_stats::UsageStats::ClearAllStatsForTest(); |
208 | ||
209 | // This config initialization will be removed once ConversionRequest can | |
210 | // take config as an injected argument. | |
211 | config::Config config; | |
212 | config::ConfigHandler::GetDefaultConfig(&config); | |
213 | config::ConfigHandler::SetConfig(config); | |
198 | 214 | } |
199 | 215 | |
200 | 216 | virtual void TearDown() { |
201 | 217 | mozc::usage_stats::UsageStats::ClearAllStatsForTest(); |
218 | ||
219 | // This config initialization will be removed once ConversionRequest can | |
220 | // take config as an injected argument. | |
221 | config::Config config; | |
222 | config::ConfigHandler::GetDefaultConfig(&config); | |
223 | config::ConfigHandler::SetConfig(config); | |
202 | 224 | } |
203 | 225 | |
204 | 226 | // Workaround for the constructor of UserDictionary being protected. |
248 | 270 | vector<Entry> entries_; |
249 | 271 | }; |
250 | 272 | |
251 | static void TestLookupPredictiveHelper(const Entry *expected, | |
252 | size_t expected_size, | |
253 | StringPiece key, | |
254 | const UserDictionary &dic) { | |
273 | void TestLookupPredictiveHelper(const Entry *expected, | |
274 | size_t expected_size, | |
275 | StringPiece key, | |
276 | const UserDictionary &dic) { | |
255 | 277 | EntryCollector collector; |
256 | dic.LookupPredictive(key, false, &collector); | |
278 | dic.LookupPredictive(key, convreq_, &collector); | |
257 | 279 | |
258 | 280 | if (expected == NULL || expected_size == 0) { |
259 | 281 | EXPECT_TRUE(collector.entries().empty()); |
263 | 285 | } |
264 | 286 | } |
265 | 287 | |
266 | static void TestLookupPrefixHelper(const Entry *expected, | |
267 | size_t expected_size, | |
268 | const char *key, | |
269 | size_t key_size, | |
270 | const UserDictionary &dic) { | |
288 | void TestLookupPrefixHelper(const Entry *expected, | |
289 | size_t expected_size, | |
290 | const char *key, | |
291 | size_t key_size, | |
292 | const UserDictionary &dic) { | |
271 | 293 | EntryCollector collector; |
272 | dic.LookupPrefix(StringPiece(key, key_size), false, &collector); | |
294 | dic.LookupPrefix(StringPiece(key, key_size), convreq_, &collector); | |
273 | 295 | |
274 | 296 | if (expected == NULL || expected_size == 0) { |
275 | 297 | EXPECT_TRUE(collector.entries().empty()); |
279 | 301 | } |
280 | 302 | } |
281 | 303 | |
282 | static void TestLookupExactHelper(const Entry *expected, | |
283 | size_t expected_size, | |
284 | const char *key, | |
285 | size_t key_size, | |
286 | const UserDictionary &dic) { | |
304 | void TestLookupExactHelper(const Entry *expected, | |
305 | size_t expected_size, | |
306 | const char *key, | |
307 | size_t key_size, | |
308 | const UserDictionary &dic) { | |
287 | 309 | EntryCollector collector; |
288 | dic.LookupExact(StringPiece(key, key_size), &collector); | |
310 | dic.LookupExact(StringPiece(key, key_size), convreq_, &collector); | |
289 | 311 | |
290 | 312 | if (expected == NULL || expected_size == 0) { |
291 | 313 | EXPECT_TRUE(collector.entries().empty()); |
355 | 377 | } |
356 | 378 | |
357 | 379 | // Helper function to lookup comment string from |dic|. |
358 | static string LookupComment(const UserDictionary& dic, | |
359 | StringPiece key, StringPiece value) { | |
380 | string LookupComment(const UserDictionary& dic, | |
381 | StringPiece key, StringPiece value) { | |
360 | 382 | string comment; |
361 | dic.LookupComment(key, value, &comment); | |
383 | dic.LookupComment(key, value, convreq_, &comment); | |
362 | 384 | return comment; |
363 | 385 | } |
364 | 386 | |
365 | 387 | unique_ptr<SuppressionDictionary> suppression_dictionary_; |
388 | ConversionRequest convreq_; | |
366 | 389 | |
367 | 390 | private: |
368 | 391 | mozc::usage_stats::scoped_usage_stats_enabler usage_stats_enabler_; |
559 | 582 | } |
560 | 583 | |
561 | 584 | TEST_F(UserDictionaryTest, IncognitoModeTest) { |
562 | config::Config config; | |
563 | config::ConfigHandler::GetConfig(&config); | |
564 | config.set_incognito_mode(true); | |
565 | config::ConfigHandler::SetConfig(config); | |
566 | ||
585 | config_set_incognito_mode(true); | |
567 | 586 | unique_ptr<UserDictionary> dic(CreateDictionaryWithMockPos()); |
568 | 587 | // Wait for async reload called from the constructor. |
569 | 588 | dic->WaitForReloader(); |
577 | 596 | TestLookupPrefixHelper(NULL, 0, "start", 4, *dic); |
578 | 597 | TestLookupPredictiveHelper(NULL, 0, "s", *dic); |
579 | 598 | |
580 | config.set_incognito_mode(false); | |
581 | config::ConfigHandler::SetConfig(config); | |
582 | ||
599 | config_set_incognito_mode(false); | |
583 | 600 | { |
584 | 601 | EntryCollector collector; |
585 | dic->LookupPrefix("start", false, &collector); | |
602 | dic->LookupPrefix("start", convreq_, &collector); | |
586 | 603 | EXPECT_FALSE(collector.entries().empty()); |
587 | 604 | } |
588 | 605 | { |
589 | 606 | EntryCollector collector; |
590 | dic->LookupPredictive("s", false, &collector); | |
607 | dic->LookupPredictive("s", convreq_, &collector); | |
591 | 608 | EXPECT_FALSE(collector.entries().empty()); |
592 | 609 | } |
593 | 610 | } |
633 | 650 | dic->Reload(); |
634 | 651 | for (int i = 0; i < 1000; ++i) { |
635 | 652 | CollectTokenCallback callback; |
636 | dic->LookupPrefix(keys[i], false, &callback); | |
653 | dic->LookupPrefix(keys[i], convreq_, &callback); | |
637 | 654 | } |
638 | 655 | } |
639 | 656 | dic->WaitForReloader(); |
664 | 681 | EXPECT_TRUE(dic->AddToAutoRegisteredDictionary( |
665 | 682 | "key" + NumberUtil::SimpleItoa(i), |
666 | 683 | "value" + NumberUtil::SimpleItoa(i), |
684 | convreq_, | |
667 | 685 | user_dictionary::UserDictionary::NOUN)); |
668 | 686 | dic->WaitForReloader(); |
669 | 687 | } |
703 | 721 | dic->WaitForReloader(); |
704 | 722 | dic->SetUserDictionaryName(filename); |
705 | 723 | EXPECT_TRUE(dic->AddToAutoRegisteredDictionary( |
706 | "key", "value", user_dictionary::UserDictionary::NOUN)); | |
724 | "key", "value", convreq_, user_dictionary::UserDictionary::NOUN)); | |
707 | 725 | dic->WaitForReloader(); |
708 | 726 | // Duplicated one is not registered. |
709 | 727 | EXPECT_FALSE(dic->AddToAutoRegisteredDictionary( |
710 | "key", "value", user_dictionary::UserDictionary::NOUN)); | |
728 | "key", "value", convreq_, user_dictionary::UserDictionary::NOUN)); | |
711 | 729 | dic->WaitForReloader(); |
712 | 730 | } |
713 | 731 | |
844 | 862 | { |
845 | 863 | const char kKey[] = "key0123"; |
846 | 864 | CollectTokenCallback callback; |
847 | user_dic->LookupPrefix(kKey, false, &callback); | |
865 | user_dic->LookupPrefix(kKey, convreq_, &callback); | |
848 | 866 | const vector<Token> &tokens = callback.tokens(); |
849 | 867 | for (size_t i = 0; i < tokens.size(); ++i) { |
850 | 868 | EXPECT_EQ("default", tokens[i].value); |
853 | 871 | { |
854 | 872 | const char kKey[] = "key"; |
855 | 873 | CollectTokenCallback callback; |
856 | user_dic->LookupPredictive(kKey, false, &callback); | |
874 | user_dic->LookupPredictive(kKey, convreq_, &callback); | |
857 | 875 | const vector<Token> &tokens = callback.tokens(); |
858 | 876 | for (size_t i = 0; i < tokens.size(); ++i) { |
859 | 877 | EXPECT_TRUE(tokens[i].value == "suggest_only" || |
924 | 942 | // Entry is in user dictionary but has no comment. |
925 | 943 | string comment; |
926 | 944 | comment = "prev comment"; |
927 | EXPECT_FALSE(dic->LookupComment("comment_key1", "comment_value2", &comment)); | |
945 | EXPECT_FALSE(dic->LookupComment( | |
946 | "comment_key1", "comment_value2", convreq_, &comment)); | |
928 | 947 | EXPECT_EQ("prev comment", comment); |
929 | 948 | |
930 | 949 | // Usual case: single key-value pair with comment. |
931 | EXPECT_TRUE(dic->LookupComment("comment_key2", "comment_value2", &comment)); | |
950 | EXPECT_TRUE(dic->LookupComment( | |
951 | "comment_key2", "comment_value2", convreq_, &comment)); | |
932 | 952 | EXPECT_EQ("comment", comment); |
933 | 953 | |
934 | 954 | // There exist two entries having the same key, value and POS. Since POS is |
935 | 955 | // irrelevant to comment lookup, the first nonempty comment should be found. |
936 | EXPECT_TRUE(dic->LookupComment("comment_key3", "comment_value3", &comment)); | |
956 | EXPECT_TRUE(dic->LookupComment( | |
957 | "comment_key3", "comment_value3", convreq_, &comment)); | |
937 | 958 | EXPECT_EQ("comment1", comment); |
938 | 959 | |
939 | 960 | // White-space only comments should be cleared. |
940 | EXPECT_FALSE(dic->LookupComment("comment_key4", "comment_value4", &comment)); | |
961 | EXPECT_FALSE(dic->LookupComment( | |
962 | "comment_key4", "comment_value4", convreq_, &comment)); | |
941 | 963 | // The previous comment should remain. |
942 | 964 | EXPECT_EQ("comment1", comment); |
943 | 965 |
0 | 0 | MAJOR=2 |
1 | 1 | MINOR=17 |
2 | BUILD=2229 | |
2 | BUILD=2230 | |
3 | 3 | REVISION=102 |
4 | 4 | # NACL_DICTIONARY_VERSION is the target version of the system dictionary to be |
5 | 5 | # downloaded by NaCl Mozc. |
44 | 44 | #include "base/number_util.h" |
45 | 45 | #include "base/util.h" |
46 | 46 | #include "composer/composer.h" |
47 | #include "config/config_handler.h" | |
48 | 47 | #include "converter/connector.h" |
49 | 48 | #include "converter/converter_interface.h" |
50 | 49 | #include "converter/immutable_converter_interface.h" |
140 | 139 | return request.mixed_conversion() || FLAGS_enable_mixed_conversion; |
141 | 140 | } |
142 | 141 | |
143 | bool IsTypingCorrectionEnabled() { | |
144 | return GET_CONFIG(use_typing_correction) || | |
142 | bool IsTypingCorrectionEnabled(const ConversionRequest &request) { | |
143 | return request.config().use_typing_correction() || | |
145 | 144 | FLAGS_enable_typing_correction; |
146 | 145 | } |
147 | 146 | |
1439 | 1438 | vector<Result> *results) const { |
1440 | 1439 | // Check that history_key/history_value are in the dictionary. |
1441 | 1440 | FindValueCallback find_history_callback(history_value); |
1442 | dictionary_->LookupPrefix(history_key, false, &find_history_callback); | |
1441 | dictionary_->LookupPrefix(history_key, request, &find_history_callback); | |
1443 | 1442 | |
1444 | 1443 | // History value is not found in the dictionary. |
1445 | 1444 | // User may create this the history candidate from T13N or segment |
1476 | 1475 | history_value_size - 1, 1)); |
1477 | 1476 | for (size_t i = prev_results_size; i < results->size(); ++i) { |
1478 | 1477 | CheckBigramResult(find_history_callback.token(), history_ctype, |
1479 | last_history_ctype, &(*results)[i]); | |
1478 | last_history_ctype, request, &(*results)[i]); | |
1480 | 1479 | } |
1481 | 1480 | } |
1482 | 1481 | |
1486 | 1485 | const Token &history_token, |
1487 | 1486 | const Util::ScriptType history_ctype, |
1488 | 1487 | const Util::ScriptType last_history_ctype, |
1488 | const ConversionRequest &request, | |
1489 | 1489 | Result *result) const { |
1490 | 1490 | DCHECK(result); |
1491 | 1491 | |
1547 | 1547 | } |
1548 | 1548 | |
1549 | 1549 | FindValueCallback callback(value); |
1550 | dictionary_->LookupPrefix(key, false, &callback); | |
1550 | dictionary_->LookupPrefix(key, request, &callback); | |
1551 | 1551 | if (!callback.found()) { |
1552 | 1552 | result->types = NO_PREDICTION; |
1553 | 1553 | return; |
1570 | 1570 | const bool is_zero_query = query_key.empty(); |
1571 | 1571 | PredictiveLookupCallback callback(types, lookup_limit, input_key.size(), |
1572 | 1572 | NULL, is_zero_query, results); |
1573 | dictionary.LookupPredictive(input_key, false, &callback); | |
1573 | dictionary.LookupPredictive(input_key, request, &callback); | |
1574 | 1574 | return; |
1575 | 1575 | } |
1576 | 1576 | |
1588 | 1588 | PredictiveLookupCallback callback( |
1589 | 1589 | types, lookup_limit, input_key.size(), |
1590 | 1590 | expanded.empty() ? NULL : &expanded, is_zero_query, results); |
1591 | dictionary.LookupPredictive( | |
1592 | input_key, request.IsKanaModifierInsensitiveConversion(), &callback); | |
1591 | dictionary.LookupPredictive(input_key, request, &callback); | |
1593 | 1592 | } |
1594 | 1593 | |
1595 | 1594 | void DictionaryPredictor::GetPredictiveResultsForBigram( |
1610 | 1609 | PredictiveBigramLookupCallback callback( |
1611 | 1610 | types, lookup_limit, input_key.size(), NULL, history_value, |
1612 | 1611 | is_zero_query, results); |
1613 | dictionary.LookupPredictive(input_key, false, &callback); | |
1612 | dictionary.LookupPredictive(input_key, request, &callback); | |
1614 | 1613 | return; |
1615 | 1614 | } |
1616 | 1615 | |
1629 | 1628 | expanded.empty() ? NULL : &expanded, |
1630 | 1629 | history_value, is_zero_query, |
1631 | 1630 | results); |
1632 | dictionary.LookupPredictive( | |
1633 | input_key, request.IsKanaModifierInsensitiveConversion(), &callback); | |
1631 | dictionary.LookupPredictive(input_key, request, &callback); | |
1634 | 1632 | } |
1635 | 1633 | |
1636 | 1634 | void DictionaryPredictor::GetPredictiveResultsForEnglish( |
1661 | 1659 | Util::LowerString(&key); |
1662 | 1660 | PredictiveLookupCallback callback(types, lookup_limit, key.size(), NULL, |
1663 | 1661 | false, results); |
1664 | dictionary.LookupPredictive(key, false, &callback); | |
1662 | dictionary.LookupPredictive(key, request, &callback); | |
1665 | 1663 | for (size_t i = prev_results_size; i < results->size(); ++i) { |
1666 | 1664 | Util::UpperString(&results->at(i).value); |
1667 | 1665 | } |
1672 | 1670 | Util::LowerString(&key); |
1673 | 1671 | PredictiveLookupCallback callback(types, lookup_limit, key.size(), NULL, |
1674 | 1672 | false, results); |
1675 | dictionary.LookupPredictive(key, false, &callback); | |
1673 | dictionary.LookupPredictive(key, request, &callback); | |
1676 | 1674 | for (size_t i = prev_results_size; i < results->size(); ++i) { |
1677 | 1675 | Util::CapitalizeString(&results->at(i).value); |
1678 | 1676 | } |
1680 | 1678 | // For other cases (lower and as-is), just look up directly. |
1681 | 1679 | PredictiveLookupCallback callback(types, lookup_limit, input_key.size(), |
1682 | 1680 | NULL, false, results); |
1683 | dictionary.LookupPredictive(input_key, false, &callback); | |
1681 | dictionary.LookupPredictive(input_key, request, &callback); | |
1684 | 1682 | } |
1685 | 1683 | // If input mode is FULL_ASCII, then convert the results to full-width. |
1686 | 1684 | if (request.composer().GetInputMode() == transliteration::FULL_ASCII) { |
1713 | 1711 | PredictiveLookupCallback callback( |
1714 | 1712 | types, lookup_limit, input_key.size(), |
1715 | 1713 | query.expanded.empty() ? NULL : &query.expanded, false, results); |
1716 | dictionary.LookupPredictive( | |
1717 | input_key, request.IsKanaModifierInsensitiveConversion(), &callback); | |
1714 | dictionary.LookupPredictive(input_key, request, &callback); | |
1718 | 1715 | |
1719 | 1716 | for (size_t i = previous_results_size; i < results->size(); ++i) { |
1720 | 1717 | results->at(i).wcost += query.cost; |
1962 | 1959 | |
1963 | 1960 | const bool zero_query_suggestion = request.request().zero_query_suggestion(); |
1964 | 1961 | if (IsLatinInputMode(request) && !zero_query_suggestion) { |
1965 | if (GET_CONFIG(use_dictionary_suggest)) { | |
1962 | if (request.config().use_dictionary_suggest()) { | |
1966 | 1963 | // By following the dictionary_suggest config, enable English prediction. |
1967 | 1964 | result |= ENGLISH; |
1968 | 1965 | } |
1972 | 1969 | return result; |
1973 | 1970 | } |
1974 | 1971 | |
1975 | if (!GET_CONFIG(use_dictionary_suggest) && | |
1972 | if (!request.config().use_dictionary_suggest() && | |
1976 | 1973 | segments.request_type() == Segments::SUGGESTION) { |
1977 | 1974 | VLOG(2) << "no_dictionary_suggest"; |
1978 | 1975 | return result; |
2022 | 2019 | result |= SUFFIX; |
2023 | 2020 | } |
2024 | 2021 | |
2025 | if (IsTypingCorrectionEnabled() && key_len >= 3) { | |
2022 | if (IsTypingCorrectionEnabled(request) && key_len >= 3) { | |
2026 | 2023 | result |= TYPING_CORRECTION; |
2027 | 2024 | } |
2028 | 2025 | |
2041 | 2038 | } |
2042 | 2039 | |
2043 | 2040 | return (segments.request_type() == Segments::PARTIAL_SUGGESTION || |
2044 | GET_CONFIG(use_realtime_conversion) || | |
2041 | request.config().use_realtime_conversion() || | |
2045 | 2042 | IsMixedConversionEnabled(request.request())); |
2046 | 2043 | } |
2047 | 2044 |
273 | 273 | void CheckBigramResult(const dictionary::Token &history_token, |
274 | 274 | const Util::ScriptType history_ctype, |
275 | 275 | const Util::ScriptType last_history_ctype, |
276 | const ConversionRequest &request, | |
276 | 277 | Result *result) const; |
277 | 278 | |
278 | 279 | void GetPredictiveResults(const dictionary::DictionaryInterface &dictionary, |
305 | 305 | bool(StringPiece)); |
306 | 306 | MOCK_CONST_METHOD3(LookupPredictive, |
307 | 307 | void(StringPiece key, |
308 | bool use_kana_modifier_insensitive_lookup, | |
308 | const ConversionRequest& convreq, | |
309 | 309 | Callback *callback)); |
310 | 310 | MOCK_CONST_METHOD3(LookupPrefix, |
311 | 311 | void(StringPiece key, |
312 | bool use_kana_modifier_insensitive_lookup, | |
312 | const ConversionRequest& convreq, | |
313 | 313 | Callback *callback)); |
314 | MOCK_CONST_METHOD2(LookupExact, | |
315 | void(StringPiece key, Callback *callback)); | |
316 | MOCK_CONST_METHOD2(LookupReverse, | |
317 | void(StringPiece str, Callback *callback)); | |
314 | MOCK_CONST_METHOD3(LookupExact, | |
315 | void(StringPiece key, | |
316 | const ConversionRequest& convreq, | |
317 | Callback *callback)); | |
318 | MOCK_CONST_METHOD3(LookupReverse, | |
319 | void(StringPiece str, | |
320 | const ConversionRequest& convreq, | |
321 | Callback *callback)); | |
318 | 322 | }; |
319 | 323 | |
320 | 324 | // Action to call the third argument of LookupPrefix with the token |
629 | 633 | composer.GetQueryForPrediction(&query); |
630 | 634 | segment->set_key(query); |
631 | 635 | |
632 | EXPECT_CALL(*check_dictionary, LookupPredictive(_, use_expansion, _)); | |
636 | EXPECT_CALL(*check_dictionary, | |
637 | LookupPredictive(_, ::testing::Ref(conversion_request), _)); | |
633 | 638 | |
634 | 639 | vector<TestableDictionaryPredictor::Result> results; |
635 | 640 | predictor->AggregateUnigramPrediction( |
687 | 692 | segment->set_key(query); |
688 | 693 | |
689 | 694 | // History key and value should be in the dictionary. |
690 | EXPECT_CALL(*check_dictionary, LookupPrefix(_, _, _)) | |
695 | EXPECT_CALL(*check_dictionary, | |
696 | LookupPrefix(_, ::testing::Ref(conversion_request), _)) | |
691 | 697 | .WillOnce(LookupPrefixOneToken( |
692 | 698 | // "ぐーぐる" |
693 | 699 | "\xe3\x81\x90\xe3\x83\xbc\xe3\x81\x90\xe3\x82\x8b", |
694 | 700 | // "グーグル" |
695 | 701 | "\xe3\x82\xb0\xe3\x83\xbc\xe3\x82\xb0\xe3\x83\xab", |
696 | 702 | 1, 1)); |
697 | EXPECT_CALL(*check_dictionary, LookupPredictive(_, use_expansion, _)); | |
703 | EXPECT_CALL(*check_dictionary, | |
704 | LookupPredictive(_, ::testing::Ref(conversion_request), _)); | |
698 | 705 | |
699 | 706 | vector<TestableDictionaryPredictor::Result> results; |
700 | 707 | predictor->AggregateBigramPrediction( |
735 | 742 | composer.GetQueryForPrediction(&query); |
736 | 743 | segment->set_key(query); |
737 | 744 | |
738 | EXPECT_CALL(*check_dictionary, LookupPredictive(_, use_expansion, _)); | |
745 | EXPECT_CALL(*check_dictionary, | |
746 | LookupPredictive(_, ::testing::Ref(conversion_request), _)); | |
739 | 747 | |
740 | 748 | vector<TestableDictionaryPredictor::Result> results; |
741 | 749 | predictor->AggregateSuffixPrediction( |
1773 | 1781 | |
1774 | 1782 | virtual void LookupPredictive( |
1775 | 1783 | StringPiece key, |
1776 | bool use_kana_modifier_insensitive_lookup, | |
1784 | const ConversionRequest &conversion_request, | |
1777 | 1785 | Callback *callback) const { |
1778 | 1786 | Token token; |
1779 | 1787 | for (size_t i = 0; i < arraysize(kSuffixTokens); ++i) { |
1804 | 1812 | } |
1805 | 1813 | |
1806 | 1814 | virtual void LookupPrefix( |
1807 | StringPiece key, bool use_kana_modifier_insensitive_lookup, | |
1815 | StringPiece key, | |
1816 | const ConversionRequest &conversion_request, | |
1808 | 1817 | Callback *callback) const {} |
1809 | 1818 | |
1810 | virtual void LookupExact(StringPiece key, Callback *callback) const {} | |
1811 | ||
1812 | virtual void LookupReverse(StringPiece str, Callback *callback) const {} | |
1819 | virtual void LookupExact(StringPiece key, | |
1820 | const ConversionRequest &conversion_request, | |
1821 | Callback *callback) const {} | |
1822 | ||
1823 | virtual void LookupReverse(StringPiece str, | |
1824 | const ConversionRequest &conversion_request, | |
1825 | Callback *callback) const {} | |
1813 | 1826 | }; |
1814 | 1827 | |
1815 | 1828 | } // namespace |
71 | 71 | return *request_; |
72 | 72 | } |
73 | 73 | |
74 | void ConversionRequest::set_request(const commands::Request *request) { | |
75 | request_ = request; | |
76 | } | |
77 | ||
74 | 78 | const config::Config &ConversionRequest::config() const { |
75 | 79 | return config::ConfigHandler::GetConfig(); |
76 | 80 | } |
91 | 91 | void set_composer_key_selection(ComposerKeySelection selection); |
92 | 92 | |
93 | 93 | const commands::Request &request() const; |
94 | void set_request(const commands::Request *request); | |
94 | 95 | |
95 | 96 | const config::Config &config() const; |
96 | 97 |
192 | 192 | if (dictionary_ != NULL) { |
193 | 193 | if (dictionary_->LookupComment(segment->candidate(j).content_key, |
194 | 194 | segment->candidate(j).content_value, |
195 | request, | |
195 | 196 | &comment)) { |
196 | 197 | Segment::Candidate *candidate = segment->mutable_candidate(j); |
197 | 198 | candidate->usage_id = usage_id_for_user_comment; |