Extract all itinerary reordering logic from ItineraryTableViewController into ItineraryReorderingLogic.swift for testability. Key changes: - Add flattenDays, dayNumber, travelRow, simulateMove pure functions - Add calculateSortOrder with proper region classification (before/after games) - Add computeValidDestinationRowsProposed with simulation+validation pattern - Add coordinate space conversion helpers (proposedToOriginal, originalToProposed) - Fix DragZones coordinate space mismatch (was mixing proposed/original indices) - Add comprehensive documentation of coordinate space conventions Test coverage includes: - Row flattening order and semantic travel model - Sort order calculation for before/after games regions - Travel constraints validation - DragZones coordinate space correctness - Coordinate conversion helpers - Edge cases (empty days, multi-day trips) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
68 lines
2.6 KiB
Swift
68 lines
2.6 KiB
Swift
//
|
|
// ItineraryEdgeCaseTests.swift
|
|
// SportsTimeTests
|
|
//
|
|
// Tests for edge cases in itinerary display and manipulation.
|
|
//
|
|
|
|
import XCTest
|
|
@testable import SportsTime
|
|
|
|
private typealias H = ItineraryTestHelpers
|
|
|
|
final class ItineraryEdgeCaseTests: XCTestCase {
|
|
|
|
private let testDate = H.testDate
|
|
|
|
// MARK: - Empty/Minimal Day Tests
|
|
|
|
func test_emptyDay_onlyShowsHeader() {
|
|
// Given: A day with no games and no items
|
|
let dayData = ItineraryDayData(id: 1, dayNumber: 1, date: testDate, games: [], items: [], travelBefore: nil)
|
|
|
|
let controller = ItineraryTableViewController(style: .plain)
|
|
controller.reloadData(days: [dayData], travelValidRanges: [:])
|
|
|
|
let rowCount = controller.tableView(controller.tableView, numberOfRowsInSection: 0)
|
|
XCTAssertEqual(rowCount, 1, "Empty day should only have header row")
|
|
}
|
|
|
|
func test_restDay_withTravelBefore_onlyShowsHeader() {
|
|
// Given: A rest day with travelBefore set (legacy field)
|
|
// Semantic model: travelBefore is IGNORED - travel must be in items to appear
|
|
let travel = H.makeTravelSegment(from: "Chicago", to: "Detroit")
|
|
let dayData = ItineraryDayData(id: 1, dayNumber: 1, date: testDate, games: [], items: [], travelBefore: travel)
|
|
|
|
let controller = ItineraryTableViewController(style: .plain)
|
|
controller.reloadData(days: [dayData], travelValidRanges: [:])
|
|
|
|
let rowCount = controller.tableView(controller.tableView, numberOfRowsInSection: 0)
|
|
XCTAssertEqual(rowCount, 1, "travelBefore is ignored - only header should appear")
|
|
}
|
|
|
|
func test_singleGameDay_showsHeaderAndGame() {
|
|
// Given: A day with one game
|
|
let games = [H.makeRichGame(city: "Detroit", hour: 19)]
|
|
let dayData = ItineraryDayData(id: 1, dayNumber: 1, date: testDate, games: games, items: [], travelBefore: nil)
|
|
|
|
let controller = ItineraryTableViewController(style: .plain)
|
|
controller.reloadData(days: [dayData], travelValidRanges: [:])
|
|
|
|
let rowCount = controller.tableView(controller.tableView, numberOfRowsInSection: 0)
|
|
XCTAssertEqual(rowCount, 2, "Day with one game should have 2 rows: header + games")
|
|
}
|
|
|
|
// MARK: - Multi-Day Trip Tests
|
|
|
|
func test_multiDayTrip_allDaysRepresented() {
|
|
// Given: A 5-day trip
|
|
let days = H.makeDays(count: 5)
|
|
|
|
let controller = ItineraryTableViewController(style: .plain)
|
|
controller.reloadData(days: days, travelValidRanges: [:])
|
|
|
|
let rowCount = controller.tableView(controller.tableView, numberOfRowsInSection: 0)
|
|
XCTAssertEqual(rowCount, 5, "5-day trip with empty days should have 5 header rows")
|
|
}
|
|
}
|