package layout import "testing" func TestSanitizeComponent(t *testing.T) { tests := []struct { in, want string }{ {"Дюна Часть вторая", "Дюна Часть вторая"}, {"a/b\\c", "a b c"}, {"..", ""}, {"../../etc/passwd", "etc passwd"}, {" trailing. ", "trailing"}, {"name: sub*title?", "name sub title"}, {"multi space", "multi space"}, {"tab\tand\nnewline", "tab and newline"}, {".hidden", "hidden"}, {"ac|d\"e", "a b c d e"}, } for _, tt := range tests { if got := sanitizeComponent(tt.in); got != tt.want { t.Errorf("sanitizeComponent(%q) = %q, want %q", tt.in, got, tt.want) } } } func TestTitleYear(t *testing.T) { got, err := titleYear("The Matrix", 1999) if err != nil || got != "The Matrix (1999)" { t.Errorf("got %q, %v", got, err) } got, err = titleYear("No Year", 0) if err != nil || got != "No Year" { t.Errorf("got %q, %v", got, err) } if _, err := titleYear("///", 2000); err == nil { t.Error("want error for empty title after sanitize") } } func TestFolderName(t *testing.T) { if got := folderName("Dune (2024)", "tmdbid-693134"); got != "Dune (2024) [tmdbid-693134]" { t.Errorf("got %q", got) } if got := folderName("Dune (2024)", ""); got != "Dune (2024)" { t.Errorf("got %q", got) } } func TestFolderBase(t *testing.T) { tests := []struct { in, want string }{ {"Фарго (2014) [tvdbid-269613]", "Фарго (2014)"}, // текущий тег {"Fargo (2017) [tmdbid-123]", "Fargo (2017)"}, // чужой/старый тег снимается так же {"No Tag (2020)", "No Tag (2020)"}, // без тега — как есть {"Bare Name", "Bare Name"}, // без года и тега {"Weird [not a tag", "Weird [not a tag"}, // незакрытый — не трогаем {"[tvdbid-1]", "[tvdbid-1]"}, // нет " [" с пробелом — не тег {"Movie (2020) [edition-Director's Cut]", "Movie (2020)"}, // снимается любой хвостовой [...] } for _, tt := range tests { if got := folderBase(tt.in); got != tt.want { t.Errorf("folderBase(%q) = %q, want %q", tt.in, got, tt.want) } } } func TestEpisodeStem(t *testing.T) { if got := episodeStem("Fargo (2015)", 2, 1, 0); got != "Fargo (2015) S02E01" { t.Errorf("got %q", got) } if got := episodeStem("Show", 1, 5, 6); got != "Show S01E05-E06" { t.Errorf("got %q", got) } } func TestSeasonFolder(t *testing.T) { if got := seasonFolder(0); got != "Season 00" { t.Errorf("got %q", got) } if got := seasonFolder(12); got != "Season 12" { t.Errorf("got %q", got) } } func TestSubtitleSuffix(t *testing.T) { if got := subtitleSuffix("ru", nil); got != ".ru" { t.Errorf("got %q", got) } if got := subtitleSuffix("RU", []string{"forced"}); got != ".ru.forced" { t.Errorf("got %q", got) } if got := subtitleSuffix("", nil); got != "" { t.Errorf("got %q", got) } } func TestUnderRoot(t *testing.T) { if !underRoot("/srv/media/movies", "/srv/media/movies/Film (2020)/Film (2020).mkv") { t.Error("want true for nested path") } if underRoot("/srv/media/movies", "/srv/media/movies") { t.Error("root itself is not a valid target") } if underRoot("/srv/media/movies", "/srv/media/series/x.mkv") { t.Error("sibling dir must be rejected") } if underRoot("/srv/media/movies", "/srv/media/movies/../series/x.mkv") { t.Error("traversal must be rejected after clean") } }