Normalizza il periodo nel backend quando l'app invia "Q1" via cable, così advance_period aggiorna regia e overlay; rimuove i controlli cronometro dalla regia e rende più tollerante il decode iOS al resume sessione. Co-authored-by: Cursor <cursoragent@cursor.com>
238 lines
7.9 KiB
Swift
238 lines
7.9 KiB
Swift
import XCTest
|
|
@testable import MatchLiveTv
|
|
|
|
final class ScoreActionDecodeTests: XCTestCase {
|
|
func testDecodesScoreActionResponse() throws {
|
|
let json = """
|
|
{
|
|
"id": "821ddb81-9dc2-466a-9ad5-2555e78f4653",
|
|
"match_id": "e887ce1d-10ee-4680-8323-79bb8f11e0aa",
|
|
"status": "live",
|
|
"platform": "matchlivetv",
|
|
"score": {
|
|
"type": "score_update",
|
|
"board_type": "volley",
|
|
"home_sets": 0,
|
|
"away_sets": 0,
|
|
"home_points": 1,
|
|
"away_points": 0,
|
|
"current_set": 1,
|
|
"set_partials": [],
|
|
"timeout_home": false,
|
|
"timeout_away": false,
|
|
"period": null,
|
|
"data": {}
|
|
},
|
|
"set_won": false,
|
|
"match_won": false,
|
|
"winner": null
|
|
}
|
|
""".data(using: .utf8)!
|
|
let dto = try ApiInstant.decoder.decode(StreamSessionDto.self, from: json)
|
|
let score = try XCTUnwrap(dto.score?.toDomain())
|
|
XCTAssertEqual(score.homePoints, 1)
|
|
XCTAssertEqual(score.boardType, "volley")
|
|
}
|
|
|
|
func testDecodesCloseSetResponseWithPartials() throws {
|
|
let json = """
|
|
{
|
|
"id": "821ddb81-9dc2-466a-9ad5-2555e78f4653",
|
|
"match_id": "e887ce1d-10ee-4680-8323-79bb8f11e0aa",
|
|
"status": "live",
|
|
"platform": "matchlivetv",
|
|
"score": {
|
|
"type": "score_update",
|
|
"board_type": "volley",
|
|
"home_sets": 1,
|
|
"away_sets": 0,
|
|
"home_points": 0,
|
|
"away_points": 0,
|
|
"current_set": 2,
|
|
"set_partials": [{ "set": 1, "home": 25, "away": 18 }],
|
|
"timeout_home": false,
|
|
"timeout_away": false
|
|
},
|
|
"set_won": true,
|
|
"match_won": false,
|
|
"winner": "home"
|
|
}
|
|
""".data(using: .utf8)!
|
|
let dto = try ApiInstant.decoder.decode(StreamSessionDto.self, from: json)
|
|
let score = try XCTUnwrap(dto.score?.toDomain())
|
|
XCTAssertEqual(score.currentSet, 2)
|
|
XCTAssertEqual(score.setPartials.count, 1)
|
|
XCTAssertEqual(score.setPartials[0].home, 25)
|
|
XCTAssertEqual(score.setPartials[0].away, 18)
|
|
}
|
|
|
|
func testDecodesBasketAdvancePeriodResponse() throws {
|
|
let json = """
|
|
{
|
|
"id": "821ddb81-9dc2-466a-9ad5-2555e78f4653",
|
|
"match_id": "e887ce1d-10ee-4680-8323-79bb8f11e0aa",
|
|
"status": "live",
|
|
"platform": "matchlivetv",
|
|
"score": {
|
|
"type": "score_update",
|
|
"board_type": "basket",
|
|
"home_points": 12,
|
|
"away_points": 10,
|
|
"current_set": 1,
|
|
"set_partials": [],
|
|
"timeout_home": false,
|
|
"timeout_away": false,
|
|
"period": "Q2",
|
|
"clock_secs": 600,
|
|
"clock_running": false,
|
|
"data": { "home_score": 12, "away_score": 10, "period": 2, "clock_secs": 600, "clock_running": false, "overtime": false }
|
|
},
|
|
"set_won": false,
|
|
"match_won": false,
|
|
"winner": null
|
|
}
|
|
""".data(using: .utf8)!
|
|
let dto = try ApiInstant.decoder.decode(StreamSessionDto.self, from: json)
|
|
let score = try XCTUnwrap(dto.score?.toDomain())
|
|
XCTAssertEqual(score.periodLabel, "Q2")
|
|
XCTAssertEqual(score.period, 2)
|
|
XCTAssertEqual(score.clockSecs, 600)
|
|
XCTAssertFalse(score.clockRunning)
|
|
}
|
|
|
|
func testDecodesResumeSessionDetailWithBasketScore() throws {
|
|
let json = """
|
|
{
|
|
"id": "420fd5b9-b2ad-45af-9c1d-569c654866f8",
|
|
"match_id": "e887ce1d-10ee-4680-8323-79bb8f11e0aa",
|
|
"status": "paused",
|
|
"platform": "matchlivetv",
|
|
"rtmp_ingest_url": "rtmp://localhost:1935/live/key",
|
|
"hls_playback_url": "http://localhost:8888/live/key/index.m3u8",
|
|
"watch_page_url": "http://localhost:3000/live/abc",
|
|
"share_url": "http://localhost:3000/live/abc",
|
|
"youtube_watch_url": null,
|
|
"youtube_broadcast_id": null,
|
|
"youtube_ready": false,
|
|
"privacy_status": "unlisted",
|
|
"quality_preset": "720p_30_2.5mbps",
|
|
"target_bitrate": 2500000,
|
|
"started_at": "2026-06-19T10:30:00.000Z",
|
|
"disconnection_count": 0,
|
|
"score": {
|
|
"type": "score_update",
|
|
"board_type": "basket",
|
|
"home_sets": 0,
|
|
"away_sets": 0,
|
|
"home_points": 42,
|
|
"away_points": 38,
|
|
"current_set": 1,
|
|
"set_partials": [],
|
|
"timeout_home": false,
|
|
"timeout_away": false,
|
|
"period": "Q3",
|
|
"clock_secs": 312,
|
|
"clock_running": true,
|
|
"data": {
|
|
"home_score": 42,
|
|
"away_score": 38,
|
|
"period": 3,
|
|
"clock_secs": 312,
|
|
"clock_running": true,
|
|
"overtime": false
|
|
}
|
|
},
|
|
"devices": [
|
|
{
|
|
"type": "device_state",
|
|
"battery": 85,
|
|
"network": "wifi",
|
|
"bitrate": 2100,
|
|
"fps": 30,
|
|
"status": "paused"
|
|
}
|
|
]
|
|
}
|
|
""".data(using: .utf8)!
|
|
let dto = try ApiInstant.decoder.decode(StreamSessionDto.self, from: json)
|
|
let score = try XCTUnwrap(dto.score?.toDomain())
|
|
XCTAssertEqual(score.homePoints, 42)
|
|
XCTAssertEqual(score.periodLabel, "Q3")
|
|
XCTAssertEqual(dto.status, "paused")
|
|
}
|
|
|
|
func testDecodesBasketScoreWithNumericTimeouts() throws {
|
|
let json = """
|
|
{
|
|
"id": "a",
|
|
"match_id": "b",
|
|
"status": "paused",
|
|
"platform": "matchlivetv",
|
|
"score": {
|
|
"board_type": "basket",
|
|
"home_points": 10,
|
|
"away_points": 8,
|
|
"period": "Q2",
|
|
"clock_secs": 600,
|
|
"clock_running": false,
|
|
"timeout_home": 0,
|
|
"timeout_away": 0,
|
|
"data": { "home_score": 10, "away_score": 8, "period": 2, "overtime": false }
|
|
}
|
|
}
|
|
""".data(using: .utf8)!
|
|
let dto = try ApiInstant.decoder.decode(StreamSessionDto.self, from: json)
|
|
XCTAssertEqual(dto.score?.toDomain().homePoints, 10)
|
|
}
|
|
|
|
func testDecodesBasketScoreWithStringPeriodInData() throws {
|
|
let json = """
|
|
{
|
|
"id": "a",
|
|
"match_id": "b",
|
|
"status": "paused",
|
|
"platform": "matchlivetv",
|
|
"score": {
|
|
"board_type": "basket",
|
|
"home_points": 10,
|
|
"away_points": 8,
|
|
"period": "Q2",
|
|
"clock_secs": 600,
|
|
"clock_running": false,
|
|
"data": { "period": "2", "home_score": 10, "away_score": 8, "overtime": false }
|
|
}
|
|
}
|
|
""".data(using: .utf8)!
|
|
let dto = try ApiInstant.decoder.decode(StreamSessionDto.self, from: json)
|
|
XCTAssertEqual(dto.score?.toDomain().period, 2)
|
|
}
|
|
|
|
func testDecodesCableAdvancePeriodPayload() throws {
|
|
let json = """
|
|
{
|
|
"type": "score_update",
|
|
"board_type": "basket",
|
|
"home_points": 0,
|
|
"away_points": 4,
|
|
"period": "Q2",
|
|
"clock_secs": 600,
|
|
"clock_running": false,
|
|
"data": {
|
|
"period": 2,
|
|
"home_score": 0,
|
|
"away_score": 4,
|
|
"clock_secs": 600,
|
|
"clock_running": false,
|
|
"overtime": false
|
|
}
|
|
}
|
|
""".data(using: .utf8)!
|
|
let score = ScoreState.fromCablePayload(try JSONSerialization.jsonObject(with: json) as! [String: Any])
|
|
XCTAssertEqual(score.period, 2)
|
|
XCTAssertEqual(score.periodLabel, "Q2")
|
|
XCTAssertEqual(score.homePoints, 0)
|
|
XCTAssertEqual(score.awayPoints, 4)
|
|
XCTAssertGreaterThan(score.progressKey(), ScoreState(boardType: "basket", period: 1, periodLabel: "Q1").progressKey())
|
|
}
|
|
}
|