|
@ -1,16 +1,15 @@ |
|
|
#include <algorithm> |
|
|
#include <algorithm> |
|
|
#include "md5.h" |
|
|
#include "md5.h" |
|
|
#include "group.h" |
|
|
#include "group.h" |
|
|
|
|
|
#include "type_id.h" |
|
|
|
|
|
#include "tiny_pool.h" |
|
|
#include "common_code.h" |
|
|
#include "common_code.h" |
|
|
|
|
|
#include "group_seeds.h" |
|
|
#include "gtest/gtest.h" |
|
|
#include "gtest/gtest.h" |
|
|
|
|
|
|
|
|
#include "tiny_pool.h" |
|
|
|
|
|
|
|
|
|
|
|
#include "group/type_id.h" |
|
|
|
|
|
#include "group/group_seeds.h" |
|
|
|
|
|
|
|
|
|
|
|
using klotski::Group; |
|
|
using klotski::Group; |
|
|
using klotski::TypeId; |
|
|
using klotski::TypeId; |
|
|
|
|
|
using klotski::GroupId; |
|
|
using klotski::AllCases; |
|
|
using klotski::AllCases; |
|
|
|
|
|
|
|
|
using klotski::RawCode; |
|
|
using klotski::RawCode; |
|
@ -19,44 +18,53 @@ using klotski::CommonCode; |
|
|
|
|
|
|
|
|
using klotski::GROUP_SEEDS; |
|
|
using klotski::GROUP_SEEDS; |
|
|
using klotski::TYPE_ID_SIZE; |
|
|
using klotski::TYPE_ID_SIZE; |
|
|
|
|
|
using klotski::ALL_GROUP_NUM; |
|
|
using klotski::TYPE_ID_LIMIT; |
|
|
using klotski::TYPE_ID_LIMIT; |
|
|
using klotski::SHORT_CODE_LIMIT; |
|
|
using klotski::SHORT_CODE_LIMIT; |
|
|
|
|
|
using klotski::TYPE_ID_GROUP_NUM; |
|
|
using klotski::ALL_CASES_SIZE_SUM; |
|
|
using klotski::ALL_CASES_SIZE_SUM; |
|
|
|
|
|
|
|
|
const char GROUP_INFO_MD5[] = "976bf22530085210e68a6a4e67053506"; |
|
|
const char GROUP_INFO_MD5[] = "976bf22530085210e68a6a4e67053506"; |
|
|
|
|
|
|
|
|
TEST(Group, all_cases) { |
|
|
TEST(Group, all_cases) { |
|
|
std::vector<std::vector<CommonCode>> all_cases; |
|
|
std::array<std::vector<CommonCode>, TYPE_ID_LIMIT> all_cases; |
|
|
|
|
|
auto build = [&all_cases](TypeId type_id) { |
|
|
|
|
|
auto cases = Group::all_cases(type_id); // build test data
|
|
|
|
|
|
EXPECT_EQ(cases.size(), TYPE_ID_SIZE[type_id.unwrap()]); // verify cases number
|
|
|
|
|
|
for (auto &&common_code : cases) { |
|
|
|
|
|
EXPECT_EQ(TypeId(common_code), type_id); // verify type id
|
|
|
|
|
|
} |
|
|
|
|
|
EXPECT_EQ(std::is_sorted(cases.begin(), cases.end()), true); // verify data order
|
|
|
|
|
|
all_cases[type_id.unwrap()] = cases; |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
auto pool = TinyPool(); |
|
|
for (uint32_t type_id = 0; type_id < TYPE_ID_LIMIT; ++type_id) { |
|
|
for (uint32_t type_id = 0; type_id < TYPE_ID_LIMIT; ++type_id) { |
|
|
all_cases.emplace_back(Group::all_cases(TypeId(type_id))); // build test data
|
|
|
pool.submit(build, TypeId(type_id)); |
|
|
} |
|
|
} |
|
|
|
|
|
pool.boot(); |
|
|
|
|
|
pool.join(); // wait data build complete
|
|
|
|
|
|
|
|
|
std::vector<uint64_t> combine; |
|
|
std::vector<CommonCode> combine; |
|
|
combine.reserve(ALL_CASES_SIZE_SUM); |
|
|
combine.reserve(ALL_CASES_SIZE_SUM); |
|
|
for (uint32_t id = 0; id < TYPE_ID_LIMIT; ++id) { |
|
|
for (auto &&cases : all_cases) { |
|
|
EXPECT_EQ(all_cases[id].size(), TYPE_ID_SIZE[id]); // verify cases number
|
|
|
combine.insert(combine.end(), cases.begin(), cases.end()); |
|
|
for (auto &&common_code : all_cases[id]) { |
|
|
|
|
|
EXPECT_EQ(TypeId(common_code).unwrap(), id); // verify type id
|
|
|
|
|
|
combine.emplace_back(common_code.unwrap()); |
|
|
|
|
|
} |
|
|
|
|
|
std::is_sorted(all_cases[id].begin(), all_cases[id].end()); // verify data order
|
|
|
|
|
|
} |
|
|
} |
|
|
EXPECT_EQ(combine.size(), ALL_CASES_SIZE_SUM); // verify sum
|
|
|
EXPECT_EQ(combine.size(), ALL_CASES_SIZE_SUM); // verify sum
|
|
|
|
|
|
|
|
|
auto all_cases_release = AllCases::release(); |
|
|
auto all_cases_release = AllCases::release(); |
|
|
std::stable_sort(combine.begin(), combine.end()); |
|
|
std::stable_sort(combine.begin(), combine.end()); |
|
|
for (uint32_t i = 0; i < combine.size(); ++i) { |
|
|
EXPECT_EQ(combine, all_cases_release); // verify combined cases
|
|
|
EXPECT_EQ(combine[i], all_cases_release[i]); // verify after combined
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
TEST(Group, group_cases) { |
|
|
TEST(Group, group_cases) { |
|
|
auto test = [](CommonCode seed) -> std::vector<CommonCode> { |
|
|
auto build = [](CommonCode seed) -> std::vector<CommonCode> { |
|
|
auto group_raw = Group::group_cases(RawCode::from_common_code(seed)); |
|
|
auto group_raw = Group::group_cases(seed); |
|
|
std::vector<CommonCode> group(group_raw.begin(), group_raw.end()); // convert as CommonCodes
|
|
|
std::vector<CommonCode> group(group_raw.begin(), group_raw.end()); // convert as CommonCodes
|
|
|
EXPECT_EQ(seed, std::min_element(group.begin(), group.end())->unwrap()); // confirm min seed
|
|
|
EXPECT_EQ(seed, std::min_element(group.begin(), group.end())->unwrap()); // confirm min seed
|
|
|
|
|
|
EXPECT_EQ(group.size(), Group::group_size(seed)); // verify group size
|
|
|
|
|
|
|
|
|
uint32_t type_id = TypeId(CommonCode(seed)).unwrap(); // current type id
|
|
|
uint32_t type_id = TypeId(seed).unwrap(); // current type id
|
|
|
for (auto &&elem : group) { |
|
|
for (auto &&elem : group) { |
|
|
EXPECT_EQ(TypeId(elem).unwrap(), type_id); // verify type id of group cases
|
|
|
EXPECT_EQ(TypeId(elem).unwrap(), type_id); // verify type id of group cases
|
|
|
} |
|
|
} |
|
@ -67,7 +75,7 @@ TEST(Group, group_cases) { |
|
|
std::vector<std::future<std::vector<CommonCode>>> futures; |
|
|
std::vector<std::future<std::vector<CommonCode>>> futures; |
|
|
for (auto &&seed : GROUP_SEEDS) { |
|
|
for (auto &&seed : GROUP_SEEDS) { |
|
|
futures.emplace_back( |
|
|
futures.emplace_back( |
|
|
pool.submit(test, CommonCode::unsafe_create(seed)) |
|
|
pool.submit(build, CommonCode::unsafe_create(seed)) |
|
|
); |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -75,61 +83,100 @@ TEST(Group, group_cases) { |
|
|
std::vector<CommonCode> all_cases; |
|
|
std::vector<CommonCode> all_cases; |
|
|
all_cases.reserve(ALL_CASES_SIZE_SUM); |
|
|
all_cases.reserve(ALL_CASES_SIZE_SUM); |
|
|
for (auto &&f : futures) { |
|
|
for (auto &&f : futures) { |
|
|
auto ret = f.get(); |
|
|
auto cases = f.get(); |
|
|
all_cases.insert(all_cases.end(), ret.begin(), ret.end()); |
|
|
all_cases.insert(all_cases.end(), cases.begin(), cases.end()); // combine build result
|
|
|
} |
|
|
} |
|
|
std::sort(all_cases.begin(), all_cases.end()); |
|
|
std::sort(all_cases.begin(), all_cases.end()); |
|
|
EXPECT_EQ(all_cases, AllCases::release()); // verify all released cases
|
|
|
EXPECT_EQ(all_cases, AllCases::release()); // verify all released cases
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
TEST(Group, build_group) { |
|
|
TEST(Group, group_seeds) { |
|
|
|
|
|
std::vector<CommonCode> all_seeds; |
|
|
|
|
|
all_seeds.reserve(ALL_GROUP_NUM); |
|
|
|
|
|
for (uint32_t type_id = 0; type_id < TYPE_ID_LIMIT; ++type_id) { |
|
|
|
|
|
auto seeds = Group::group_seeds(TypeId(type_id)); |
|
|
|
|
|
for (auto &&seed : seeds) { |
|
|
|
|
|
EXPECT_EQ(TypeId(seed).unwrap(), type_id); // verify type id of seeds
|
|
|
|
|
|
} |
|
|
|
|
|
all_seeds.insert(all_seeds.end(), seeds.begin(), seeds.end()); |
|
|
|
|
|
|
|
|
|
|
|
std::vector<CommonCode> sub_seeds; |
|
|
|
|
|
sub_seeds.reserve(TYPE_ID_GROUP_NUM[type_id]); |
|
|
|
|
|
for (uint32_t group_id = 0; group_id < TYPE_ID_GROUP_NUM[type_id]; ++group_id) { |
|
|
|
|
|
sub_seeds.emplace_back(Group::group_seed(GroupId(type_id, group_id))); |
|
|
|
|
|
} |
|
|
|
|
|
std::sort(seeds.begin(), seeds.end()); |
|
|
|
|
|
std::sort(sub_seeds.begin(), sub_seeds.end()); // don't verify seeds order for now
|
|
|
|
|
|
EXPECT_EQ(seeds, sub_seeds); // verify group seeds
|
|
|
|
|
|
} |
|
|
|
|
|
std::vector<CommonCode> group_seeds(GROUP_SEEDS, GROUP_SEEDS + ALL_GROUP_NUM); |
|
|
|
|
|
EXPECT_EQ(all_seeds, group_seeds); // verify group seeds
|
|
|
|
|
|
|
|
|
|
|
|
auto test = [](CommonCode seed) { |
|
|
|
|
|
EXPECT_EQ(Group::group_seed(seed), seed); // verify group seed fetch
|
|
|
|
|
|
EXPECT_EQ(Group::group_seed(seed.to_raw_code()), seed); |
|
|
|
|
|
}; |
|
|
|
|
|
auto pool = TinyPool(); |
|
|
|
|
|
for (auto &&seed : GROUP_SEEDS) { // traverse all seeds
|
|
|
|
|
|
pool.submit(test, CommonCode::unsafe_create(seed)); |
|
|
|
|
|
} |
|
|
|
|
|
pool.boot(); |
|
|
|
|
|
pool.join(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
TEST(Group, build_groups) { |
|
|
TEST(Group, build_groups) { |
|
|
struct group_info_t { |
|
|
std::vector<Group::group_info_t> all_cases(SHORT_CODE_LIMIT); |
|
|
uint16_t group_id; |
|
|
|
|
|
uint32_t group_index; |
|
|
|
|
|
}; |
|
|
|
|
|
ShortCode::speed_up(ShortCode::FAST); |
|
|
|
|
|
std::vector<group_info_t> all_cases(SHORT_CODE_LIMIT); |
|
|
|
|
|
|
|
|
|
|
|
std::vector<uint16_t> group_ids; |
|
|
auto test = [&all_cases](TypeId type_id) { |
|
|
|
|
|
auto groups = Group::build_groups(type_id); |
|
|
|
|
|
EXPECT_EQ(groups.size(), TYPE_ID_GROUP_NUM[type_id.unwrap()]); // verify groups num
|
|
|
|
|
|
|
|
|
for (uint16_t type_id = 0; type_id < klotski::TYPE_ID_LIMIT; ++type_id) { |
|
|
|
|
|
std::vector<uint32_t> group_sizes; |
|
|
std::vector<uint32_t> group_sizes; |
|
|
std::vector<CommonCode> group_seeds; |
|
|
std::map<uint32_t, std::vector<CommonCode>> group_seeds; // <group_size, group_seeds>
|
|
|
auto groups = Group::build_groups(TypeId(type_id)); |
|
|
|
|
|
group_sizes.reserve(groups.size()); |
|
|
for (uint32_t group_id = 0; group_id < groups.size(); ++group_id) { |
|
|
group_seeds.reserve(groups.size()); |
|
|
auto group = Group::build_group(GroupId(type_id, group_id)); |
|
|
|
|
|
std::sort(group.begin(), group.end()); |
|
|
for (uint32_t id = 0; id < groups.size(); ++id) { |
|
|
std::sort(groups[group_id].begin(), groups[group_id].end()); |
|
|
group_sizes.emplace_back(groups[id].size()); // record size
|
|
|
EXPECT_EQ(groups[group_id], group); // verify group data
|
|
|
std::sort(groups[id].begin(), groups[id].end()); // sort for group index
|
|
|
EXPECT_EQ(group.size(), Group::group_size(GroupId(type_id, group_id))); // verify group size
|
|
|
for (uint32_t index = 0; index < groups[id].size(); ++index) { |
|
|
EXPECT_EQ(*group.begin(), Group::group_seed(GroupId(type_id, group_id))); // verify group seed
|
|
|
all_cases[groups[id][index].to_short_code().unwrap()] = { |
|
|
|
|
|
.group_id = static_cast<uint16_t>(id), |
|
|
for (uint32_t index = 0; index < group.size(); ++index) { |
|
|
|
|
|
all_cases[group[index].to_short_code().unwrap()] = { // storage group info
|
|
|
|
|
|
.type_id = 0, |
|
|
|
|
|
.group_id = static_cast<uint16_t>(group_id), |
|
|
.group_index = index, |
|
|
.group_index = index, |
|
|
}; |
|
|
}; |
|
|
EXPECT_EQ(TypeId(groups[id][index]).unwrap(), type_id); // verify type id
|
|
|
EXPECT_EQ(TypeId(group[index]), type_id); // verify released type id
|
|
|
} |
|
|
} |
|
|
group_seeds.emplace_back(groups[id][0]); // record seed
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// TODO: check group_seeds and group_sizes
|
|
|
group_seeds[group.size()].emplace_back(*group.begin()); // storage group seeds
|
|
|
|
|
|
group_sizes.emplace_back(group.size()); // storage group size
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// TODO: verify GROUP_OFFSET
|
|
|
EXPECT_EQ(std::is_sorted(group_sizes.rbegin(), group_sizes.rend()), true); // verify group size order
|
|
|
|
|
|
for (auto &&tmp : group_seeds) { |
|
|
|
|
|
EXPECT_EQ(std::is_sorted(tmp.second.begin(), tmp.second.end()), true); // verify group cases order
|
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
auto pool = TinyPool(); |
|
|
|
|
|
ShortCode::speed_up(ShortCode::FAST); |
|
|
|
|
|
for (uint32_t type_id = 0; type_id < TYPE_ID_LIMIT; ++type_id) { |
|
|
|
|
|
pool.submit(test, TypeId(type_id)); |
|
|
} |
|
|
} |
|
|
|
|
|
pool.boot(); |
|
|
// TODO: verify GROUP_SEEDS / GROUP_SEEDS_INDEX / GROUP_SEEDS_INDEX_REV
|
|
|
pool.join(); |
|
|
|
|
|
|
|
|
char buffer[9]; |
|
|
char buffer[9]; |
|
|
std::string group_info; |
|
|
std::string group_info_str; |
|
|
for (auto &&tmp : all_cases) { |
|
|
for (auto &&tmp : all_cases) { |
|
|
sprintf(buffer, "%d,%d\n", tmp.group_id, tmp.group_index); |
|
|
sprintf(buffer, "%d,%d\n", tmp.group_id, tmp.group_index); |
|
|
group_info += buffer; |
|
|
group_info_str += buffer; |
|
|
} |
|
|
} |
|
|
auto group_info_md5 = md5(group_info.c_str(), group_info.size()); |
|
|
auto group_info_md5 = md5(group_info_str.c_str(), group_info_str.size()); |
|
|
EXPECT_STREQ(group_info_md5.c_str(), GROUP_INFO_MD5); // verify all group info
|
|
|
EXPECT_STREQ(group_info_md5.c_str(), GROUP_INFO_MD5); // verify all group info
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// TODO: verify GROUP_SEEDS_INDEX_REV
|
|
|