Files
MeBox/internal/service/episode_metadata_cleanup_test.go
T
truewhile b0fe40142a Rebrand MMTL to MeBox (name, logo, Docker image) (#17)
* Rebrand MMTL to MeBox across codebase and assets

Rename the project display name, Go module path, environment variable
prefix (MEBOX_*), Docker image references, and UI branding from MMTL/mmtl
to MeBox/mebox. Replace logo assets with the new MeBox icon and keep
legacy SQLite migration support for existing mmtl.db deployments.

Co-authored-by: truewhile <truewhile@users.noreply.github.com>

* Fix logo icons: use cube-only crop without truncated text

Previous icon generation cropped too much of the source image, including
partial MeBox wordmark text that was cut off in square icon containers.
Regenerate logo-64/192/512, favicon, and SVG from cube-only region.

Co-authored-by: truewhile <truewhile@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: truewhile <truewhile@users.noreply.github.com>
2026-09-02 16:26:28 +08:00

96 lines
3.7 KiB
Go

package service
import (
"testing"
"go.uber.org/zap"
"gorm.io/gorm"
"github.com/truewhile/MeBox/internal/model"
"github.com/truewhile/MeBox/internal/repository"
)
func newCleanupTestContainer(t *testing.T) (*Container, *gorm.DB) {
t.Helper()
db := newServiceTestDB(t, &model.Media{}, &model.Setting{})
if sqlDB, err := db.DB(); err == nil {
sqlDB.SetMaxOpenConns(1)
}
repos := repository.New(db)
return &Container{Repo: repos, Log: zap.NewNop()}, db
}
func TestShowDirFromEpisodePath(t *testing.T) {
cases := []struct{ in, want string }{
{`/tv/国漫/遮天 (2023)/Season 01/遮天 - S01E01.mkv`, `/tv/国漫/遮天 (2023)`},
{`cloud://drive/国漫/武神主宰 (2020)/S01/武神主宰 - S01E05.mkv`, `cloud://drive/国漫/武神主宰 (2020)`},
{`/tv/某剧/第 2 季/某剧 第05集.mkv`, `/tv/某剧`},
// 无季文件夹: 取父目录。
{`/tv/某剧/某剧 - S01E01.mkv`, `/tv/某剧`},
}
for _, tc := range cases {
if got := showDirFromEpisodePath(tc.in); got != tc.want {
t.Errorf("showDirFromEpisodePath(%q) = %q, want %q", tc.in, got, tc.want)
}
}
}
// TestNormalizePollutedEpisodeMetadata 验证: 被单集 id/名污染的剧组被清洗,
// 干净的剧组不动, 且迁移幂等(写入标记后再跑不重复处理)。
func TestNormalizePollutedEpisodeMetadata(t *testing.T) {
container, db := newCleanupTestContainer(t)
rows := []model.Media{
// 污染组: 同一部剧每集 tmdb 不同、original_name 是单集名 → 应清洗。
{Base: model.Base{ID: "z1"}, LibraryID: "lib", SeasonNum: 1, EpisodeNum: 1, TMDbID: 4375419, OriginalName: "九龙拉棺", ScrapeStatus: "matched", Path: `/tv/国漫/遮天 (2023)/Season 01/遮天 - S01E01.mkv`},
{Base: model.Base{ID: "z2"}, LibraryID: "lib", SeasonNum: 1, EpisodeNum: 2, TMDbID: 4375461, OriginalName: "星空古路", ScrapeStatus: "matched", Path: `/tv/国漫/遮天 (2023)/Season 01/遮天 - S01E02.mkv`},
// 干净组: 全组共享同一整剧 tmdb、original_name 一致 → 不动。
{Base: model.Base{ID: "c1"}, LibraryID: "lib", SeasonNum: 1, EpisodeNum: 1, TMDbID: 1234, OriginalName: "Clean Show", ScrapeStatus: "matched", Path: `/tv/欧美剧/Clean Show (2020)/Season 01/Clean Show - S01E01.mkv`},
{Base: model.Base{ID: "c2"}, LibraryID: "lib", SeasonNum: 1, EpisodeNum: 2, TMDbID: 1234, OriginalName: "Clean Show", ScrapeStatus: "matched", Path: `/tv/欧美剧/Clean Show (2020)/Season 01/Clean Show - S01E02.mkv`},
}
for i := range rows {
if err := db.Create(&rows[i]).Error; err != nil {
t.Fatalf("create %s: %v", rows[i].ID, err)
}
}
cleaned, err := container.NormalizePollutedEpisodeMetadata(t.Context())
if err != nil {
t.Fatalf("normalize: %v", err)
}
if cleaned != 2 {
t.Fatalf("cleaned = %d, want 2 (only the polluted show)", cleaned)
}
load := func(id string) model.Media {
var m model.Media
if err := db.First(&m, "id = ?", id).Error; err != nil {
t.Fatalf("load %s: %v", id, err)
}
return m
}
// 污染组被清空字段并重置 pending。
for _, id := range []string{"z1", "z2"} {
m := load(id)
if m.TMDbID != 0 || m.OriginalName != "" || m.ScrapeStatus != "pending" {
t.Fatalf("polluted row %s not cleaned: %+v", id, m)
}
}
// 干净组保持不变。
for _, id := range []string{"c1", "c2"} {
m := load(id)
if m.TMDbID != 1234 || m.OriginalName != "Clean Show" || m.ScrapeStatus != "matched" {
t.Fatalf("clean row %s should be untouched: %+v", id, m)
}
}
// 幂等: 第二次运行不再处理(已写标记)。
cleaned2, err := container.NormalizePollutedEpisodeMetadata(t.Context())
if err != nil {
t.Fatalf("normalize again: %v", err)
}
if cleaned2 != 0 {
t.Fatalf("second run should be a no-op, cleaned=%d", cleaned2)
}
}