Files
msime-windows/server/tests/src/test_ipc_protocol_constants.cpp
T
fanlusky 94df9a7917 fix(stats): 修复统计功能审查发现的 8 个问题
- Server 退出时唤醒统计管道监听线程,避免从未有客户端连接时 join 永久阻塞
- DLL 发送批次时对 ERROR_FILE_NOT_FOUND 重试,覆盖服务端重建管道的窗口
- 新增 StatisticsEnabledChanged(26) 推送开关,DLL 侧在采集入口直接短路:
  关闭时不读 range、不分类、不开管道
- stats_meta 的 schema_version 写入正确的键名(此前键与值都是 "1")
- dropped_count 仅在实际发送的批次中消费,空批次不再吞掉丢弃计数
- _CaptureCompositionStats 改为遍历 composition range 的克隆,避免移动宿主的活动区间
- FanyImeStatsEvent 显式声明 reserved 尾部,不再把未初始化的填充字节写入管道
- 透传统计去重标记在抑制一次后即消费,避免同一 tick 内的连击被漏计
2026-09-20 20:34:50 +08:00

165 lines
10 KiB
C++

#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "ipc/ipc.h"
#include "ipc/input_key_policy.h"
#include "statistics/stats_pipe.h"
#include "tests/includes/test_framework.h"
TEST_CASE(ipc_reverse_pipes_buffer_multiple_complete_frames)
{
REQUIRE(FANY_IME_TO_TSF_PIPE_FRAME_CAPACITY >= 64);
REQUIRE(FANY_IME_TO_TSF_WORKER_PIPE_FRAME_CAPACITY >= 16);
REQUIRE(sizeof(FanyImeNamedpipeDataToTsf) * FANY_IME_TO_TSF_PIPE_FRAME_CAPACITY >=
sizeof(FanyImeNamedpipeDataToTsf) * 64);
REQUIRE(sizeof(FanyImeNamedpipeDataToTsfWorkerThread) * FANY_IME_TO_TSF_WORKER_PIPE_FRAME_CAPACITY >=
sizeof(FanyImeNamedpipeDataToTsfWorkerThread) * 16);
}
TEST_CASE(tsf_diagnostic_batches_have_a_bounded_versioned_frame)
{
REQUIRE_EQ(FANY_IME_TSF_DIAGNOSTIC_MAGIC, 0x474F4C54u);
REQUIRE_EQ(FANY_IME_TSF_DIAGNOSTIC_VERSION, 1u);
REQUIRE_EQ(sizeof(FanyImeTsfDiagnosticBatchHeader), 28u);
REQUIRE_EQ(FANY_IME_TSF_DIAGNOSTIC_MAX_FRAME_BYTES, 16u * 1024u);
REQUIRE(sizeof(FanyImeTsfDiagnosticBatchHeader) < FANY_IME_TSF_DIAGNOSTIC_MAX_FRAME_BYTES);
}
TEST_CASE(ipc_pipe_ready_is_a_distinct_server_reply)
{
REQUIRE_EQ(Global::DataFromServerMsgType::PipeReady, 9u);
REQUIRE(Global::DataFromServerMsgType::PipeReady > Global::DataFromServerMsgType::MovePageNext);
REQUIRE_EQ(Global::DataFromServerMsgType::CommitExactText, 10u);
REQUIRE(Global::DataFromServerMsgType::CommitExactText > Global::DataFromServerMsgType::PipeReady);
REQUIRE_EQ(Global::DataFromServerMsgType::UiLessComposition, 11u);
REQUIRE(Global::DataFromServerMsgType::UiLessComposition > Global::DataFromServerMsgType::CommitExactText);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::FocusSessionReady, 8u);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::PipeReady, 9u);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::InsertText, 10u);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::SmartPunctuationChanged, 11u);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::PairedPunctuationChanged, 12u);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::MicrosoftShuangpinChanged, 13u);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::SmartPunctuationRepeatToChineseChanged, 14u);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::UpdateVoiceComposition, 15u);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::CancelVoiceComposition, 16u);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::CommitVoiceComposition, 17u);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::InputModeChanged, 18u);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::CapsLockChanged, 19u);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::TsfDiagnosticLogChanged, 20u);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::PunctuationLockChanged, 21u);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::SmartPunctuationSpaceConvertChanged, 22u);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::SmartPunctuationDirectDigitChanged, 24u);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::SmartPunctuationDirectLetterChanged, 25u);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::StatisticsEnabledChanged, 26u);
// Opcode 23 (the removed paired-symbol space conversion) is intentionally
// left unused.
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::MaxKnown, 26u);
REQUIRE(Global::DataFromServerMsgTypeToTsfWorkerThread::FocusSessionReady >
Global::DataFromServerMsgTypeToTsfWorkerThread::PagingCommaPeriodChanged);
REQUIRE(Global::DataFromServerMsgTypeToTsfWorkerThread::PipeReady >
Global::DataFromServerMsgTypeToTsfWorkerThread::FocusSessionReady);
REQUIRE(Global::DataFromServerMsgTypeToTsfWorkerThread::InsertText >
Global::DataFromServerMsgTypeToTsfWorkerThread::PipeReady);
REQUIRE(Global::DataFromServerMsgTypeToTsfWorkerThread::SmartPunctuationChanged >
Global::DataFromServerMsgTypeToTsfWorkerThread::InsertText);
REQUIRE(Global::DataFromServerMsgTypeToTsfWorkerThread::PairedPunctuationChanged >
Global::DataFromServerMsgTypeToTsfWorkerThread::SmartPunctuationChanged);
REQUIRE(Global::DataFromServerMsgTypeToTsfWorkerThread::MicrosoftShuangpinChanged >
Global::DataFromServerMsgTypeToTsfWorkerThread::PairedPunctuationChanged);
REQUIRE(Global::DataFromServerMsgTypeToTsfWorkerThread::SmartPunctuationRepeatToChineseChanged >
Global::DataFromServerMsgTypeToTsfWorkerThread::MicrosoftShuangpinChanged);
REQUIRE(Global::DataFromServerMsgTypeToTsfWorkerThread::UpdateVoiceComposition >
Global::DataFromServerMsgTypeToTsfWorkerThread::SmartPunctuationRepeatToChineseChanged);
REQUIRE(Global::DataFromServerMsgTypeToTsfWorkerThread::CancelVoiceComposition >
Global::DataFromServerMsgTypeToTsfWorkerThread::UpdateVoiceComposition);
REQUIRE(Global::DataFromServerMsgTypeToTsfWorkerThread::CommitVoiceComposition >
Global::DataFromServerMsgTypeToTsfWorkerThread::CancelVoiceComposition);
REQUIRE(Global::DataFromServerMsgTypeToTsfWorkerThread::InputModeChanged >
Global::DataFromServerMsgTypeToTsfWorkerThread::CommitVoiceComposition);
REQUIRE(Global::DataFromServerMsgTypeToTsfWorkerThread::CapsLockChanged >
Global::DataFromServerMsgTypeToTsfWorkerThread::InputModeChanged);
REQUIRE(Global::DataFromServerMsgTypeToTsfWorkerThread::TsfDiagnosticLogChanged >
Global::DataFromServerMsgTypeToTsfWorkerThread::CapsLockChanged);
REQUIRE(Global::DataFromServerMsgTypeToTsfWorkerThread::PunctuationLockChanged >
Global::DataFromServerMsgTypeToTsfWorkerThread::TsfDiagnosticLogChanged);
REQUIRE(Global::DataFromServerMsgTypeToTsfWorkerThread::SmartPunctuationSpaceConvertChanged >
Global::DataFromServerMsgTypeToTsfWorkerThread::PunctuationLockChanged);
REQUIRE(Global::DataFromServerMsgTypeToTsfWorkerThread::SmartPunctuationDirectDigitChanged >
Global::DataFromServerMsgTypeToTsfWorkerThread::SmartPunctuationSpaceConvertChanged);
REQUIRE(Global::DataFromServerMsgTypeToTsfWorkerThread::SmartPunctuationDirectLetterChanged >
Global::DataFromServerMsgTypeToTsfWorkerThread::SmartPunctuationDirectDigitChanged);
REQUIRE(Global::DataFromServerMsgTypeToTsfWorkerThread::StatisticsEnabledChanged >
Global::DataFromServerMsgTypeToTsfWorkerThread::SmartPunctuationDirectLetterChanged);
REQUIRE_EQ(Global::DataFromServerMsgTypeToTsfWorkerThread::MaxKnown,
Global::DataFromServerMsgTypeToTsfWorkerThread::StatisticsEnabledChanged);
}
TEST_CASE(ipc_client_suspension_is_a_distinct_nonterminal_route_reset)
{
REQUIRE_EQ(FanyImePipeEventType::ClientActivated, 11u);
REQUIRE_EQ(FanyImePipeEventType::ClientDeactivated, 12u);
REQUIRE_EQ(FanyImePipeEventType::StatusSnapshot, 13u);
REQUIRE_EQ(FanyImePipeEventType::ClientSuspended, 14u);
REQUIRE(FanyImePipeEventType::IsRouteDeactivation(FanyImePipeEventType::ClientDeactivated));
REQUIRE(FanyImePipeEventType::IsRouteDeactivation(FanyImePipeEventType::ClientSuspended));
REQUIRE(FanyImePipeEventType::IsTerminalDeactivation(FanyImePipeEventType::ClientDeactivated));
REQUIRE(!FanyImePipeEventType::IsTerminalDeactivation(FanyImePipeEventType::ClientSuspended));
REQUIRE(!FanyImePipeEventType::IsRouteDeactivation(FanyImePipeEventType::ClientActivated));
}
TEST_CASE(ipc_focus_restored_is_an_appended_opcode_and_not_a_route_reset)
{
REQUIRE_EQ(FanyImePipeEventType::FocusRestored, 15u);
REQUIRE(!FanyImePipeEventType::IsRouteDeactivation(FanyImePipeEventType::FocusRestored));
REQUIRE(!FanyImePipeEventType::IsTerminalDeactivation(FanyImePipeEventType::FocusRestored));
}
TEST_CASE(ipc_uiless_flag_is_outside_key_modifier_mask)
{
REQUIRE_EQ(FanyImePipeFlags::UiLess, 0x80000000u);
REQUIRE((FanyImePipeFlags::UiLess & FanyImeIpc::kKeyModifierMask) == 0u);
REQUIRE((FanyImeIpc::kModifierUiLess & FanyImeIpc::kKeyModifierMask) == 0u);
}
TEST_CASE(ipc_pipe_dacl_admits_only_the_owning_account)
{
const std::wstring sddl = FanyImeIpc::BuildPipeSecurityDescriptorSddl(L"S-1-5-21-1-2-3-1001");
// Everyone must never appear: the pipe namespace is machine-global, so a WD ACE lets any local account connect to
// the server, and FILE_ALL_ACCESS additionally lets it add instances to a name the server already owns.
REQUIRE(sddl.find(L";;;WD)") == std::wstring::npos);
REQUIRE(sddl.find(L"(A;;FA;;;S-1-5-21-1-2-3-1001)") != std::wstring::npos);
REQUIRE(sddl.find(L"(A;;FA;;;SY)") != std::wstring::npos);
REQUIRE(sddl.find(L"S:(ML;;NW;;;LW)") != std::wstring::npos);
}
TEST_CASE(ipc_pipe_dacl_gives_app_containers_connect_only_rights)
{
const std::wstring sddl = FanyImeIpc::BuildPipeSecurityDescriptorSddl(L"S-1-5-21-1-2-3-1001");
REQUIRE(sddl.find(L"(A;;FA;;;AC)") == std::wstring::npos);
REQUIRE(sddl.find(L"(A;;0x12019b;;;AC)") != std::wstring::npos);
REQUIRE((FanyImeIpc::kPipeClientAccessMask & FILE_CREATE_PIPE_INSTANCE) == 0u);
REQUIRE((FanyImeIpc::kPipeClientAccessMask & FILE_READ_DATA) != 0u);
REQUIRE((FanyImeIpc::kPipeClientAccessMask & FILE_WRITE_DATA) != 0u);
REQUIRE((FanyImeIpc::kPipeClientAccessMask & FILE_WRITE_ATTRIBUTES) != 0u);
REQUIRE((FanyImeIpc::kPipeClientAccessMask & SYNCHRONIZE) != 0u);
}
TEST_CASE(ipc_pipe_security_descriptor_fails_closed_without_an_owner_sid)
{
REQUIRE(FanyImeIpc::BuildPipeSecurityDescriptorSddl(L"").empty());
}
TEST_CASE(stats_pipe_name_carries_the_decimal_session_suffix)
{
// Named pipes are machine-global; a missing or non-decimal suffix would let
// concurrent sessions fight over one listener, so the DLL and Server must
// build the exact same name.
REQUIRE_EQ(MsimeStats::BuildStatsPipeName(0), std::wstring(L"\\\\.\\pipe\\FanyImeStatsNamedPipe-0"));
REQUIRE_EQ(MsimeStats::BuildStatsPipeName(7), std::wstring(L"\\\\.\\pipe\\FanyImeStatsNamedPipe-7"));
REQUIRE_EQ(MsimeStats::BuildStatsPipeName(42), std::wstring(L"\\\\.\\pipe\\FanyImeStatsNamedPipe-42"));
REQUIRE_EQ(std::wstring(FANY_IME_STATS_PIPE_NAME_PREFIX) + L"12", MsimeStats::BuildStatsPipeName(12));
}