| // Copyright 2010-2015, Google Inc. |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| // This is a client and session test with fixed sequence of key events. It is |
| // similar test with session_stress_test_main, but senario test uses fixed key |
| // events specified by FLAGS_input file or interactive standard input. Input |
| // file format is same as one of session/session_client_main. |
| |
| #include <iostream> |
| #include <string> |
| #include <vector> |
| |
| #include "base/file_stream.h" |
| #include "base/file_util.h" |
| #include "base/logging.h" |
| #include "base/port.h" |
| #include "base/system_util.h" |
| #include "base/util.h" |
| #include "client/client.h" |
| #include "renderer/renderer_command.pb.h" |
| #include "renderer/renderer_client.h" |
| #include "session/commands.pb.h" |
| #include "session/key_parser.h" |
| |
| DEFINE_bool(display_preedit, false, "display predit to tty"); |
| DEFINE_string(input, "", "Input file"); |
| DEFINE_int32(key_duration, 10, "Key duration (msec)"); |
| DEFINE_string(profile_dir, "", "Profile dir"); |
| DEFINE_bool(sentence_mode, false, "Use input as sentences"); |
| DEFINE_string(server_path, "", "Specify server path"); |
| DEFINE_bool(test_renderer, false, "Test renderer"); |
| DEFINE_bool(test_testsendkey, true, "Test TestSendKey"); |
| |
| namespace mozc { |
| namespace { |
| |
| string UTF8ToTtyString(const string &text) { |
| #ifdef OS_WIN |
| string tmp; |
| Util::UTF8ToSJIS(text, &tmp); |
| return tmp; |
| #else |
| return text; |
| #endif |
| } |
| |
| void DisplayPreedit(const commands::Output &output) { |
| if (output.has_preedit()) { |
| string value; |
| for (size_t i = 0; i < output.preedit().segment_size(); ++i) { |
| value += output.preedit().segment(i).value(); |
| } |
| cout << UTF8ToTtyString(value) << '\r'; |
| } else if (output.has_result()) { |
| cout << UTF8ToTtyString(output.result().value()) << endl; |
| } |
| } |
| |
| // Parses key events. If |input| gets EOF, returns false. |
| bool ReadKeys(istream *input, |
| vector<commands::KeyEvent> *keys, |
| string *answer) { |
| keys->clear(); |
| answer->clear(); |
| |
| string line; |
| while (getline(*input, line)) { |
| Util::ChopReturns(&line); |
| if (line.size() > 1 && line[0] == '#' && line[1] == '#') { |
| continue; |
| } |
| if (line.find(">> ") == 0) { |
| // Answer line |
| answer->assign(line, 3, line.size() - 3); |
| continue; |
| } |
| if (line.empty()) { |
| return true; |
| } |
| commands::KeyEvent key; |
| if (!KeyParser::ParseKey(line, &key)) { |
| LOG(ERROR) << "cannot parse: " << line; |
| continue; |
| } |
| keys->push_back(key); |
| } |
| return false; |
| } |
| |
| int Loop(istream *input) { |
| mozc::client::Client client; |
| if (!FLAGS_server_path.empty()) { |
| client.set_server_program(FLAGS_server_path); |
| } |
| |
| CHECK(client.IsValidRunLevel()) << "IsValidRunLevel failed"; |
| CHECK(client.EnsureSession()) << "EnsureSession failed"; |
| CHECK(client.NoOperation()) << "Server is not responding"; |
| |
| scoped_ptr<mozc::renderer::RendererClient> renderer_client; |
| mozc::commands::RendererCommand renderer_command; |
| |
| if (FLAGS_test_renderer) { |
| #if defined(OS_WIN) || defined(OS_MACOSX) |
| #ifdef OS_WIN |
| renderer_command.mutable_application_info()->set_process_id |
| (::GetCurrentProcessId()); |
| renderer_command.mutable_application_info()->set_thread_id |
| (::GetCurrentThreadId()); |
| #endif |
| renderer_command.mutable_preedit_rectangle()->set_left(10); |
| renderer_command.mutable_preedit_rectangle()->set_top(10); |
| renderer_command.mutable_preedit_rectangle()->set_right(200); |
| renderer_command.mutable_preedit_rectangle()->set_bottom(30); |
| #else |
| LOG(FATAL) << "test_renderer is only supported on Windows and Mac"; |
| #endif |
| renderer_client.reset(new renderer::RendererClient); |
| CHECK(renderer_client->Activate()); |
| } |
| |
| commands::Command command; |
| commands::Output output; |
| vector<commands::KeyEvent> keys; |
| string answer; |
| |
| // TODO(tok): Stop the test if server is crashed. Currently, we cannot |
| // detect the server crash out of client library, as client automatically |
| // re-launches the server. See also session_stress_test_main.cc. |
| |
| while (ReadKeys(input, &keys, &answer)) { |
| CHECK(client.NoOperation()) << "Server is not responding"; |
| for (size_t i = 0; i < keys.size(); ++i) { |
| Util::Sleep(FLAGS_key_duration); |
| |
| if (FLAGS_test_testsendkey) { |
| VLOG(2) << "Sending to Server: " << keys[i].DebugString(); |
| client.TestSendKey(keys[i], &output); |
| VLOG(2) << "Output of TestSendKey: " << output.DebugString(); |
| Util::Sleep(10); |
| } |
| |
| VLOG(2) << "Sending to Server: " << keys[i].DebugString(); |
| client.SendKey(keys[i], &output); |
| VLOG(2) << "Output of SendKey: " << output.DebugString(); |
| |
| if (renderer_client.get() != NULL) { |
| renderer_command.set_type(commands::RendererCommand::UPDATE); |
| renderer_command.set_visible(output.has_candidates()); |
| renderer_command.mutable_output()->CopyFrom(output); |
| VLOG(2) << "Sending to Renderer: " << renderer_command.DebugString(); |
| renderer_client->ExecCommand(renderer_command); |
| } |
| |
| if (FLAGS_display_preedit) { |
| mozc::DisplayPreedit(output); |
| } |
| } |
| if (!answer.empty() && (output.result().value() != answer)) { |
| LOG(ERROR) << "wrong value: " << output.result().value() |
| << " (expected: " << answer << ")"; |
| } |
| } |
| |
| return 0; |
| } |
| |
| } // namespace |
| } // namespace mozc |
| |
| int main(int argc, char **argv) { |
| InitGoogle(argv[0], &argc, &argv, false); |
| |
| if (!FLAGS_profile_dir.empty()) { |
| mozc::FileUtil::CreateDirectory(FLAGS_profile_dir); |
| mozc::SystemUtil::SetUserProfileDirectory(FLAGS_profile_dir); |
| } |
| |
| scoped_ptr<mozc::InputFileStream> input_file; |
| istream *input = NULL; |
| |
| if (!FLAGS_input.empty()) { |
| // Batch mode loading the input file. |
| input_file.reset(new mozc::InputFileStream(FLAGS_input.c_str())); |
| if (input_file->fail()) { |
| LOG(ERROR) << "File not opened: " << FLAGS_input; |
| return 1; |
| } |
| input = input_file.get(); |
| } else { |
| // Interaction mode. |
| input = &cin; |
| } |
| |
| return mozc::Loop(input); |
| } |