Files
msime-windows/server/tests/src/test_config_template_merge.cpp
T
Evan 42238a2af6 style: 用 .clang-format 重排 server / windows / ui / log
一次性重排,无任何行为改动。四个目录各自的 .clang-format 放在仓库里已久,但全组织只有
MSIME-Linux 在 CI 里执行 clang-format 检查,这边 149 个文件里有 149 个不符合自己声明的风格。

已逐文件核对语义等价:去掉空白、注释与相邻字符串字面量拆分之后,全部 149 个文件与重排前逐字节
相同。差异只有三类——缩进与换行、clang-format 补的 } // namespace 结尾注释、以及长字符串被拆成
相邻字面量(C++ 保证自动拼接)。

这个提交会写进 .git-blame-ignore-revs。
2026-09-06 12:13:47 +09:00

119 lines
5.8 KiB
C++

#define NOMINMAX
#include "config/ime_config.h"
#include "tests/includes/test_framework.h"
#include <type_traits>
TEST_CASE(config_merge_keeps_customized_values_and_adds_new_keys)
{
const std::string template_text = "[general]\n"
"# 悬浮工具栏\n"
"floating_toolbar = true\n"
"cloud_candidates = true\n"
"\n"
"[input]\n"
"schema = \"shuangpin\" # 可选:quanpin/shuangpin\n";
const std::string user_text = "[general]\n"
"floating_toolbar = false\n"
"\n"
"[input]\n"
"schema = \"quanpin\"\n";
const std::string baseline_text = "[general]\n"
"floating_toolbar = true\n"
"\n"
"[input]\n"
"schema = \"shuangpin\"\n";
const std::string expected = "[general]\n"
"# 悬浮工具栏\n"
"floating_toolbar = false\n"
"cloud_candidates = true\n"
"\n"
"[input]\n"
"schema = \"quanpin\" # 可选:quanpin/shuangpin\n";
REQUIRE_EQ(MergeConfigIntoTemplate(template_text, user_text, baseline_text), expected);
}
TEST_CASE(config_merge_lets_new_defaults_win_for_untouched_keys)
{
const std::string template_text = "[appearance]\npage_size = 9\nfont_size = 18\n";
const std::string user_text = "[appearance]\npage_size = 8\nfont_size = 20\n";
const std::string baseline_text = "[appearance]\npage_size = 8\nfont_size = 16\n";
// page_size 仍是旧默认值 -> 跟随新默认值;font_size 被用户改过 -> 保留。
REQUIRE_EQ(MergeConfigIntoTemplate(template_text, user_text, baseline_text),
"[appearance]\npage_size = 9\nfont_size = 20\n");
}
TEST_CASE(config_merge_drops_keys_and_sections_absent_from_template)
{
const std::string template_text = "[general]\nkept = true\n";
const std::string user_text = "[general]\nkept = false\nretired = 1\n\n[gone]\nvalue = \"x\"\n";
REQUIRE_EQ(MergeConfigIntoTemplate(template_text, user_text, std::string()), "[general]\nkept = false\n");
}
TEST_CASE(config_merge_keeps_all_user_values_without_a_baseline)
{
// 从没有 config.base.toml 的旧版本升级时,无法区分「用户改的」和「旧默认值」。
const std::string template_text = "[voice_input]\nasr_token = \"<YOUR_OWN_ASR_TOKEN>\"\nlanguage = \"zh-cn\"\n";
const std::string user_text = "[voice_input]\nasr_token = \"sk-real-token\"\nlanguage = \"en\"\n";
REQUIRE_EQ(MergeConfigIntoTemplate(template_text, user_text, std::string()),
"[voice_input]\nasr_token = \"sk-real-token\"\nlanguage = \"en\"\n");
}
TEST_CASE(config_merge_handles_multiline_string_values)
{
const std::string template_text = "[ai_assistant]\n"
"prompt = \"\"\"new\ndefault prompt\"\"\"\n"
"model = \"v2\"\n";
const std::string user_text = "[ai_assistant]\n"
"prompt = \"\"\"my\nown prompt\"\"\"\n"
"model = \"v1\"\n";
const std::string baseline_text = "[ai_assistant]\n"
"prompt = \"\"\"old\ndefault prompt\"\"\"\n"
"model = \"v1\"\n";
const std::string expected = "[ai_assistant]\n"
"prompt = \"\"\"my\nown prompt\"\"\"\n"
"model = \"v2\"\n";
REQUIRE_EQ(MergeConfigIntoTemplate(template_text, user_text, baseline_text), expected);
}
TEST_CASE(config_merge_ignores_assignments_inside_multiline_strings)
{
const std::string template_text = "[ai_assistant]\n"
"prompt = \"\"\"say hi\"\"\"\n"
"model = \"v2\"\n";
// prompt 正文里的 model = ... 只是提示词内容,不能被当成一个键。
const std::string user_text = "[ai_assistant]\n"
"prompt = \"\"\"say hi\nmodel = \"hijacked\"\n\"\"\"\n";
const std::string expected = "[ai_assistant]\n"
"prompt = \"\"\"say hi\nmodel = \"hijacked\"\n\"\"\"\n"
"model = \"v2\"\n";
REQUIRE_EQ(MergeConfigIntoTemplate(template_text, user_text, std::string()), expected);
}
TEST_CASE(config_merge_ignores_commented_out_keys)
{
const std::string template_text = "[input]\n# schema = \"wubi\"\nschema = \"shuangpin\"\n";
const std::string user_text = "[input]\n# schema = \"quanpin\"\nschema = \"wubi\"\n";
REQUIRE_EQ(MergeConfigIntoTemplate(template_text, user_text, std::string()),
"[input]\n# schema = \"wubi\"\nschema = \"wubi\"\n");
}
TEST_CASE(configured_voice_input_is_handed_out_as_a_snapshot)
{
// LoadImeConfig rewrites the whole voice config on the IPC worker thread (asr_tokens / polish_tokens are cleared
// and refilled) while the voice control thread and the low-level keyboard hook read it on every keystroke. Handing
// out a reference lets those readers walk strings and maps that are being rewritten, so this accessor must return a
// snapshot by value.
REQUIRE(!std::is_reference_v<decltype(GetConfiguredVoiceInput())>);
REQUIRE((std::is_same_v<decltype(GetConfiguredVoiceInput()), VoiceInputConfig>));
const VoiceInputConfig snapshot = GetConfiguredVoiceInput();
REQUIRE_EQ(snapshot.commit_mode, VoiceInputConfig().commit_mode);
}