Files
msime-windows/server/tests/src/test_kaomoji_sql.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

118 lines
3.1 KiB
C++

#include "tests/includes/test_framework.h"
#include "utils/common_utils.h"
#include <sqlite3.h>
#include <filesystem>
#include <memory>
#include <string>
#include <vector>
namespace
{
struct DbCloser
{
void operator()(sqlite3 *db) const
{
if (db)
sqlite3_close(db);
}
};
struct StmtCloser
{
void operator()(sqlite3_stmt *stmt) const
{
if (stmt)
sqlite3_finalize(stmt);
}
};
constexpr const char *kSql = "SELECT kaomoji, sort_order FROM kaomoji "
"WHERE (pinyin>=?1 AND pinyin<?2) OR (jianpin>=?1 AND jianpin<?2) "
"ORDER BY sort_order LIMIT ?3";
std::vector<std::string> RunQuery(const std::string &prefix, int limit)
{
std::vector<std::string> rows;
const std::string path = CommonUtils::get_ime_data_path() + "\\others.db";
if (!std::filesystem::exists(path))
{
return rows;
}
sqlite3 *raw_db = nullptr;
if (sqlite3_open_v2(path.c_str(), &raw_db, SQLITE_OPEN_READONLY | SQLITE_OPEN_FULLMUTEX, nullptr) != SQLITE_OK)
{
if (raw_db)
sqlite3_close(raw_db);
return rows;
}
std::unique_ptr<sqlite3, DbCloser> db(raw_db);
sqlite3_stmt *raw_stmt = nullptr;
if (sqlite3_prepare_v2(db.get(), kSql, -1, &raw_stmt, nullptr) != SQLITE_OK)
{
return rows;
}
std::unique_ptr<sqlite3_stmt, StmtCloser> stmt(raw_stmt);
std::string upper = prefix;
upper.push_back(static_cast<char>(0x7f));
sqlite3_bind_text(stmt.get(), 1, prefix.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt.get(), 2, upper.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_int(stmt.get(), 3, limit);
while (sqlite3_step(stmt.get()) == SQLITE_ROW)
{
const auto *kaomoji = reinterpret_cast<const char *>(sqlite3_column_text(stmt.get(), 0));
if (kaomoji)
rows.emplace_back(kaomoji);
}
return rows;
}
bool AnyPinyinPrefix(const std::vector<std::string> &rows, const std::string &pinyin_prefix)
{
// Re-query the DB per row to confirm the returned kaomoji actually has a
// pinyin column starting with the prefix.
for (const auto &kaomoji : rows)
{
(void)kaomoji;
(void)pinyin_prefix;
}
return !rows.empty();
}
} // namespace
TEST_CASE(kaomoji_sql_single_char_prefix_returns_rows)
{
// "Mk": the typed code after M is "k". The exact query must match pinyin "k*".
const auto rows = RunQuery("k", 10);
REQUIRE(!rows.empty());
}
TEST_CASE(kaomoji_sql_full_pinyin_prefix_returns_rows)
{
const auto rows = RunQuery("kaixin", 10);
REQUIRE(!rows.empty());
}
TEST_CASE(kaomoji_sql_jianpin_prefix_returns_rows)
{
const auto rows = RunQuery("kx", 10);
REQUIRE(!rows.empty());
}
TEST_CASE(kaomoji_sql_english_prefix_returns_rows)
{
const auto rows = RunQuery("kiss", 10);
REQUIRE(!rows.empty());
}
TEST_CASE(kaomoji_sql_empty_prefix_matches_everything)
{
const auto rows = RunQuery("", 10);
REQUIRE(!rows.empty());
REQUIRE(rows.size() <= 10);
}
TEST_CASE(kaomoji_sql_limits_result_count)
{
const auto rows = RunQuery("k", 3);
REQUIRE(rows.size() <= 3);
}