# ============================================================================ # 字符串工具模块测试(src/lib/strings.sh) # ============================================================================ # 每个测试前重置依赖的全局状态 setup() { COLOR_OUTPUT=false TMDB_LANG="zh-CN" SPECIAL_MAP=() } # sanitize:删除非法字符 test_sanitize_removes_illegal_chars() { assert_eq "abcdefghij" "$(sanitize 'a/b\c:d*e?f"gi|j')" "sanitize 应删除 \\ / : * ? \" < > |" } # sanitize:保留中文与空格 test_sanitize_keeps_cjk_and_spaces() { assert_eq "某科学的超电磁炮T" "$(sanitize '某科学的超电磁炮T')" assert_eq "刀剑神域 爱丽丝篇" "$(sanitize '刀剑神域 爱丽丝篇')" } # sanitize:空输入 test_sanitize_empty_input() { assert_eq "" "$(sanitize "")" assert_eq "" "$(sanitize "///")" } # clean_name:去方括号标记与首尾空白 test_clean_name_strips_brackets_and_spaces() { assert_eq "Show Title" "$(clean_name '[VCB-Studio] Show Title [1080p]')" assert_eq "Title" "$(clean_name ' [A] Title [B] ')" } # strip_season_suffix:多种季后缀 test_strip_season_suffix_variants() { assert_eq "Show" "$(strip_season_suffix 'Show S01')" assert_eq "Show" "$(strip_season_suffix 'Show 2nd Season')" assert_eq "Show" "$(strip_season_suffix 'Show S12')" # 行为契约:仅剥离 Season 前带数字的形式;"Show Season 2" 由 parse_media_filename 处理 assert_eq "Show Season 2" "$(strip_season_suffix 'Show Season 2')" assert_eq "无需处理" "$(strip_season_suffix '无需处理')" } # norm_str:全角转半角 + 去空格/连字符 + 小写 test_norm_str_fullwidth_to_halfwidth() { assert_eq "aliceization" "$(norm_str 'Aliceization')" assert_eq "swordartonline" "$(norm_str 'Sword Art Online')" assert_eq "iiiiiivv" "$(norm_str 'ⅡⅢⅣⅤ')" assert_eq "menu01" "$(norm_str 'Menu 01')" } # safe_printf_int:补零与非数字默认值 test_safe_printf_int_padding() { assert_eq "01" "$(safe_printf_int 1)" assert_eq "23" "$(safe_printf_int 23)" assert_eq "00" "$(safe_printf_int "")" assert_eq "99" "$(safe_printf_int "abc" "99")" assert_eq "07" "$(safe_printf_int "007")" } # normalize_abs:相对/绝对路径归一化 test_normalize_abs_paths() { local d d="$(mktemp -d)" assert_eq "$d" "$(normalize_abs "$d")" "绝对路径原样返回" assert_eq "$d/sub" "$(normalize_abs "$d/sub")" "不存在的子目录也应归一化" assert_eq "" "$(normalize_abs "")" "空串原样返回" rm -rf "$d" } # is_companion:伴随文件判断 test_is_companion_detection() { assert_success is_companion "/path/Show.S01E01.mkv.ass" "/path/Show.S01E01.mkv" assert_success is_companion "/path/Show.S01E01.zh-CN.ass" "/path/Show.S01E01" assert_success is_companion "/path/Show.S01E01.flac" "/path/Show.S01E01" assert_failure is_companion "/path/Other.mkv" "/path/Show.S01E01" # 行为契约:视频自身去扩展名后等于 vbase → 也判为伴随(link_companions 调用前先跳过自身) assert_success is_companion "/path/Show.S01E01.mkv" "/path/Show.S01E01" } # translate_fragment:查表、核心词回退、归一化 test_translate_fragment_lookup() { SPECIAL_MAP["menu"]='["Menu", "菜单"]' SPECIAL_MAP["cm01"]='["CM", "广告"]' assert_eq "Menu" "$(translate_fragment "Menu01")" "去数字后查核心词" assert_eq "CM" "$(translate_fragment "CM01")" "精确键优先" assert_eq "Menu" "$(translate_fragment "Menu01")" "全角归一化" assert_eq "PV-01" "$(translate_fragment "PV-01")" "无映射时原样返回" }