import XCTest @testable import iPX final class OfflineTests: XCTestCase { private var dir: URL! override func setUp() { dir = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) } override func tearDown() { try? FileManager.default.removeItem(at: dir) UserDefaults.standard.removeObject(forKey: "ipx.outbox") } private func tempFile(_ bytes: Int = 4) -> URL { let u = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) try? Data(repeating: 7, count: bytes).write(to: u) return u } func testOnlyThePagesTwoKindsOfFileAreKept() { XCTAssertTrue(EpisodeStore.isKeepable("/media/42")) XCTAssertTrue(EpisodeStore.isKeepable("/media/42/deadair")) XCTAssertFalse(EpisodeStore.isKeepable("/media/42/deadair.m3u8")) XCTAssertFalse(EpisodeStore.isKeepable("/media/../../etc/passwd"), "a path names a place on disk") XCTAssertFalse(EpisodeStore.isKeepable("/api/feeds")) } func testAKeptFileIsFoundAgainAfterARelaunch() throws { var store = EpisodeStore(directory: dir) try store.add("/media/42", moving: tempFile(10), ext: "mp3") XCTAssertEqual(store.paths, ["/media/42"]) XCTAssertEqual(store.entries["/media/42"]?.bytes, 10) let again = EpisodeStore(directory: dir) XCTAssertEqual(again.fileURL(for: "/media/42")?.lastPathComponent, "media-42.mp3") } func testAFileTheSystemTookBackIsNotKept() throws { var store = EpisodeStore(directory: dir) try store.add("/media/7/deadair", moving: tempFile(), ext: "m4a") try FileManager.default.removeItem(at: store.fileURL(for: "/media/7/deadair")!) XCTAssertNil(EpisodeStore(directory: dir).fileURL(for: "/media/7/deadair")) } func testRemovingTakesTheFileToo() throws { var store = EpisodeStore(directory: dir) try store.add("/media/1", moving: tempFile(), ext: "mp3") let file = store.fileURL(for: "/media/1")! store.remove("/media/1") XCTAssertFalse(FileManager.default.fileExists(atPath: file.path)) XCTAssertTrue(store.paths.isEmpty) } func testTheTypeIsTakenFromTheServersAnswer() { XCTAssertEqual(EpisodeStore.ext(forMime: "audio/mpeg"), "mp3") XCTAssertEqual(EpisodeStore.ext(forMime: "audio/x-m4a"), "m4a") XCTAssertEqual(EpisodeStore.ext(forMime: "audio/mp4; codecs=mp4a.40.2"), "m4a") XCTAssertEqual(EpisodeStore.ext(forMime: nil), "mp3") } func testANewerPlaceReplacesTheOlderAndOtherWritesAreLeftOut() { Outbox.add(path: "/api/entries/f/g/position", json: ["secs": 10]) Outbox.add(path: "/api/entries/f/g/flags", json: ["read": true]) Outbox.add(path: "/api/entries/f/g/position", json: ["secs": 90]) Outbox.add(path: "/api/feeds", json: ["url": "x"]) let all = Outbox.pending XCTAssertEqual(all.map(\.path), ["/api/entries/f/g/flags", "/api/entries/f/g/position"]) XCTAssertEqual(String(data: all[1].json, encoding: .utf8), #"{"secs":90}"#) } }