blob: 8e3a4915f5b8c4bf6286fb84ba15639a55f53cb1 [file] [log] [blame]
// 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.
#include "converter/segments.h"
#include <string>
#include <vector>
#include "base/number_util.h"
#include "base/system_util.h"
#include "base/util.h"
#include "config/config.pb.h"
#include "config/config_handler.h"
#include "testing/base/public/gunit.h"
DECLARE_string(test_tmpdir);
namespace mozc {
class SegmentsTest : public testing::Test {
protected:
virtual void SetUp() {
SystemUtil::SetUserProfileDirectory(FLAGS_test_tmpdir);
config::ConfigHandler::GetDefaultConfig(&default_config_);
config::ConfigHandler::SetConfig(default_config_);
}
virtual void TearDown() {
config::ConfigHandler::SetConfig(default_config_);
}
private:
config::Config default_config_;
};
class CandidateTest : public testing::Test {
protected:
virtual void SetUp() {
SystemUtil::SetUserProfileDirectory(FLAGS_test_tmpdir);
config::ConfigHandler::GetDefaultConfig(&default_config_);
config::ConfigHandler::SetConfig(default_config_);
}
private:
config::Config default_config_;
};
class SegmentTest : public testing::Test {
protected:
virtual void SetUp() {
SystemUtil::SetUserProfileDirectory(FLAGS_test_tmpdir);
config::ConfigHandler::GetDefaultConfig(&default_config_);
config::ConfigHandler::SetConfig(default_config_);
}
virtual void TearDown() {
config::ConfigHandler::SetConfig(default_config_);
}
private:
config::Config default_config_;
};
TEST_F(SegmentsTest, BasicTest) {
Segments segments;
// flags
segments.set_request_type(Segments::CONVERSION);
EXPECT_EQ(Segments::CONVERSION, segments.request_type());
segments.set_request_type(Segments::SUGGESTION);
EXPECT_EQ(Segments::SUGGESTION, segments.request_type());
segments.set_user_history_enabled(true);
EXPECT_TRUE(segments.user_history_enabled());
segments.set_user_history_enabled(false);
EXPECT_FALSE(segments.user_history_enabled());
EXPECT_EQ(0, segments.segments_size());
const int kSegmentsSize = 5;
Segment *seg[kSegmentsSize];
for (int i = 0; i < kSegmentsSize; ++i) {
EXPECT_EQ(i, segments.segments_size());
seg[i] = segments.push_back_segment();
EXPECT_EQ(i + 1, segments.segments_size());
}
const string output = segments.DebugString();
EXPECT_FALSE(output.empty());
EXPECT_FALSE(segments.resized());
segments.set_resized(true);
EXPECT_TRUE(segments.resized());
segments.set_resized(false);
EXPECT_FALSE(segments.resized());
segments.set_max_history_segments_size(10);
EXPECT_EQ(10, segments.max_history_segments_size());
segments.set_max_history_segments_size(5);
EXPECT_EQ(5, segments.max_history_segments_size());
segments.set_max_prediction_candidates_size(10);
EXPECT_EQ(10, segments.max_prediction_candidates_size());
segments.set_max_prediction_candidates_size(5);
EXPECT_EQ(5, segments.max_prediction_candidates_size());
for (int i = 0; i < kSegmentsSize; ++i) {
EXPECT_EQ(seg[i], segments.mutable_segment(i));
}
segments.pop_back_segment();
EXPECT_EQ(seg[3], segments.mutable_segment(3));
segments.pop_front_segment();
EXPECT_EQ(seg[1], segments.mutable_segment(0));
segments.Clear();
EXPECT_EQ(0, segments.segments_size());
for (int i = 0; i < kSegmentsSize; ++i) {
seg[i] = segments.push_back_segment();
}
// erase
segments.erase_segment(1);
EXPECT_EQ(seg[0], segments.mutable_segment(0));
EXPECT_EQ(seg[2], segments.mutable_segment(1));
segments.erase_segments(1, 2);
EXPECT_EQ(seg[0], segments.mutable_segment(0));
EXPECT_EQ(seg[4], segments.mutable_segment(1));
EXPECT_EQ(2, segments.segments_size());
segments.erase_segments(0, 1);
EXPECT_EQ(1, segments.segments_size());
EXPECT_EQ(seg[4], segments.mutable_segment(0));
// insert
seg[1] = segments.insert_segment(1);
EXPECT_EQ(seg[1], segments.mutable_segment(1));
segments.Clear();
for (int i = 0; i < kSegmentsSize; ++i) {
seg[i] = segments.push_back_segment();
if (i < 2) {
seg[i]->set_segment_type(Segment::HISTORY);
}
}
// history/conversion
for (int i = 0; i < 3; ++i) {
EXPECT_EQ(segments.mutable_segment(i + segments.history_segments_size()),
segments.mutable_conversion_segment(i));
}
EXPECT_EQ(2, segments.history_segments_size());
EXPECT_EQ(3, segments.conversion_segments_size());
EXPECT_EQ(seg[2], segments.mutable_conversion_segment(0));
EXPECT_EQ(seg[0], segments.mutable_history_segment(0));
segments.clear_history_segments();
EXPECT_EQ(3, segments.segments_size());
segments.clear_conversion_segments();
EXPECT_EQ(0, segments.segments_size());
}
TEST_F(CandidateTest, BasicTest) {
Segment segment;
const char str[] = "this is a test";
segment.set_key(str);
EXPECT_EQ(segment.key(), str);
segment.set_segment_type(Segment::FIXED_BOUNDARY);
EXPECT_EQ(Segment::FIXED_BOUNDARY, segment.segment_type());
const int kCandidatesSize = 5;
Segment::Candidate *cand[kCandidatesSize];
for (int i = 0; i < kCandidatesSize; ++i) {
EXPECT_EQ(i, segment.candidates_size());
cand[i] = segment.push_back_candidate();
EXPECT_EQ(i + 1, segment.candidates_size());
}
for (int i = 0; i < kCandidatesSize; ++i) {
EXPECT_EQ(cand[i], segment.mutable_candidate(i));
}
for (int i = 0; i < kCandidatesSize; ++i) {
EXPECT_EQ(i, segment.indexOf(segment.mutable_candidate(i)));
}
for (int i = -static_cast<int>(segment.meta_candidates_size()) - 1;
i >= 0; ++i) {
EXPECT_EQ(i, segment.indexOf(segment.mutable_candidate(i)));
}
EXPECT_EQ(segment.candidates_size(),
segment.indexOf(NULL));
segment.pop_back_candidate();
EXPECT_EQ(cand[3], segment.mutable_candidate(3));
segment.pop_front_candidate();
EXPECT_EQ(cand[1], segment.mutable_candidate(0));
segment.Clear();
EXPECT_EQ(0, segment.candidates_size());
for (int i = 0; i < kCandidatesSize; ++i) {
cand[i] = segment.push_back_candidate();
}
// erase
segment.erase_candidate(1);
EXPECT_EQ(cand[0], segment.mutable_candidate(0));
EXPECT_EQ(cand[2], segment.mutable_candidate(1));
segment.erase_candidates(1, 2);
EXPECT_EQ(cand[0], segment.mutable_candidate(0));
EXPECT_EQ(cand[4], segment.mutable_candidate(1));
EXPECT_EQ(2, segment.candidates_size());
// insert
cand[1] = segment.insert_candidate(1);
EXPECT_EQ(cand[1], segment.mutable_candidate(1));
EXPECT_EQ(cand[4], segment.mutable_candidate(2));
// move
segment.Clear();
for (int i = 0; i < kCandidatesSize; ++i) {
cand[i] = segment.push_back_candidate();
}
segment.move_candidate(2, 0);
EXPECT_EQ(cand[2], segment.mutable_candidate(0));
EXPECT_EQ(cand[0], segment.mutable_candidate(1));
EXPECT_EQ(cand[1], segment.mutable_candidate(2));
}
TEST_F(CandidateTest, CopyFrom) {
Segment::Candidate src, dest;
src.Init();
src.key = "key";
src.value = "value";
src.content_key = "content_key";
src.content_value = "content_value";
src.prefix = "prefix";
src.suffix = "suffix";
src.description = "description";
src.usage_title = "usage_title";
src.usage_description = "usage_description";
src.cost = 1;
src.wcost = 2;
src.structure_cost = 3;
src.lid = 4;
src.rid = 5;
src.attributes = 6;
src.style = NumberUtil::NumberString::NUMBER_CIRCLED;
src.command = Segment::Candidate::DISABLE_PRESENTATION_MODE;
src.PushBackInnerSegmentBoundary(1, 3, 5, 7);
dest.CopyFrom(src);
EXPECT_EQ(src.key, dest.key);
EXPECT_EQ(src.value, dest.value);
EXPECT_EQ(src.content_key, dest.content_key);
EXPECT_EQ(src.content_value, dest.content_value);
EXPECT_EQ(src.prefix, dest.prefix);
EXPECT_EQ(src.suffix, dest.suffix);
EXPECT_EQ(src.description, dest.description);
EXPECT_EQ(src.usage_title, dest.usage_title);
EXPECT_EQ(src.usage_description, dest.usage_description);
EXPECT_EQ(src.cost, dest.cost);
EXPECT_EQ(src.wcost, dest.wcost);
EXPECT_EQ(src.structure_cost, dest.structure_cost);
EXPECT_EQ(src.lid, dest.lid);
EXPECT_EQ(src.rid, dest.rid);
EXPECT_EQ(src.attributes, dest.attributes);
EXPECT_EQ(src.style, dest.style);
EXPECT_EQ(src.command, dest.command);
EXPECT_EQ(src.inner_segment_boundary, dest.inner_segment_boundary);
}
TEST_F(CandidateTest, IsValid) {
Segment::Candidate c;
c.Init();
EXPECT_TRUE(c.IsValid());
c.key = "key";
c.value = "value";
c.content_key = "content_key";
c.content_value = "content_value";
c.prefix = "prefix";
c.suffix = "suffix";
c.description = "description";
c.usage_title = "usage_title";
c.usage_description = "usage_description";
c.cost = 1;
c.wcost = 2;
c.structure_cost = 3;
c.lid = 4;
c.rid = 5;
c.attributes = 6;
c.style = NumberUtil::NumberString::NUMBER_CIRCLED;
c.command = Segment::Candidate::DISABLE_PRESENTATION_MODE;
EXPECT_TRUE(c.IsValid()); // Empty inner_segment_boundary
// Valid inner_segment_boundary.
c.inner_segment_boundary.push_back(
Segment::Candidate::EncodeLengths(1, 3, 8, 8));
c.inner_segment_boundary.push_back(
Segment::Candidate::EncodeLengths(2, 2, 3, 5));
EXPECT_TRUE(c.IsValid());
// Invalid inner_segment_boundary.
c.inner_segment_boundary.clear();
c.inner_segment_boundary.push_back(
Segment::Candidate::EncodeLengths(1, 1, 2, 2));
c.inner_segment_boundary.push_back(
Segment::Candidate::EncodeLengths(2, 2, 3, 3));
c.inner_segment_boundary.push_back(
Segment::Candidate::EncodeLengths(3, 3, 4, 4));
EXPECT_FALSE(c.IsValid());
}
TEST_F(SegmentsTest, RevertEntryTest) {
Segments segments;
EXPECT_EQ(0, segments.revert_entries_size());
const int kSize = 10;
for (int i = 0; i < kSize; ++i) {
Segments::RevertEntry *e = segments.push_back_revert_entry();
e->key = "test" + NumberUtil::SimpleItoa(i);
e->id = i;
}
EXPECT_EQ(kSize, segments.revert_entries_size());
for (int i = 0; i < kSize; ++i) {
{
const Segments::RevertEntry &e = segments.revert_entry(i);
EXPECT_EQ(string("test") + NumberUtil::SimpleItoa(i), e.key);
EXPECT_EQ(i, e.id);
}
{
Segments::RevertEntry *e = segments.mutable_revert_entry(i);
EXPECT_EQ(string("test") + NumberUtil::SimpleItoa(i), e->key);
EXPECT_EQ(i, e->id);
}
}
for (int i = 0; i < kSize; ++i) {
Segments::RevertEntry *e = segments.mutable_revert_entry(i);
e->id = kSize - i;
e->key = "test2" + NumberUtil::SimpleItoa(i);
}
for (int i = 0; i < kSize; ++i) {
const Segments::RevertEntry &e = segments.revert_entry(i);
EXPECT_EQ(string("test2") + NumberUtil::SimpleItoa(i), e.key);
EXPECT_EQ(kSize - i, e.id);
}
{
const Segments::RevertEntry &src = segments.revert_entry(0);
Segments::RevertEntry dest;
dest.CopyFrom(src);
EXPECT_EQ(src.revert_entry_type, dest.revert_entry_type);
EXPECT_EQ(src.id, dest.id);
EXPECT_EQ(src.timestamp, dest.timestamp);
EXPECT_EQ(src.key, dest.key);
}
segments.clear_revert_entries();
EXPECT_EQ(0, segments.revert_entries_size());
}
TEST_F(SegmentsTest, CopyFromTest) {
Segments src;
src.set_max_history_segments_size(1);
src.set_max_prediction_candidates_size(2);
src.set_max_conversion_candidates_size(2);
src.set_resized(true);
src.set_user_history_enabled(true);
src.set_request_type(Segments::PREDICTION);
const int kSegmentsSize = 3;
const int kCandidatesSize = 2;
for (int i = 0; i < kSegmentsSize; ++i) {
Segment *segment = src.add_segment();
segment->set_key(Util::StringPrintf("segment_%d", i));
for (int j = 0; j < kCandidatesSize; ++j) {
Segment::Candidate *candidate = segment->add_candidate();
candidate->key = Util::StringPrintf("candidate_%d", i);
}
}
EXPECT_EQ(kSegmentsSize, src.segments_size());
EXPECT_EQ(kCandidatesSize, src.segment(0).candidates_size());
Segments dest;
dest.CopyFrom(src);
EXPECT_EQ(src.max_history_segments_size(), dest.max_history_segments_size());
EXPECT_EQ(src.max_prediction_candidates_size(),
dest.max_prediction_candidates_size());
EXPECT_EQ(src.max_conversion_candidates_size(),
dest.max_conversion_candidates_size());
EXPECT_EQ(src.resized(), dest.resized());
EXPECT_EQ(src.user_history_enabled(), dest.user_history_enabled());
EXPECT_EQ(src.request_type(), dest.request_type());
EXPECT_EQ(kSegmentsSize, dest.segments_size());
EXPECT_EQ(kCandidatesSize, dest.segment(0).candidates_size());
for (int i = 0; i < kSegmentsSize; ++i) {
EXPECT_EQ(src.segment(i).key(), dest.segment(i).key());
for (int j = 0; j < kCandidatesSize; ++j) {
EXPECT_EQ(src.segment(i).candidate(j).key,
dest.segment(i).candidate(j).key);
}
}
}
TEST_F(CandidateTest, functional_key) {
Segment::Candidate candidate;
candidate.Init();
candidate.key = "testfoobar";
candidate.content_key = "test";
EXPECT_EQ("foobar", candidate.functional_key());
candidate.key = "testfoo";
candidate.content_key = "test";
EXPECT_EQ("foo", candidate.functional_key());
// This is unexpected key/context_key.
// This method doesn't check the prefix part.
candidate.key = "abcdefg";
candidate.content_key = "test";
EXPECT_EQ("efg", candidate.functional_key());
candidate.key = "test";
candidate.content_key = "test";
EXPECT_EQ("", candidate.functional_key());
candidate.key = "test";
candidate.content_key = "testfoobar";
EXPECT_EQ("", candidate.functional_key());
candidate.key = "";
candidate.content_key = "";
EXPECT_EQ("", candidate.functional_key());
}
TEST_F(CandidateTest, functional_value) {
Segment::Candidate candidate;
candidate.Init();
candidate.value = "testfoobar";
candidate.content_value = "test";
EXPECT_EQ("foobar", candidate.functional_value());
candidate.value = "testfoo";
candidate.content_value = "test";
EXPECT_EQ("foo", candidate.functional_value());
// This is unexpected value/context_value.
// This method doesn't check the prefix part.
candidate.value = "abcdefg";
candidate.content_value = "test";
EXPECT_EQ("efg", candidate.functional_value());
candidate.value = "test";
candidate.content_value = "test";
EXPECT_EQ("", candidate.functional_value());
candidate.value = "test";
candidate.content_value = "testfoobar";
EXPECT_EQ("", candidate.functional_value());
candidate.value = "";
candidate.content_value = "";
EXPECT_EQ("", candidate.functional_value());
}
TEST_F(CandidateTest, InnerSegmentIterator) {
{
// For empty inner_segment_boundary, the initial state is done.
Segment::Candidate candidate;
candidate.Init();
candidate.key = "testfoobar";
candidate.value = "redgreenblue";
Segment::Candidate::InnerSegmentIterator iter(&candidate);
EXPECT_TRUE(iter.Done());
}
{
// key: test | foobar
// value: red | greenblue
// content key: test | foo
// content value: red | green
Segment::Candidate candidate;
candidate.Init();
candidate.key = "testfoobar";
candidate.value = "redgreenblue";
candidate.PushBackInnerSegmentBoundary(4, 3, 4, 3);
candidate.PushBackInnerSegmentBoundary(6, 9, 3, 5);
vector<StringPiece> keys, values, content_keys, content_values;
for (Segment::Candidate::InnerSegmentIterator iter(&candidate);
!iter.Done(); iter.Next()) {
keys.push_back(iter.GetKey());
values.push_back(iter.GetValue());
content_keys.push_back(iter.GetContentKey());
content_values.push_back(iter.GetContentValue());
}
ASSERT_EQ(2, keys.size());
EXPECT_EQ("test", keys[0]);
EXPECT_EQ("foobar", keys[1]);
ASSERT_EQ(2, values.size());
EXPECT_EQ("red", values[0]);
EXPECT_EQ("greenblue", values[1]);
ASSERT_EQ(2, content_keys.size());
EXPECT_EQ("test", content_keys[0]);
EXPECT_EQ("foo", content_keys[1]);
ASSERT_EQ(2, content_values.size());
EXPECT_EQ("red", content_values[0]);
EXPECT_EQ("green", content_values[1]);
}
}
TEST_F(SegmentTest, CopyFrom) {
Segment src, dest;
src.set_key("key");
src.set_segment_type(Segment::FIXED_VALUE);
Segment::Candidate *candidate1 = src.add_candidate();
candidate1->key = "candidate1->key";
Segment::Candidate *candidate2 = src.add_candidate();
candidate2->key = "candidate2->key";
Segment::Candidate *meta_candidate = src.add_meta_candidate();
meta_candidate->key = "meta_candidate->key";
dest.CopyFrom(src);
EXPECT_EQ(src.key(), dest.key());
EXPECT_EQ(src.segment_type(), dest.segment_type());
EXPECT_EQ(src.candidate(0).key, dest.candidate(0).key);
EXPECT_EQ(src.candidate(1).key, dest.candidate(1).key);
EXPECT_EQ(src.meta_candidate(0).key, dest.meta_candidate(0).key);
}
TEST_F(SegmentTest, MetaCandidateTest) {
Segment segment;
EXPECT_EQ(0, segment.meta_candidates_size());
const int kCandidatesSize = 5;
vector<string> values;
for (size_t i = 0; i < kCandidatesSize; ++i) {
values.push_back(string('a' + i, 1));
}
// add_meta_candidate()
for (size_t i = 0; i < kCandidatesSize; ++i) {
EXPECT_EQ(i, segment.meta_candidates_size());
Segment::Candidate *cand = segment.add_meta_candidate();
cand->value = values[i];
EXPECT_EQ(i + 1, segment.meta_candidates_size());
}
// mutable_candidate()
for (size_t i = 0; i < kCandidatesSize; ++i) {
const int meta_idx = -static_cast<int>(i)-1;
Segment::Candidate *cand = segment.mutable_candidate(meta_idx);
EXPECT_EQ(values[i], cand->value);
}
// mutable_meta_candidate()
for (size_t i = 0; i < kCandidatesSize; ++i) {
Segment::Candidate *cand = segment.mutable_meta_candidate(i);
EXPECT_EQ(values[i], cand->value);
}
// candidate()
for (size_t i = 0; i < kCandidatesSize; ++i) {
const int meta_idx = -static_cast<int>(i)-1;
const Segment::Candidate &cand = segment.candidate(meta_idx);
EXPECT_EQ(values[i], cand.value);
}
// meta_candidate()
for (size_t i = 0; i < kCandidatesSize; ++i) {
const Segment::Candidate &cand = segment.meta_candidate(i);
EXPECT_EQ(values[i], cand.value);
}
// indexOf
for (size_t i = 0; i < kCandidatesSize; ++i) {
const int meta_idx = -static_cast<int>(i)-1;
EXPECT_EQ(meta_idx, segment.indexOf(segment.mutable_candidate(meta_idx)));
}
EXPECT_EQ(segment.candidates_size(),
segment.indexOf(NULL));
// mutable_meta_candidates
{
vector<Segment::Candidate> *meta_candidates =
segment.mutable_meta_candidates();
EXPECT_EQ(kCandidatesSize, meta_candidates->size());
Segment::Candidate cand;
cand.Init();
cand.value = "Test";
meta_candidates->push_back(cand);
}
// meta_candidates
{
const vector<Segment::Candidate> &meta_candidates =
segment.meta_candidates();
EXPECT_EQ(kCandidatesSize + 1, meta_candidates.size());
for (size_t i = 0; i < kCandidatesSize; ++i) {
EXPECT_EQ(values[i], meta_candidates[i].value);
}
EXPECT_EQ("Test", meta_candidates[kCandidatesSize].value);
}
// clear
segment.clear_meta_candidates();
EXPECT_EQ(0, segment.meta_candidates_size());
}
} // namespace mozc