tv-anarchy/Tests/TVAnarchyCoreTests/FilenameParserTests.swift
Natalie 7ff780fe56 feat(apps/tv-anarchy): add restart command support
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-09 21:17:10 -07:00

105 lines
4.4 KiB
Swift

import XCTest
@testable import TVAnarchyCore
/// The deterministic metadata core filename structured fields. Cases are
/// real-shaped release names (incl. the messy registry style with " " notes).
final class FilenameParserTests: XCTestCase {
func testEpisodeRelease() {
let p = FilenameParser.parse(filename: "Psych.S01E04.720p.WEB-DL.x264-GROUP")
XCTAssertEqual(p.title, "Psych")
XCTAssertEqual(p.season, 1)
XCTAssertEqual(p.episode, 4)
XCTAssertEqual(p.quality, "720p")
XCTAssertEqual(p.codec?.lowercased(), "x264")
XCTAssertEqual(p.releaseSource?.lowercased(), "web-dl")
}
func testYearKeptOutOfTitle() {
let p = FilenameParser.parse(filename: "Psych 2006 Season 6 Complete 720p AMZN WEB-DL x264")
XCTAssertEqual(p.title, "Psych")
XCTAssertEqual(p.year, 2006)
XCTAssertEqual(p.quality, "720p")
}
func testDottedNameAndHevc() {
let p = FilenameParser.parse(filename: "Twin.Peaks.S01.COMPLETE.1080p.BluRay.x265.HEVC-PSA")
XCTAssertEqual(p.title, "Twin Peaks")
XCTAssertEqual(p.season, 1)
XCTAssertEqual(p.quality, "1080p")
XCTAssertEqual(p.codec?.lowercased(), "x265")
}
func testParseFromPathStripsDirAndExt() {
let p = FilenameParser.parse(path: "/m/cartoons/Futurama/Futurama S03E01 The Honking.mp4")
XCTAssertEqual(p.title, "Futurama")
XCTAssertEqual(p.season, 3)
XCTAssertEqual(p.episode, 1)
}
func testMovieWithYearNoEpisode() {
let p = FilenameParser.parse(filename: "The.Mists.Of.Avalon.2001.DVDRip.XviD-DiVAS")
XCTAssertEqual(p.title, "The Mists Of Avalon")
XCTAssertEqual(p.year, 2001)
XCTAssertNil(p.season)
XCTAssertNil(p.episode)
XCTAssertEqual(p.codec?.lowercased(), "xvid")
}
func testEnrichResultPartialDecode() throws {
// The real graceful-degrade shape (TMDB key unset, IMDb present).
let json = #"""
{"query":"Psych","year":2006,"tmdb_error":"TMDB_API_KEY unset",
"imdb_rating":8.4,"imdb_votes":120400,"genres":["Comedy","Crime","Mystery"]}
"""#
let r = try JSONDecoder().decode(EnrichResult.self, from: Data(json.utf8))
XCTAssertEqual(r.imdb_rating, 8.4)
XCTAssertEqual(r.imdb_votes, 120400)
XCTAssertEqual(r.genres, ["Comedy", "Crime", "Mystery"])
XCTAssertNil(r.poster_url)
XCTAssertEqual(r.tmdb_error, "TMDB_API_KEY unset")
var meta = MediaMeta(path: "/m/Psych", parsed: ParsedFilename(title: "Psych", year: 2006))
meta.apply(r, at: Date(timeIntervalSince1970: 0))
XCTAssertEqual(meta.imdbRating, 8.4)
XCTAssertNil(meta.posterURL)
XCTAssertNotNil(meta.enrichedAt)
}
// MARK: TitleRefiner seam
/// The refiner is consulted ONLY when regex yields a degenerate (<2 char)
/// title, and its answer wins; a clean regex title never pays for the model.
func testRefinerConsultedOnlyForDegenerateTitles() {
final class SpyRefiner: TitleRefiner, @unchecked Sendable {
var asked: [String] = []
func refineTitle(from filename: String) -> String? {
asked.append(filename)
return "Refined Title"
}
}
let spy = SpyRefiner()
FilenameParser.refiner = spy
defer { FilenameParser.refiner = nil }
// Noise-first name: every marker sits at index 0 empty regex title.
let messy = FilenameParser.parse(filename: "2160p.x265.GROUP-RELEASE")
XCTAssertEqual(messy.title, "Refined Title")
XCTAssertEqual(spy.asked, ["2160p.x265.GROUP-RELEASE"])
let clean = FilenameParser.parse(filename: "Psych.S01E04.720p.WEB-DL.x264-GROUP")
XCTAssertEqual(clean.title, "Psych")
XCTAssertEqual(spy.asked.count, 1, "clean titles must not consult the model")
}
/// A refiner with no answer (nil) leaves the regex result intact.
func testRefinerNilAnswerKeepsRegexResult() {
struct MuteRefiner: TitleRefiner {
func refineTitle(from filename: String) -> String? { nil }
}
FilenameParser.refiner = MuteRefiner()
defer { FilenameParser.refiner = nil }
let p = FilenameParser.parse(filename: "2160p.x265.GROUP-RELEASE")
XCTAssertEqual(p.title, "2160p.x265.GROUP-RELEASE",
"with no usable title anywhere, the raw name survives")
}
}