Browse Source

test: add global helper module

master
Dnomd343 2 months ago
parent
commit
ca945b450f
  1. 10
      src/core_test/CMakeLists.txt
  2. 109
      src/core_test/cases/group_union.cc
  3. 2
      src/core_test/cases/helper/cases.h
  4. 22
      src/core_test/cases/helper/helper.cc
  5. 86
      src/core_test/helper/internal/impl.cc
  6. 51
      src/core_test/helper/parallel.h

10
src/core_test/CMakeLists.txt

@ -12,6 +12,13 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR})
# ------------------------------------------------------------------------------------ #
add_library(test_helper
helper/internal/impl.cc
)
target_link_libraries(test_helper PRIVATE klotski_core bs::thread_pool)
# ------------------------------------------------------------------------------------ #
set(KLSK_TEST_CASES_SRC
cases/ranges.cc
cases/ranges_union.cc
@ -19,13 +26,12 @@ set(KLSK_TEST_CASES_SRC
cases/all_cases.cc
cases/group_union.cc
cases/group.cc
cases/helper/helper.cc
cases/helper/block_num.cc
cases/helper/group_impl.cc
)
add_executable(test_klotski_cases ${KLSK_TEST_CASES_SRC})
target_link_libraries(test_klotski_cases PRIVATE ${KLSK_TEST_DEPS})
target_link_libraries(test_klotski_cases PRIVATE ${KLSK_TEST_DEPS} test_helper)
add_test(NAME klotski_cases COMMAND test_klotski_cases)
# ------------------------------------------------------------------------------------ #

109
src/core_test/cases/group_union.cc

@ -9,6 +9,8 @@
#include "helper/cases.h"
#include "common_code/common_code.h"
#include "helper/parallel.h"
using klotski::codec::ShortCode;
using klotski::cases::Group;
@ -23,96 +25,77 @@ using klotski::cases::ALL_GROUP_NUM;
EXPECT_SORTED_AND_UNIQUE(R); \
EXPECT_EQ(R.back(), R.size() - 1)
TEST(GroupUnion, basic) {
EXPECT_FALSE(GroupUnion::create(TYPE_ID_LIMIT).has_value());
type_id_parallel([](uint32_t type_id) {
#define EXPECT_REPEAT(R, val) \
EXPECT_FALSE(R.empty()); \
EXPECT_EQ(R.front(), val); \
EXPECT_EQ(std::adjacent_find(R.begin(), R.end(), std::not_equal_to<>()), R.end())
TEST(GroupUnion, basic) {
TYPE_ID_PARALLEL({
EXPECT_TRUE(GroupUnion::create(type_id).has_value());
EXPECT_EQ(GroupUnion::create(type_id).value().unwrap(), type_id);
EXPECT_EQ(GroupUnion::unsafe_create(type_id).unwrap(), type_id);
});
EXPECT_FALSE(GroupUnion::create(TYPE_ID_LIMIT).has_value());
auto group_union = GroupUnion::unsafe_create(type_id);
auto groups = group_union.groups();
for (const auto group : groups) {
EXPECT_EQ(group.type_id(), type_id);
}
GROUP_UNION_PARALLEL({
const auto groups = group_union.groups();
EXPECT_EQ(groups.size(), group_union.group_num());
auto get_type_id = [](const auto g) { return g.type_id(); };
const auto type_ids = groups | std::views::transform(get_type_id) | std::ranges::to<std::vector>();
EXPECT_REPEAT(type_ids, group_union.unwrap());
auto group_ids = groups | std::views::transform([](Group g) {
return g.group_id();
}) | std::ranges::to<std::vector>();
auto get_group_id = [](const auto g) { return g.group_id(); };
const auto group_ids = groups | std::views::transform(get_group_id) | std::ranges::to<std::vector>();
EXPECT_IOTA(group_ids);
for (auto group_id : group_ids) {
for (const auto g : group_union.groups()) {
auto type_id = g.type_id();
auto group_id = g.group_id();
EXPECT_TRUE(group_union.group(group_id).has_value());
EXPECT_EQ(group_union.group(group_id).value().type_id(), type_id);
EXPECT_EQ(group_union.group(group_id).value().group_id(), group_id);
EXPECT_EQ(group_union.group(group_id)->type_id(), type_id);
EXPECT_EQ(group_union.group(group_id)->group_id(), group_id);
}
EXPECT_FALSE(group_union.group(group_ids.size()).has_value());
EXPECT_FALSE(group_union.group(group_union.group_num()).has_value());
});
}
TEST(GroupUnion, constant) {
EXPECT_EQ(TYPE_ID_LIMIT, 203);
EXPECT_EQ(ALL_GROUP_NUM, 25422);
// TODO: verify from local builder
EXPECT_EQ(TYPE_ID_LIMIT, group_union_num());
// TODO: verify TYPE_ID_LIMIT / ALL_GROUP_NUM data
uint32_t sum = 0;
for (uint32_t i = 0; i < group_union_num(); ++i) {
sum += group_num(i);
}
EXPECT_EQ(ALL_GROUP_NUM, sum);
// TODO: verify GROUP_UNION_SIZE (size) / GROUP_NUM (group_num) / MAX_GROUP_SIZE (max_group_size)
// test from member function directly?
EXPECT_EQ(TYPE_ID_LIMIT, group_union_num());
}
TEST(GroupUnion, values) {
GROUP_UNION_PARALLEL({
auto type_id = group_union.unwrap();
auto &cases = group_union_cases(type_id);
type_id_parallel([](uint32_t type_id) {
auto &kk = group_union_cases(type_id);
EXPECT_EQ(GroupUnion::unsafe_create(type_id).size(), kk.size());
EXPECT_EQ(GroupUnion::unsafe_create(type_id).group_num(), group_num(type_id));
auto groups = GroupUnion::unsafe_create(type_id).groups();
auto kk_view = groups | std::views::transform([](Group group) {
return group.size();
});
auto max_it = *std::ranges::max_element(kk_view);
EXPECT_EQ(GroupUnion::unsafe_create(type_id).max_group_size(), max_it);
EXPECT_EQ(group_union.size(), cases.size());
EXPECT_EQ(group_union.cases().codes(), cases);
EXPECT_EQ(group_union.group_num(), group_num(type_id));
});
}
TEST(GroupUnion, cases) {
type_id_parallel([](uint32_t type_id) {
auto cases = group_union_cases(type_id);
EXPECT_EQ(cases, GroupUnion::unsafe_create(type_id).cases().codes());
auto get_group_size = [](auto g) { return g.size(); };
const auto sizes = group_union.groups() | std::views::transform(get_group_size);
EXPECT_EQ(group_union.max_group_size(), *std::ranges::max_element(sizes));
});
}
TEST(GroupUnion, type_id) {
ShortCode::speed_up(true);
// TODO: using `common_code_parallel`
for (uint64_t head = 0; head < 16; ++head) {
for (const auto range : AllCases::instance().fetch()[head]) {
auto common_code = CommonCode::unsafe_create(head << 32 | range);
auto short_code = common_code.to_short_code();
auto raw_code = common_code.to_raw_code();
auto expect = to_type_id(cal_block_num(range));
EXPECT_EQ(GroupUnion::from_raw_code(raw_code).unwrap(), expect);
EXPECT_EQ(GroupUnion::from_short_code(short_code).unwrap(), expect);
EXPECT_EQ(GroupUnion::from_common_code(common_code).unwrap(), expect);
}
}
COMMON_CODE_PARALLEL({
auto type_id = to_type_id(cal_block_num(code.unwrap()));
EXPECT_EQ(GroupUnion::from_common_code(code).unwrap(), type_id);
EXPECT_EQ(GroupUnion::from_raw_code(code.to_raw_code()).unwrap(), type_id);
EXPECT_EQ(GroupUnion::from_short_code(code.to_short_code()).unwrap(), type_id);
});
}

2
src/core_test/cases/helper/cases.h

@ -116,5 +116,3 @@ const std::vector<CommonCode>& group_union_cases(uint32_t type_id);
const std::vector<CommonCode>& group_cases(uint32_t type_id, uint32_t group_id);
// ----------------------------------------------------------------------------------------- //
void type_id_parallel(std::function<void(uint32_t type_id)> &&func);

22
src/core_test/cases/helper/helper.cc

@ -1,22 +0,0 @@
#include <gtest/gtest.h>
#include "cases.h"
using klotski::cases::TYPE_ID_LIMIT;
void type_id_parallel(std::function<void(uint32_t type_id)> &&func) {
BS::thread_pool pool;
// TODO: using `detach_sequence`
for (uint32_t type_id = 0; type_id < TYPE_ID_LIMIT; ++type_id) {
pool.detach_task([type_id, func = std::move(func)]() {
func(type_id);
});
}
pool.wait();
}

86
src/core_test/helper/internal/impl.cc

@ -0,0 +1,86 @@
#include <BS_thread_pool.hpp>
#include <iostream>
#include "group/group.h"
#include "helper/parallel.h"
#include "all_cases/all_cases.h"
using klotski::cases::AllCases;
using klotski::cases::TYPE_ID_LIMIT;
using klotski::cases::ALL_CASES_NUM_;
void helper::type_id_parallel(std::function<void(uint32_t type_id)> &&func) {
BS::thread_pool pool;
// TODO: using `detach_sequence`
for (uint32_t type_id = 0; type_id < TYPE_ID_LIMIT; ++type_id) {
pool.detach_task([type_id, &func]() {
func(type_id);
});
}
pool.wait();
}
void helper::group_union_parallel(std::function<void(GroupUnion)> &&func) {
type_id_parallel([&func](uint32_t type_id) {
func(GroupUnion::unsafe_create(type_id));
});
}
void helper::common_code_parallel(std::function<void(std::span<CommonCode>)> &&func) {
static auto codes = AllCases::instance().fetch().codes();
BS::thread_pool pool;
// TODO: enhance performance
pool.detach_blocks((uint64_t)0, codes.size(), [&func](auto start, auto end) {
func(std::span<CommonCode> {codes.data() + start, end - start});
}, 16);
pool.wait();
}
void helper::raw_code_parallel(std::function<void(std::span<RawCode>)> &&func) {
auto common_codes = AllCases::instance().fetch().codes();
static auto codes = std::vector<RawCode> {common_codes.begin(), common_codes.end()};
BS::thread_pool pool;
pool.detach_blocks((uint64_t)0, codes.size(), [&func](auto start, auto end) {
func(std::span<RawCode> {codes.data() + start, end - start});
}, 16);
pool.wait();
}
void helper::short_code_parallel(std::function<void(std::span<ShortCode>)> &&func) {
static auto codes = []() {
std::vector<uint32_t> v (klotski::codec::SHORT_CODE_LIMIT);
std::iota(v.begin(), v.end(), 0);
return v;
}();
BS::thread_pool pool;
pool.detach_blocks((uint64_t)0, codes.size(), [&func](auto start, auto end) {
auto span = std::span<uint32_t> {codes.data() + start, end - start};
func(std::bit_cast<std::span<ShortCode>>(span));
}, 16);
pool.wait();
}

51
src/core_test/helper/parallel.h

@ -0,0 +1,51 @@
#pragma once
#include <span>
#include "raw_code/raw_code.h"
#include "short_code/short_code.h"
#include "common_code/common_code.h"
using klotski::codec::RawCode;
using klotski::codec::ShortCode;
using klotski::codec::CommonCode;
using klotski::cases::GroupUnion;
namespace helper {
// ----------------------------------------------------------------------------------------- //
void type_id_parallel(std::function<void(uint32_t type_id)> &&func);
void group_union_parallel(std::function<void(GroupUnion group_union)> &&func);
#define TYPE_ID_PARALLEL(impl) \
helper::type_id_parallel([](uint32_t type_id) {impl})
#define GROUP_UNION_PARALLEL(impl) \
helper::group_union_parallel([](GroupUnion group_union) {impl})
// ----------------------------------------------------------------------------------------- //
/// Spawn all valid RawCodes in parallel.
void raw_code_parallel(std::function<void(std::span<RawCode>)> &&func);
/// Spawn all valid ShortCodes in parallel.
void short_code_parallel(std::function<void(std::span<ShortCode>)> &&func);
/// Spawn all valid CommonCodes in parallel.
void common_code_parallel(std::function<void(std::span<CommonCode>)> &&func);
#define CODE_PARALLEL(Type, type, impl) \
helper::type##_code_parallel([](std::span<Type##Code> codes) { \
for (auto code : codes) {impl} \
})
#define RAW_CODE_PARALLEL(impl) CODE_PARALLEL(Raw, raw, impl)
#define SHORT_CODE_PARALLEL(impl) CODE_PARALLEL(Short, short, impl)
#define COMMON_CODE_PARALLEL(impl) CODE_PARALLEL(Common, common, impl)
// ----------------------------------------------------------------------------------------- //
} // namespace helper
Loading…
Cancel
Save