一次性重排,无任何行为改动。四个目录各自的 .clang-format 放在仓库里已久,但全组织只有 MSIME-Linux 在 CI 里执行 clang-format 检查,这边 149 个文件里有 149 个不符合自己声明的风格。 已逐文件核对语义等价:去掉空白、注释与相邻字符串字面量拆分之后,全部 149 个文件与重排前逐字节 相同。差异只有三类——缩进与换行、clang-format 补的 } // namespace 结尾注释、以及长字符串被拆成 相邻字面量(C++ 保证自动拼接)。 这个提交会写进 .git-blame-ignore-revs。
145 lines
4.8 KiB
C++
145 lines
4.8 KiB
C++
#include "global/globals.h"
|
|
#include "tests/includes/test_framework.h"
|
|
|
|
namespace
|
|
{
|
|
Global::CandidateUiState MakeCandidateUiState(int item_count, int page_size)
|
|
{
|
|
Global::CandidateUiState state;
|
|
state.item_total_count = item_count;
|
|
state.page_size = page_size;
|
|
return state;
|
|
}
|
|
} // namespace
|
|
|
|
TEST_CASE(candidate_ui_selection_moves_from_page_end_to_next_page_start)
|
|
{
|
|
auto state = MakeCandidateUiState(8, 3);
|
|
state.page_index = 0;
|
|
state.selected_index_in_page = 2;
|
|
|
|
REQUIRE(state.move_selection(1));
|
|
REQUIRE_EQ(state.page_index, 1);
|
|
REQUIRE_EQ(state.selected_index_in_page, 0);
|
|
}
|
|
|
|
TEST_CASE(candidate_ui_selection_moves_from_page_start_to_previous_page_end)
|
|
{
|
|
auto state = MakeCandidateUiState(8, 3);
|
|
state.page_index = 1;
|
|
state.selected_index_in_page = 0;
|
|
|
|
REQUIRE(state.move_selection(-1));
|
|
REQUIRE_EQ(state.page_index, 0);
|
|
REQUIRE_EQ(state.selected_index_in_page, 2);
|
|
}
|
|
|
|
TEST_CASE(candidate_ui_selection_stops_at_first_and_last_candidate)
|
|
{
|
|
auto state = MakeCandidateUiState(8, 3);
|
|
REQUIRE(!state.move_selection(-1));
|
|
REQUIRE_EQ(state.page_index, 0);
|
|
REQUIRE_EQ(state.selected_index_in_page, 0);
|
|
|
|
state.page_index = 2;
|
|
state.selected_index_in_page = 1;
|
|
REQUIRE(!state.move_selection(1));
|
|
REQUIRE_EQ(state.page_index, 2);
|
|
REQUIRE_EQ(state.selected_index_in_page, 1);
|
|
}
|
|
|
|
TEST_CASE(candidate_ui_detects_only_the_last_loaded_candidate_as_exhausted)
|
|
{
|
|
auto state = MakeCandidateUiState(24, 6);
|
|
|
|
state.page_index = 0;
|
|
state.selected_index_in_page = 5;
|
|
REQUIRE(!state.is_selection_at_last_candidate());
|
|
REQUIRE(state.has_next_page());
|
|
|
|
state.page_index = 3;
|
|
state.selected_index_in_page = 4;
|
|
REQUIRE(!state.is_selection_at_last_candidate());
|
|
REQUIRE(!state.has_next_page());
|
|
|
|
state.selected_index_in_page = 5;
|
|
REQUIRE(state.is_selection_at_last_candidate());
|
|
}
|
|
|
|
TEST_CASE(candidate_ui_detects_last_candidate_on_a_partial_page)
|
|
{
|
|
auto state = MakeCandidateUiState(14, 6);
|
|
state.page_index = 2;
|
|
state.selected_index_in_page = 1;
|
|
|
|
REQUIRE(state.is_selection_at_last_candidate());
|
|
}
|
|
|
|
TEST_CASE(candidate_ui_reports_whether_the_current_page_is_full)
|
|
{
|
|
auto full = MakeCandidateUiState(24, 6);
|
|
full.page_index = 3;
|
|
REQUIRE(full.is_current_page_full());
|
|
|
|
auto partial = MakeCandidateUiState(26, 6);
|
|
partial.page_index = 4;
|
|
REQUIRE(!partial.is_current_page_full());
|
|
}
|
|
|
|
TEST_CASE(candidate_ui_detects_entry_into_a_partial_last_page)
|
|
{
|
|
auto partial = MakeCandidateUiState(26, 6);
|
|
partial.page_index = 3;
|
|
partial.selected_index_in_page = 5;
|
|
REQUIRE(partial.is_next_page_partial_last_page());
|
|
REQUIRE(partial.is_selection_at_current_page_end());
|
|
|
|
partial.page_index = 2;
|
|
REQUIRE(!partial.is_next_page_partial_last_page());
|
|
|
|
auto full = MakeCandidateUiState(24, 6);
|
|
full.page_index = 2;
|
|
full.selected_index_in_page = 5;
|
|
REQUIRE(!full.is_next_page_partial_last_page());
|
|
REQUIRE(full.is_selection_at_current_page_end());
|
|
}
|
|
|
|
TEST_CASE(candidate_page_snapshot_survives_a_rebuild_of_the_live_state)
|
|
{
|
|
Global::ClearCandidatePageSnapshot();
|
|
Global::candidate_ui.clear_page();
|
|
Global::candidate_ui.page_views.push_back(CandidateViewItem{"ni", "", "", "", false});
|
|
Global::candidate_ui.page_words.push_back(L"ni");
|
|
Global::candidate_ui.cur_page_item_cnt = 1;
|
|
Global::candidate_ui.item_total_count = 1;
|
|
Global::candidate_ui.page_size = 8;
|
|
Global::candidate_ui.selected_index_in_page = 0;
|
|
|
|
auto published = std::make_shared<Global::CandidatePageSnapshot>();
|
|
published->page_views = Global::candidate_ui.page_views;
|
|
published->page_words = Global::candidate_ui.page_words;
|
|
published->candidate_string = L"1.ni";
|
|
published->selected_index_in_page = Global::candidate_ui.selected_index_in_page;
|
|
published->page_count = Global::candidate_ui.current_page_count();
|
|
published->page_item_count = Global::candidate_ui.cur_page_item_cnt;
|
|
Global::PublishCandidatePageSnapshot(std::move(published));
|
|
|
|
const Global::CandidatePageSnapshotPtr page = Global::LoadCandidatePageSnapshot();
|
|
|
|
// The worker rebuilds the live page while the UI thread still holds the snapshot it was handed. Reading the live
|
|
// vectors here is exactly the use-after-free the snapshot exists to prevent, so the loaded page has to be
|
|
// unaffected.
|
|
Global::candidate_ui.set_items({});
|
|
|
|
REQUIRE_EQ(page->page_views.size(), static_cast<size_t>(1));
|
|
REQUIRE_EQ(page->page_views[0].text, std::string("ni"));
|
|
REQUIRE_EQ(page->page_words.size(), static_cast<size_t>(1));
|
|
REQUIRE_EQ(page->candidate_string, std::wstring(L"1.ni"));
|
|
REQUIRE_EQ(page->page_count, 1);
|
|
REQUIRE_EQ(page->page_item_count, 1);
|
|
REQUIRE(Global::candidate_ui.page_views.empty());
|
|
|
|
Global::ClearCandidatePageSnapshot();
|
|
REQUIRE(Global::LoadCandidatePageSnapshot()->page_views.empty());
|
|
}
|