refactor: 迁移至 bashly CLI 与功能域模块结构

- CLI 定义迁移至 src/bashly.yml(bashly 1.4 生成参数解析),入口收敛为 src/root_command.sh
- 源码按功能域重组:config/storage/integrate/media/pipeline,消除扁平散落
- 新增零依赖测试框架 tests/(123 用例)与 CI 流水线(lint + test + build + 产物一致性)
- build.sh 支持版本单一来源注入与 --check 产物校验;新增 lint.sh(bash -n + shellcheck 零容忍)
- 删除旧单文件 media_organizer.sh 与旧扁平模块
This commit is contained in:
Shuery committed 2026-08-14 22:41:28 +08:00
1 parent d978a13a83
commit 0df07ad0ae
48 files changed
+5813 -6812

No files matched your search

+114
View File
@@ -0,0 +1,114 @@
# ============================================================================
# 配置文件类目分区测试(src/lib/config/maps.sh)
# ============================================================================
setup() {
TEST_DIR="$(mktemp -d)"
AUTOMATED=true
# 干净状态
SPECIAL_WORDS_CAT=()
SKIP_DIRS_CAT=()
SPECIAL_MAP_CAT=()
RAW_SPECIAL_MAP_CAT=()
SEASON_OFFSET_CAT=()
SKIP_DIRS=()
SKIP_DIRS_LOWER=()
SPECIAL_WORDS=()
}
teardown() {
rm -rf "$TEST_DIR"
}
# is_category_partitioned:分区形态判定
test_is_category_partitioned() {
echo '{"tv": ["menu"], "musicvideo": ["mv"], "default": ["x"]}' >"$TEST_DIR/p.json"
assert_success is_category_partitioned "$TEST_DIR/p.json"
echo '{"menu": ["Menu"]}' >"$TEST_DIR/g.json"
assert_failure is_category_partitioned "$TEST_DIR/g.json"
echo '{"tv": ["menu"], "menu": ["x"]}' >"$TEST_DIR/mixed.json"
assert_failure is_category_partitioned "$TEST_DIR/mixed.json"
}
# init_special_words:分区形态 → 词按类目查询(musicvideo 不回退 tv 词表)
test_partitioned_special_words() {
cat >"$TEST_DIR/kw.json" <<'EOF'
{"tv": ["menu", "cm"], "musicvideo": ["mv", "live"], "default": ["通用"]}
EOF
init_special_words "$TEST_DIR/kw.json"
# tv 分区词
assert_eq "menu" "$(special_word_hit tv "menu01")"
# musicvideo 分区词
assert_eq "mv" "$(special_word_hit musicvideo "mv")"
# tv 分区词不落入 musicvideo(子串 "mv" 在 musicvideo 分区,tv 词不回退)
assert_empty "$(special_word_hit musicvideo "cm")"
# default 分区词两则命中
assert_eq "通用" "$(special_word_hit tv "通用词")"
assert_eq "通用" "$(special_word_hit musicvideo "通用词")"
# 精确匹配:目录信号语义("tmp.xxx" 不命中任何词)
assert_failure special_word_exact musicvideo "tmp.xxx"
assert_success special_word_exact musicvideo "mv"
assert_success special_word_exact musicvideo "live"
}
# init_skip_dirs:分区形态 = 完整语义(不叠加内置默认)
test_partitioned_skip_dirs() {
cat >"$TEST_DIR/skips.json" <<'EOF'
{"video": ["sps", "specials"], "music": ["scans", "fonts"], "default": ["特典"]}
EOF
init_skip_dirs "$TEST_DIR/skips.json"
assert_success skip_dir_in video "sps"
# music 分区未含 sps → 不回退内置默认(分区完整语义)
assert_failure skip_dir_in music "sps"
assert_success skip_dir_in music "scans"
# default 分区回退
assert_success skip_dir_in video "特典"
assert_success skip_dir_in music "特典"
# 分区外词不命中(内置默认不叠加)
assert_failure skip_dir_in video "cds"
}
# 全局形态(旧版数组文件)保持行为:文件内容优先,空数组回退内置默认
test_legacy_skip_dirs_global() {
echo '["myspecial"]' >"$TEST_DIR/skips_legacy.json"
init_skip_dirs "$TEST_DIR/skips_legacy.json"
assert_success skip_dir_in video "myspecial"
# 非空数组文件 = 文件内容优先(不叠加内置默认)
assert_failure skip_dir_in video "sps"
}
# 全局形态空数组 → 内置默认兜底
test_legacy_skip_dirs_empty_falls_back() {
echo '[]' >"$TEST_DIR/skips_empty.json"
init_skip_dirs "$TEST_DIR/skips_empty.json"
assert_success skip_dir_in video "sps"
}
# load_special_map:分区形态(tv 分区 + default 分区回退 + 引用展开)
test_partitioned_special_map() {
cat >"$TEST_DIR/maps.json" <<'EOF'
{"tv": {"menu": ["Menu", "菜单"], "menu01": "menu"}, "default": {"cm": ["CM"]}}
EOF
load_special_map "$TEST_DIR/maps.json"
assert_eq '["Menu","菜单"]' "$(special_map_value tv "menu")"
# 分区内引用展开
assert_eq '["Menu","菜单"]' "$(special_map_value tv "menu01")"
# default 分区回退
assert_eq '["CM"]' "$(special_map_value tv "cm")"
# 无映射键 → 空
assert_empty "$(special_map_value tv "不存在")"
}
# init_season_offset:分区形态(tv 分区 + default 分区回退)
test_partitioned_season_offset() {
cat >"$TEST_DIR/offsets.json" <<'EOF'
{"tv": {"demo show": 5}, "default": {"id:123": 3}}
EOF
SEASON_OFFSET_FILE="$TEST_DIR/offsets.json" init_season_offset "$TEST_DIR/offsets.json"
assert_eq "5" "$(season_offset_get tv "demo show")"
assert_eq "3" "$(season_offset_get tv "id:123")"
# 内置默认仍可用(全局表兜底)
assert_eq "23" "$(season_offset_get tv "jujutsu kaisen")"
# 未命中 → 空
assert_empty "$(season_offset_get tv "no such show")"
}