mirror of
https://github.com/RubyMetric/chsrc
synced 2026-10-25 17:36:32 +08:00
351 lines
12 KiB
C
351 lines
12 KiB
C
/** ------------------------------------------------------------
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
* -------------------------------------------------------------
|
|
* uv-helper.c (uv.toml 字符串改写工具) 单元测试
|
|
*
|
|
* 独立编译: 不依赖 xy.h / framework, 直接 #include uv-helper.c
|
|
* ------------------------------------------------------------*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "../src/recipe/lang/Python/uv-helper.c"
|
|
|
|
static int total = 0;
|
|
static int failures = 0;
|
|
|
|
#define CHECK(cond) \
|
|
do { \
|
|
total++; \
|
|
if (!(cond)) \
|
|
{ \
|
|
failures++; \
|
|
printf ("FAIL %s:%d: %s\n", __FILE__, __LINE__, #cond); \
|
|
} \
|
|
} while (0)
|
|
|
|
#define CHECK_STR(got, expect) \
|
|
do { \
|
|
total++; \
|
|
if (strcmp ((got), (expect)) != 0) \
|
|
{ \
|
|
failures++; \
|
|
printf ("FAIL %s:%d:\n expected [%s]\n got [%s]\n", \
|
|
__FILE__, __LINE__, (expect), (got)); \
|
|
} \
|
|
} while (0)
|
|
|
|
|
|
static void
|
|
test_replace_pypi_index_url (void)
|
|
{
|
|
char *r;
|
|
|
|
/* 空文件: 追加整个段 */
|
|
r = replace_pypi_index_url ("", "https://mirror");
|
|
CHECK_STR (r, "[[index]]\nurl = \"https://mirror\"\ndefault = true\n");
|
|
free (r);
|
|
|
|
/* 已有 [[index]] 与 url: 仅替换 url 行 */
|
|
r = replace_pypi_index_url (
|
|
"[[index]]\nurl = \"https://old\"\ndefault = true\n",
|
|
"https://mirror");
|
|
CHECK_STR (r, "[[index]]\nurl = \"https://mirror\"\ndefault = true\n");
|
|
free (r);
|
|
|
|
/* default = false 保留 */
|
|
r = replace_pypi_index_url (
|
|
"[[index]]\nurl = \"https://old\"\ndefault = false\n",
|
|
"https://mirror");
|
|
CHECK_STR (r, "[[index]]\nurl = \"https://mirror\"\ndefault = false\n");
|
|
free (r);
|
|
|
|
/* [[index]] 段内没有 url 键: 在段内第一行之前插入 url + default */
|
|
r = replace_pypi_index_url (
|
|
"[[index]]\nname = \"tuna\"\n",
|
|
"https://mirror");
|
|
CHECK_STR (r, "[[index]]\nurl = \"https://mirror\"\ndefault = true\nname = \"tuna\"\n");
|
|
free (r);
|
|
|
|
/* 注释中的 [[index]] 不应被当作真实段: 追加新段 */
|
|
r = replace_pypi_index_url (
|
|
"# [[index]]\nfoo = 1\n",
|
|
"https://mirror");
|
|
CHECK_STR (r, "# [[index]]\nfoo = 1\n[[index]]\nurl = \"https://mirror\"\ndefault = true\n");
|
|
free (r);
|
|
|
|
/* 注释与真实段并存: 修改真实段 */
|
|
r = replace_pypi_index_url (
|
|
"# [[index]]\n[[index]]\nurl = \"https://old\"\n",
|
|
"https://mirror");
|
|
CHECK_STR (r, "# [[index]]\n[[index]]\nurl = \"https://mirror\"\n");
|
|
free (r);
|
|
|
|
/* 单引号字符串值也能被替换 (替换后统一为双引号) */
|
|
r = replace_pypi_index_url (
|
|
"[[index]]\nurl = 'https://old'\n",
|
|
"https://mirror");
|
|
CHECK_STR (r, "[[index]]\nurl = \"https://mirror\"\n");
|
|
free (r);
|
|
|
|
/* 多个 [[index]] 段: 优先修改 default = true 的 PyPI 替代源 */
|
|
r = replace_pypi_index_url (
|
|
"[[index]]\nurl = \"https://private\"\ndefault = false\n\n[[index]]\nurl = \"https://old\"\ndefault = true\n",
|
|
"https://mirror");
|
|
CHECK_STR (r, "[[index]]\nurl = \"https://private\"\ndefault = false\n\n[[index]]\nurl = \"https://mirror\"\ndefault = true\n");
|
|
free (r);
|
|
|
|
/* 段边界: [[index]] 之后其他表的 url 键不被误改 */
|
|
r = replace_pypi_index_url (
|
|
"[[index]]\nurl = \"https://old\"\n\n[python]\nurl = \"https://python\"\n",
|
|
"https://mirror");
|
|
CHECK_STR (r, "[[index]]\nurl = \"https://mirror\"\n\n[python]\nurl = \"https://python\"\n");
|
|
free (r);
|
|
}
|
|
|
|
|
|
static void
|
|
test_replace_python_install_mirror (void)
|
|
{
|
|
char *r;
|
|
|
|
/* 空文件 */
|
|
r = replace_python_install_mirror ("", "https://mirror");
|
|
CHECK_STR (r, "python-install-mirror = \"https://mirror\"\n");
|
|
free (r);
|
|
|
|
/* 顶层已有: 就地替换 */
|
|
r = replace_python_install_mirror (
|
|
"python-install-mirror = \"https://old\"\nother = 1\n",
|
|
"https://mirror");
|
|
CHECK_STR (r, "python-install-mirror = \"https://mirror\"\nother = 1\n");
|
|
free (r);
|
|
|
|
/* 顶层键在段头之前: 替换后仍是顶层键 */
|
|
r = replace_python_install_mirror (
|
|
"python-install-mirror = \"https://old\"\n\n[python]\nx = 1\n",
|
|
"https://mirror");
|
|
CHECK_STR (r, "python-install-mirror = \"https://mirror\"\n\n[python]\nx = 1\n");
|
|
free (r);
|
|
|
|
/* 顶层无旧键但有段: 在第一个段头之前插入, 保证新键仍属顶层 */
|
|
r = replace_python_install_mirror (
|
|
"[python]\nx = 1\n",
|
|
"https://mirror");
|
|
CHECK_STR (r, "python-install-mirror = \"https://mirror\"\n[python]\nx = 1\n");
|
|
free (r);
|
|
|
|
/* 段内同名键不受影响 (chsrc 只管理顶层键) */
|
|
r = replace_python_install_mirror (
|
|
"[python]\npython-install-mirror = \"https://old\"\n",
|
|
"https://mirror");
|
|
CHECK_STR (r, "python-install-mirror = \"https://mirror\"\n[python]\npython-install-mirror = \"https://old\"\n");
|
|
free (r);
|
|
|
|
/* 注释行不误删 */
|
|
r = replace_python_install_mirror (
|
|
"# python-install-mirror = \"comment\"\npython-install-mirror = \"https://old\"\n",
|
|
"https://mirror");
|
|
CHECK_STR (r, "# python-install-mirror = \"comment\"\npython-install-mirror = \"https://mirror\"\n");
|
|
free (r);
|
|
}
|
|
|
|
|
|
static void
|
|
test_uvh_get_top_level_value (void)
|
|
{
|
|
char *v;
|
|
|
|
v = uvh_get_top_level_value (
|
|
"python-install-mirror = \"https://x\"\n", "python-install-mirror");
|
|
CHECK (v != NULL);
|
|
if (v) { CHECK_STR (v, "https://x"); free (v); }
|
|
|
|
/* 单引号 */
|
|
v = uvh_get_top_level_value (
|
|
"python-install-mirror = 'https://x'\n", "python-install-mirror");
|
|
CHECK (v != NULL);
|
|
if (v) { CHECK_STR (v, "https://x"); free (v); }
|
|
|
|
/* 等号周围无空格 */
|
|
v = uvh_get_top_level_value (
|
|
"python-install-mirror=\"https://x\"\n", "python-install-mirror");
|
|
CHECK (v != NULL);
|
|
if (v) { CHECK_STR (v, "https://x"); free (v); }
|
|
|
|
/* 键位于段内 (非顶层) 时返回 NULL */
|
|
v = uvh_get_top_level_value (
|
|
"[python]\npython-install-mirror = \"https://x\"\n", "python-install-mirror");
|
|
CHECK (v == NULL);
|
|
|
|
/* 键不存在时返回 NULL */
|
|
v = uvh_get_top_level_value ("other = 1\n", "python-install-mirror");
|
|
CHECK (v == NULL);
|
|
|
|
/* 注释行中的键不匹配 */
|
|
v = uvh_get_top_level_value (
|
|
"# python-install-mirror = \"comment\"\n", "python-install-mirror");
|
|
CHECK (v == NULL);
|
|
}
|
|
|
|
|
|
static void
|
|
test_replace_index_url_pyproject (void)
|
|
{
|
|
char *r;
|
|
|
|
/* 空文件: 创建 [tool.uv] 表 + [[tool.uv.index]] 段 */
|
|
r = replace_index_url ("", "https://mirror", "[[tool.uv.index]]", "[tool.uv]");
|
|
CHECK_STR (r, "[tool.uv]\n[[tool.uv.index]]\nurl = \"https://mirror\"\ndefault = true\n");
|
|
free (r);
|
|
|
|
/* 已有 [tool.uv] 无 index 段: 表内追加 (在下一个段头前) */
|
|
r = replace_index_url (
|
|
"[tool.uv]\nsome = 1\n[tool.poetry]\nx = 1\n",
|
|
"https://mirror", "[[tool.uv.index]]", "[tool.uv]");
|
|
CHECK_STR (r, "[tool.uv]\nsome = 1\n[tool.poetry]\nx = 1\n[[tool.uv.index]]\nurl = \"https://mirror\"\ndefault = true\n");
|
|
free (r);
|
|
|
|
/* 已有 [tool.uv] + [[tool.uv.index]]: 替换 url */
|
|
r = replace_index_url (
|
|
"[tool.uv]\n[[tool.uv.index]]\nurl = \"https://old\"\ndefault = true\n",
|
|
"https://mirror", "[[tool.uv.index]]", "[tool.uv]");
|
|
CHECK_STR (r, "[tool.uv]\n[[tool.uv.index]]\nurl = \"https://mirror\"\ndefault = true\n");
|
|
free (r);
|
|
|
|
/* 有 [project] 等其他表时正确找到 [tool.uv] */
|
|
r = replace_index_url (
|
|
"[project]\nname = \"x\"\n\n[tool.uv]\n[[tool.uv.index]]\nurl = \"https://old\"\n",
|
|
"https://mirror", "[[tool.uv.index]]", "[tool.uv]");
|
|
CHECK_STR (r, "[project]\nname = \"x\"\n\n[tool.uv]\n[[tool.uv.index]]\nurl = \"https://mirror\"\n");
|
|
free (r);
|
|
|
|
/* [[tool.uv.index]] 段内无 url 键: 段内插入 url + default */
|
|
r = replace_index_url (
|
|
"[tool.uv]\n[[tool.uv.index]]\nname = \"mirror\"\n",
|
|
"https://mirror", "[[tool.uv.index]]", "[tool.uv]");
|
|
CHECK_STR (r, "[tool.uv]\n[[tool.uv.index]]\nurl = \"https://mirror\"\ndefault = true\nname = \"mirror\"\n");
|
|
free (r);
|
|
|
|
/* CRLF 表头与缩进键应被识别,不能产生 duplicate table/key */
|
|
r = replace_index_url (
|
|
" [tool.uv]\r\n python-install-mirror = \"https://old-python\"\r\n [[tool.uv.index]]\r\n url = \"https://old\"\r\n default = true\r\n",
|
|
"https://mirror", "[[tool.uv.index]]", "[tool.uv]");
|
|
CHECK_STR (r,
|
|
" [tool.uv]\r\n python-install-mirror = \"https://old-python\"\r\n [[tool.uv.index]]\r\n url = \"https://mirror\"\r\n default = true\r\n");
|
|
free (r);
|
|
|
|
/* CRLF 文件中无 [tool.uv]: 新建段同样使用 CRLF */
|
|
r = replace_index_url (
|
|
"[project]\r\nname = \"x\"\r\n",
|
|
"https://mirror", "[[tool.uv.index]]", "[tool.uv]");
|
|
CHECK_STR (r,
|
|
"[project]\r\nname = \"x\"\r\n\r\n[tool.uv]\r\n[[tool.uv.index]]\r\nurl = \"https://mirror\"\r\ndefault = true\r\n");
|
|
free (r);
|
|
|
|
/* [tool.uv.sources] 不会阻止后续 index 被找到 */
|
|
r = replace_index_url (
|
|
"[tool.uv]\n[tool.uv.sources]\nfoo = { path = \"foo\" }\n[[tool.uv.index]]\nurl = \"https://old\"\ndefault = true\n",
|
|
"https://mirror", "[[tool.uv.index]]", "[tool.uv]");
|
|
CHECK_STR (r,
|
|
"[tool.uv]\n[tool.uv.sources]\nfoo = { path = \"foo\" }\n[[tool.uv.index]]\nurl = \"https://mirror\"\ndefault = true\n");
|
|
free (r);
|
|
}
|
|
|
|
|
|
static void
|
|
test_replace_key_value_pyproject (void)
|
|
{
|
|
char *r;
|
|
|
|
/* 空文件: 创建 [tool.uv] 表 + 键 */
|
|
r = replace_key_value ("", "python-install-mirror", "https://mirror", "[tool.uv]");
|
|
CHECK_STR (r, "[tool.uv]\npython-install-mirror = \"https://mirror\"\n");
|
|
free (r);
|
|
|
|
/* [tool.uv] 内已有键: 替换 */
|
|
r = replace_key_value (
|
|
"[tool.uv]\npython-install-mirror = \"https://old\"\n",
|
|
"python-install-mirror", "https://mirror", "[tool.uv]");
|
|
CHECK_STR (r, "[tool.uv]\npython-install-mirror = \"https://mirror\"\n");
|
|
free (r);
|
|
|
|
/* [tool.uv] 内无该键但已有 [[tool.uv.index]] 子表: 键插在子表头前 */
|
|
r = replace_key_value (
|
|
"[tool.uv]\n[[tool.uv.index]]\nurl = \"https://pypi\"\n",
|
|
"python-install-mirror", "https://mirror", "[tool.uv]");
|
|
CHECK_STR (r, "[tool.uv]\npython-install-mirror = \"https://mirror\"\n[[tool.uv.index]]\nurl = \"https://pypi\"\n");
|
|
free (r);
|
|
|
|
/* 缩进键就地替换,不重复定义 */
|
|
r = replace_key_value (
|
|
"[tool.uv]\r\n python-install-mirror = \"https://old\"\r\n",
|
|
"python-install-mirror", "https://mirror", "[tool.uv]");
|
|
CHECK_STR (r, "[tool.uv]\r\n python-install-mirror = \"https://mirror\"\r\n");
|
|
free (r);
|
|
|
|
/* CRLF 文件中无 [tool.uv]: 新建表同样使用 CRLF */
|
|
r = replace_key_value (
|
|
"[project]\r\nname = \"x\"\r\n",
|
|
"python-install-mirror", "https://mirror", "[tool.uv]");
|
|
CHECK_STR (r,
|
|
"[project]\r\nname = \"x\"\r\n\r\n[tool.uv]\r\npython-install-mirror = \"https://mirror\"\r\n");
|
|
free (r);
|
|
}
|
|
|
|
|
|
static void
|
|
test_uvh_get_value_pyproject (void)
|
|
{
|
|
char *v;
|
|
|
|
/* 表内键提取 */
|
|
v = uvh_get_value_in_table (
|
|
"[tool.uv]\npython-install-mirror = \"https://x\"\n", "python-install-mirror", "[tool.uv]");
|
|
CHECK (v != NULL);
|
|
if (v) { CHECK_STR (v, "https://x"); free (v); }
|
|
|
|
/* 其他表内同名键: 找不到 */
|
|
v = uvh_get_value_in_table (
|
|
"[tool.other]\npython-install-mirror = \"https://x\"\n", "python-install-mirror", "[tool.uv]");
|
|
CHECK (v == NULL);
|
|
|
|
/* index url 提取 */
|
|
v = uvh_get_index_url (
|
|
"[tool.uv]\n[[tool.uv.index]]\nurl = \"https://pypi\"\ndefault = true\n",
|
|
"[[tool.uv.index]]", "[tool.uv]");
|
|
CHECK (v != NULL);
|
|
if (v) { CHECK_STR (v, "https://pypi"); free (v); }
|
|
|
|
/* 无 index 段: NULL */
|
|
v = uvh_get_index_url (
|
|
"[tool.uv]\nsome = 1\n", "[[tool.uv.index]]", "[tool.uv]");
|
|
CHECK (v == NULL);
|
|
|
|
/* 表不存在: NULL */
|
|
v = uvh_get_index_url ("", "[[tool.uv.index]]", "[tool.uv]");
|
|
CHECK (v == NULL);
|
|
}
|
|
|
|
|
|
int
|
|
main (void)
|
|
{
|
|
test_replace_pypi_index_url ();
|
|
test_replace_python_install_mirror ();
|
|
test_uvh_get_top_level_value ();
|
|
test_replace_index_url_pyproject ();
|
|
test_replace_key_value_pyproject ();
|
|
test_uvh_get_value_pyproject ();
|
|
|
|
if (failures)
|
|
{
|
|
printf ("uv-helper-test: %d/%d checks FAILED\n", failures, total);
|
|
return 1;
|
|
}
|
|
|
|
printf ("uv-helper-test: all %d checks passed\n", total);
|
|
return 0;
|
|
}
|