1 // Copyright 2010-2018, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "session/session_handler_test_util.h"
31
32 #include <utility>
33
34 #include "base/config_file_stream.h"
35 #include "base/file_util.h"
36 #include "base/logging.h"
37 #include "base/system_util.h"
38 #include "config/character_form_manager.h"
39 #include "config/config_handler.h"
40 #include "converter/converter_interface.h"
41 #include "engine/engine_interface.h"
42 #include "prediction/user_history_predictor.h"
43 #include "protocol/commands.pb.h"
44 #include "protocol/config.pb.h"
45 #include "session/session_handler.h"
46 #include "session/session_handler_interface.h"
47 #include "session/session_usage_observer.h"
48 #include "storage/registry.h"
49
50 DECLARE_string(test_tmpdir);
51
52 DECLARE_int32(max_session_size);
53 DECLARE_int32(create_session_min_interval);
54 DECLARE_int32(watch_dog_interval);
55 DECLARE_int32(last_command_timeout);
56 DECLARE_int32(last_create_session_timeout);
57 DECLARE_bool(restricted);
58
59 namespace mozc {
60 namespace session {
61 namespace testing {
62
63 using commands::Command;
64 using config::CharacterFormManager;
65 using config::ConfigHandler;
66
CreateSession(SessionHandlerInterface * handler,uint64 * id)67 bool CreateSession(SessionHandlerInterface *handler, uint64 *id) {
68 Command command;
69 command.mutable_input()->set_type(commands::Input::CREATE_SESSION);
70 command.mutable_input()->mutable_capability()->set_text_deletion(
71 commands::Capability::DELETE_PRECEDING_TEXT);
72 handler->EvalCommand(&command);
73 if (id != nullptr) {
74 *id = command.has_output() ? command.output().id() : 0;
75 }
76 return (command.output().error_code() == commands::Output::SESSION_SUCCESS);
77 }
78
DeleteSession(SessionHandlerInterface * handler,uint64 id)79 bool DeleteSession(SessionHandlerInterface *handler, uint64 id) {
80 Command command;
81 command.mutable_input()->set_id(id);
82 command.mutable_input()->set_type(commands::Input::DELETE_SESSION);
83 return handler->EvalCommand(&command);
84 }
85
CleanUp(SessionHandlerInterface * handler,uint64 id)86 bool CleanUp(SessionHandlerInterface *handler, uint64 id) {
87 Command command;
88 command.mutable_input()->set_id(id);
89 command.mutable_input()->set_type(commands::Input::CLEANUP);
90 return handler->EvalCommand(&command);
91 }
92
ClearUserPrediction(SessionHandlerInterface * handler,uint64 id)93 bool ClearUserPrediction(SessionHandlerInterface *handler, uint64 id) {
94 Command command;
95 command.mutable_input()->set_id(id);
96 command.mutable_input()->set_type(commands::Input::CLEAR_USER_PREDICTION);
97 return handler->EvalCommand(&command);
98 }
99
IsGoodSession(SessionHandlerInterface * handler,uint64 id)100 bool IsGoodSession(SessionHandlerInterface *handler, uint64 id) {
101 Command command;
102 command.mutable_input()->set_id(id);
103 command.mutable_input()->set_type(commands::Input::SEND_KEY);
104 command.mutable_input()->mutable_key()->set_special_key(
105 commands::KeyEvent::SPACE);
106 handler->EvalCommand(&command);
107 return (command.output().error_code() == commands::Output::SESSION_SUCCESS);
108 }
109
SessionHandlerTestBase()110 SessionHandlerTestBase::SessionHandlerTestBase() {
111 }
~SessionHandlerTestBase()112 SessionHandlerTestBase::~SessionHandlerTestBase() {
113 }
114
SetUp()115 void SessionHandlerTestBase::SetUp() {
116 flags_max_session_size_backup_ = FLAGS_max_session_size;
117 flags_create_session_min_interval_backup_ = FLAGS_create_session_min_interval;
118 flags_watch_dog_interval_backup_ = FLAGS_watch_dog_interval;
119 flags_last_command_timeout_backup_ = FLAGS_last_command_timeout;
120 flags_last_create_session_timeout_backup_ = FLAGS_last_create_session_timeout;
121 flags_restricted_backup_ = FLAGS_restricted;
122
123 user_profile_directory_backup_ = SystemUtil::GetUserProfileDirectory();
124 SystemUtil::SetUserProfileDirectory(FLAGS_test_tmpdir);
125 ConfigHandler::GetConfig(&config_backup_);
126 ClearState();
127 }
128
TearDown()129 void SessionHandlerTestBase::TearDown() {
130 ClearState();
131 ConfigHandler::SetConfig(config_backup_);
132 SystemUtil::SetUserProfileDirectory(user_profile_directory_backup_);
133
134 FLAGS_max_session_size = flags_max_session_size_backup_;
135 FLAGS_create_session_min_interval = flags_create_session_min_interval_backup_;
136 FLAGS_watch_dog_interval = flags_watch_dog_interval_backup_;
137 FLAGS_last_command_timeout = flags_last_command_timeout_backup_;
138 FLAGS_last_create_session_timeout = flags_last_create_session_timeout_backup_;
139 FLAGS_restricted = flags_restricted_backup_;
140 }
141
ClearState()142 void SessionHandlerTestBase::ClearState() {
143 config::Config config;
144 ConfigHandler::GetDefaultConfig(&config);
145 ConfigHandler::SetConfig(config);
146
147 // CharacterFormManager is not automatically updated when the config is
148 // updated.
149 CharacterFormManager::GetCharacterFormManager()->ReloadConfig(config);
150
151 // Some destructors may save the state on storages. To clear the state, we
152 // explicitly call destructors before clearing storages.
153 storage::Registry::Clear();
154 FileUtil::Unlink(ConfigFileStream::GetFileName("user://boundary.db"));
155 FileUtil::Unlink(ConfigFileStream::GetFileName("user://segment.db"));
156 FileUtil::Unlink(UserHistoryPredictor::GetUserHistoryFileName());
157 }
158
TestSessionClient(std::unique_ptr<EngineInterface> engine)159 TestSessionClient::TestSessionClient(std::unique_ptr<EngineInterface> engine)
160 : id_(0),
161 usage_observer_(new SessionUsageObserver),
162 handler_(new SessionHandler(std::move(engine))) {
163 handler_->AddObserver(usage_observer_.get());
164 }
165
~TestSessionClient()166 TestSessionClient::~TestSessionClient() {
167 }
168
CreateSession()169 bool TestSessionClient::CreateSession() {
170 return ::mozc::session::testing::CreateSession(handler_.get(), &id_);
171 }
172
DeleteSession()173 bool TestSessionClient::DeleteSession() {
174 return ::mozc::session::testing::DeleteSession(handler_.get(), id_);
175 }
176
CleanUp()177 bool TestSessionClient::CleanUp() {
178 return ::mozc::session::testing::CleanUp(handler_.get(), id_);
179 }
180
ClearUserPrediction()181 bool TestSessionClient::ClearUserPrediction() {
182 return ::mozc::session::testing::ClearUserPrediction(handler_.get(), id_);
183 }
184
SendKeyWithOption(const commands::KeyEvent & key,const commands::Input & option,commands::Output * output)185 bool TestSessionClient::SendKeyWithOption(const commands::KeyEvent &key,
186 const commands::Input &option,
187 commands::Output *output) {
188 commands::Input input;
189 input.set_type(commands::Input::SEND_KEY);
190 input.mutable_key()->CopyFrom(key);
191 input.MergeFrom(option);
192 return EvalCommand(&input, output);
193 }
194
TestSendKeyWithOption(const commands::KeyEvent & key,const commands::Input & option,commands::Output * output)195 bool TestSessionClient::TestSendKeyWithOption(const commands::KeyEvent &key,
196 const commands::Input &option,
197 commands::Output *output) {
198 commands::Input input;
199 input.set_type(commands::Input::TEST_SEND_KEY);
200 input.mutable_key()->CopyFrom(key);
201 input.MergeFrom(option);
202 return EvalCommand(&input, output);
203 }
204
SelectCandidate(uint32 id,commands::Output * output)205 bool TestSessionClient::SelectCandidate(uint32 id, commands::Output *output) {
206 commands::Input input;
207 input.set_type(commands::Input::SEND_COMMAND);
208 input.mutable_command()->set_type(commands::SessionCommand::SELECT_CANDIDATE);
209 input.mutable_command()->set_id(id);
210 return EvalCommand(&input, output);
211 }
212
SubmitCandidate(uint32 id,commands::Output * output)213 bool TestSessionClient::SubmitCandidate(uint32 id, commands::Output *output) {
214 commands::Input input;
215 input.set_type(commands::Input::SEND_COMMAND);
216 input.mutable_command()->set_type(commands::SessionCommand::SUBMIT_CANDIDATE);
217 input.mutable_command()->set_id(id);
218 return EvalCommand(&input, output);
219 }
220
Reload()221 bool TestSessionClient::Reload() {
222 commands::Input input;
223 input.set_type(commands::Input::RELOAD);
224 return EvalCommand(&input, nullptr);
225 }
226
ResetContext()227 bool TestSessionClient::ResetContext() {
228 commands::Input input;
229 input.set_type(commands::Input::SEND_COMMAND);
230 input.mutable_command()->set_type(commands::SessionCommand::RESET_CONTEXT);
231 return EvalCommand(&input, nullptr);
232 }
233
UndoOrRewind(commands::Output * output)234 bool TestSessionClient::UndoOrRewind(commands::Output *output) {
235 commands::Input input;
236 input.set_type(commands::Input::SEND_COMMAND);
237 input.mutable_command()->set_type(commands::SessionCommand::UNDO_OR_REWIND);
238 return EvalCommand(&input, output);
239 }
240
SwitchInputMode(commands::CompositionMode composition_mode)241 bool TestSessionClient::SwitchInputMode(
242 commands::CompositionMode composition_mode) {
243 commands::Input input;
244 input.set_type(commands::Input::SEND_COMMAND);
245 input.mutable_command()->set_type(
246 commands::SessionCommand::SWITCH_INPUT_MODE);
247 input.mutable_command()->set_composition_mode(composition_mode);
248 return EvalCommand(&input, nullptr);
249 }
250
SetRequest(const commands::Request & request,commands::Output * output)251 bool TestSessionClient::SetRequest(const commands::Request &request,
252 commands::Output *output) {
253 commands::Input input;
254 input.set_type(commands::Input::SET_REQUEST);
255 input.mutable_request()->CopyFrom(request);
256 return EvalCommand(&input, output);
257 }
258
SetConfig(const config::Config & config,commands::Output * output)259 bool TestSessionClient::SetConfig(const config::Config &config,
260 commands::Output *output) {
261 commands::Input input;
262 input.set_type(commands::Input::SET_CONFIG);
263 *input.mutable_config() = config;
264 return EvalCommand(&input, output);
265 }
266
SetCallbackText(const string & text)267 void TestSessionClient::SetCallbackText(const string &text) {
268 callback_text_ = text;
269 }
270
EvalCommandInternal(commands::Input * input,commands::Output * output,bool allow_callback)271 bool TestSessionClient::EvalCommandInternal(commands::Input *input,
272 commands::Output *output,
273 bool allow_callback) {
274 input->set_id(id_);
275 commands::Command command;
276 command.mutable_input()->CopyFrom(*input);
277 bool result = handler_->EvalCommand(&command);
278 if (result && output != nullptr) {
279 output->CopyFrom(command.output());
280 }
281
282 // If callback is allowed and the callback field exists, evaluate the callback
283 // command.
284 if (result &&
285 allow_callback &&
286 command.output().has_callback() &&
287 command.output().callback().has_session_command()) {
288 commands::Input input2;
289 input2.set_type(commands::Input::SEND_COMMAND);
290 input2.mutable_command()->CopyFrom(
291 command.output().callback().session_command());
292 input2.mutable_command()->set_text(callback_text_);
293 // Disallow further recursion.
294 result = EvalCommandInternal(&input2, output, false);
295 }
296 callback_text_.clear();
297 return result;
298 }
299
EvalCommand(commands::Input * input,commands::Output * output)300 bool TestSessionClient::EvalCommand(commands::Input *input,
301 commands::Output *output) {
302 return EvalCommandInternal(input, output, true);
303 }
304
305 } // namespace testing
306 } // namespace session
307 } // namespace mozc
308