import XCTest @testable import TVAnarchyCore /// The configurable folder→type mapping, the editable type catalog, and the /// derived adult-set. `LibraryConfig` is a process-global cache (written by /// SettingsStore), so every test resets it to the defaults in tearDown so it /// can't leak into HomeGatingTests or others. final class LibraryConfigTests: XCTestCase { private var tmp: URL! private func reset(_ folderTypes: [String: String] = [:], _ types: [LibraryType] = LibraryTypes.defaults) { LibraryConfig.update(folderTypes: folderTypes, types: types) } override func setUpWithError() throws { tmp = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true) .appendingPathComponent("libcfg-\(UUID().uuidString)", isDirectory: true) try FileManager.default.createDirectory(at: tmp, withIntermediateDirectories: true) setenv("TV_ANARCHY_STATE_DIR", tmp.path, 1) reset() } override func tearDownWithError() throws { reset() // never leak a mapping/catalog into other suites unsetenv("TV_ANARCHY_STATE_DIR") try? FileManager.default.removeItem(at: tmp) } // MARK: catalog func testDefaultCatalogLabelsAndAdultFlag() { XCTAssertTrue(LibraryConfig.isAdultType("porn")) XCTAssertFalse(LibraryConfig.isAdultType("tv")) XCTAssertEqual(LibraryConfig.label("tv"), "TV") XCTAssertEqual(LibraryConfig.label("custom"), "Custom") // capitalized fallback } func testSlug() { XCTAssertEqual(LibraryTypes.slug("Music Videos"), "music-videos") XCTAssertEqual(LibraryTypes.slug("Stand-Up!"), "stand-up") } // MARK: default (empty config) == old hardcoded behaviour func testDefaultMatchesLegacyPornBehaviour() { XCTAssertTrue(LibraryConfig.isAdult(category: "porn")) XCTAssertFalse(LibraryConfig.isAdult(category: "tv")) XCTAssertTrue(LibraryConfig.isAdult(path: "/bigdisk/_/media/porn/hentai/x.mp4")) XCTAssertFalse(LibraryConfig.isAdult(path: "/Users/q/media/tv/Psych/S01E01.mkv")) XCTAssertEqual(LibraryConfig.type(of: "tv"), "tv") // identity when unmapped } // MARK: mark an arbitrarily-named folder adult func testMappingFolderToPornMakesItAdult() { reset(["xxx": "porn", "kids": "cartoons"]) XCTAssertTrue(LibraryConfig.isAdult(category: "xxx")) XCTAssertTrue(LibraryConfig.isAdult(path: "/media/xxx/clip.mp4")) XCTAssertEqual(LibraryConfig.type(of: "xxx"), "porn") XCTAssertEqual(LibraryConfig.type(of: "kids"), "cartoons") XCTAssertFalse(LibraryConfig.isAdult(category: "kids")) XCTAssertTrue(LibraryConfig.isAdult(category: "porn")) // literal porn still adult } func testRetypingPornFolderClearsAdult() { reset(["porn": "movies"]) XCTAssertFalse(LibraryConfig.isAdult(category: "porn")) XCTAssertFalse(LibraryConfig.isAdult(path: "/media/porn/x.mp4")) XCTAssertEqual(LibraryConfig.type(of: "porn"), "movies") } // MARK: editable / expandable catalog func testCustomAdultTypeDrivesGating() { // Add a custom adult type and map a folder to it — no "porn" involved. var types = LibraryTypes.defaults types.append(LibraryType(id: "fetish", label: "Fetish", adult: true)) reset(["dungeon": "fetish"], types) XCTAssertTrue(LibraryConfig.isAdultType("fetish")) XCTAssertEqual(LibraryConfig.label("fetish"), "Fetish") XCTAssertTrue(LibraryConfig.isAdult(category: "dungeon")) XCTAssertTrue(LibraryConfig.isAdult(path: "/media/dungeon/x.mp4")) } func testEmptyCatalogFallsBackToDefaults() { reset([:], []) XCTAssertEqual(LibraryConfig.types.map(\.id), LibraryTypes.defaults.map(\.id)) } // MARK: the cache is owned by SettingsStore func testSaveAndLoadSyncTheCache() { var types = LibraryTypes.defaults types.append(LibraryType(id: "asmr", label: "ASMR", adult: true)) SettingsStore.save(AppSettings(folderTypes: ["whispers": "asmr"], libraryTypes: types)) XCTAssertTrue(LibraryConfig.isAdult(category: "whispers")) XCTAssertEqual(LibraryConfig.label("asmr"), "ASMR") // load() re-syncs from disk (a fresh launch). reset() _ = SettingsStore.load() XCTAssertTrue(LibraryConfig.isAdult(category: "whispers")) } }