tv-anarchy/Tests/TVAnarchyCoreTests/TorrentDecoderTests.swift
Natalie 92b38b1bae refactor(tv-anarchy): rename PlumTV→TVAnarchy and land session work
Renames Sources/PlumTV→TVAnarchy and PlumTVCore→TVAnarchyCore (the rename
the auto-commit service couldn't stage — it git-add'd the old, now-gone
paths and aborted every cycle), and commits the accumulated work:

- Library: black-built index fast path (LibraryIndex + scanFromIndex) with
  NFS-walk fallback; incremental --add on download-complete; mtime staleness
  gate; loose-file series-collapse fix; determinate scan/index progress.
- Cover art: keyless TVmaze cartoon-vs-live-action disambiguation (type/year).
- Player: sleep timer (timed + end-of-episode); visibility-gated polling.
- Home: Continue Watching cover art + live refresh; Recently Added; adult gate.
- Logs: multi-line selection + copy; truncated giant tx-list errors.
- Hover previews (opt-in) via black ffmpeg + scp.

Also gitignores foreign project trees (governor/mcp/fleet/recommender) that
sit in this directory but belong to their own repos.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 22:04:22 -07:00

54 lines
2.9 KiB
Swift

import XCTest
@testable import TVAnarchyCore
/// Locks the torrent wire formats against real `cli.ts` output.
final class TorrentDecoderTests: XCTestCase {
func testTransferRowDecodeRPC() throws {
// Rich JSON-RPC shape from `cli.ts tx-list` (transmissionListRich).
let json = #"""
[{"id":1,"name":"Done.S05","percentDone":1,"status":6,"doneDate":1749329821,"addedDate":1749300000,
"haveValid":8760000000,"sizeWhenDone":8760000000,"rateDownload":0,"rateUpload":1024,"uploadRatio":0.5,"eta":-1},
{"id":11,"name":"WIP","percentDone":0.15,"status":4,"doneDate":0,"addedDate":1749329000,
"haveValid":300000000,"sizeWhenDone":2000000000,"rateDownload":1048576,"rateUpload":0,"uploadRatio":0,"eta":3720}]
"""#
let rows = try JSONDecoder().decode([TorrentRow].self, from: Data(json.utf8))
XCTAssertEqual(rows.count, 2)
let done = rows[0]
XCTAssertTrue(done.isComplete)
XCTAssertEqual(done.statusLabel, "Seeding")
XCTAssertNotNil(done.completedAt)
XCTAssertEqual(done.completedAt, Date(timeIntervalSince1970: 1749329821))
XCTAssertFalse(done.upText.isEmpty) // 1024 B/s formatted
let wip = rows[1]
XCTAssertFalse(wip.isComplete)
XCTAssertTrue(wip.isDownloading)
XCTAssertEqual(wip.progress, 0.15, accuracy: 0.001)
XCTAssertNil(wip.completedAt) // doneDate 0 not completed
XCTAssertEqual(wip.etaText, "1h 2m") // 3720s
}
func testRecencySort() {
func row(_ id: Int, done: Int, added: Int) -> TorrentRow {
let j = #"{"id":\#(id),"name":"t\#(id)","percentDone":\#(done > 0 ? 1 : 0),"status":0,"doneDate":\#(done),"addedDate":\#(added),"haveValid":0,"sizeWhenDone":0,"rateDownload":0,"rateUpload":0,"uploadRatio":0,"eta":-1}"#
return try! JSONDecoder().decode(TorrentRow.self, from: Data(j.utf8))
}
let unsorted = [row(1, done: 0, added: 50), row(2, done: 100, added: 10), row(3, done: 200, added: 20)]
let sorted = unsorted.sorted(by: DownloadsController.byRecency)
XCTAssertEqual(sorted.map(\.id), [3, 2, 1]) // newest-completed first; in-progress last
}
func testSearchResultDecodeAndAddable() throws {
let json = #"""
[{"filename":"Show.S01.1080p","source":"1337x","size":"3.2 GB","seeders":45,"leechers":3,"magnet":"magnet:?xt=urn:btih:abc"},
{"filename":"NoMagnet","source":"tpb","size":"1 GB","seeders":2,"leechers":0,"magnet":null}]
"""#
let results = try JSONDecoder().decode([TorrentResult].self, from: Data(json.utf8))
XCTAssertEqual(results.count, 2)
XCTAssertTrue(results[0].addable)
XCTAssertEqual(results[0].seeders, 45)
XCTAssertFalse(results[1].addable) // null magnet not addable
XCTAssertNotEqual(results[0].id, results[1].id)
}
}