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