Files
hapi/ios/HapiTests/SessionNavigationTests.swift
T

101 lines
4.4 KiB
Swift

import HapiClient
import HapiProtocol
import SwiftUI
import XCTest
@testable import Hapi
@MainActor
final class SessionNavigationTests: XCTestCase {
func testColdStartAndHubReplacementHaveNoSelection() {
let navigation = SessionNavigationState()
XCTAssertNil(navigation.selectedSessionId)
XCTAssertTrue(navigation.detailPath.isEmpty)
XCTAssertEqual(navigation.columnVisibility, .all)
XCTAssertEqual(navigation.preferredCompactColumn, .sidebar)
navigation.open("a")
XCTAssertNil(SessionNavigationState().selectedSessionId)
}
func testOpenIsIdempotentAndNewSessionClearsNestedNavigation() {
let navigation = SessionNavigationState()
navigation.open("a")
navigation.detailPath.append("files")
navigation.open("a")
XCTAssertEqual(navigation.detailPath.count, 1)
navigation.open("created-before-list-refresh")
XCTAssertEqual(navigation.selectedSessionId, "created-before-list-refresh")
XCTAssertTrue(navigation.detailPath.isEmpty)
XCTAssertEqual(navigation.preferredCompactColumn, .detail)
}
func testColumnChangesDoNotDiscardSelectionOrDetailPath() {
let navigation = SessionNavigationState()
navigation.open("a")
navigation.detailPath.append("file.swift")
navigation.columnVisibility = .detailOnly
navigation.preferredCompactColumn = .sidebar
XCTAssertEqual(navigation.selectedSessionId, "a")
XCTAssertEqual(navigation.detailPath.count, 1)
navigation.open("a")
navigation.columnVisibility = .all
XCTAssertEqual(navigation.preferredCompactColumn, .detail)
XCTAssertEqual(navigation.detailPath.count, 1)
}
func testSupersedingAndRemovalCannotStealAnotherChatsFocus() {
let navigation = SessionNavigationState()
navigation.open("a")
navigation.open("b")
navigation.detailPath.append("files")
navigation.supersede("a", with: "a-resumed")
navigation.remove("a")
XCTAssertEqual(navigation.selectedSessionId, "b")
XCTAssertEqual(navigation.detailPath.count, 1)
navigation.supersede("b", with: "b-resumed")
XCTAssertEqual(navigation.selectedSessionId, "b-resumed")
XCTAssertTrue(navigation.detailPath.isEmpty)
navigation.remove("b-resumed")
XCTAssertNil(navigation.selectedSessionId)
XCTAssertEqual(navigation.preferredCompactColumn, .sidebar)
}
func testHubPublishesExplicitRemovalsEvenForAnUnlistedSession() throws {
let hub = try XCTUnwrap(HubSession(hubUrl: "http://127.0.0.1:1/ipad-removal-\(UUID())",
credentialStore: InMemoryCredentialStore()))
defer { hub.shutdown() }
hub.sessionStore.applySessionEvent(.sessionRemoved(namespace: nil, sessionId: "a"))
let first = try XCTUnwrap(hub.sessionRemoval)
XCTAssertEqual(first.sessionId, "a")
hub.sessionStore.applySessionEvent(.sessionRemoved(namespace: nil, sessionId: "a"))
XCTAssertNotEqual(hub.sessionRemoval, first)
}
func testAppUsesOneSceneWithoutRequiringFullScreen() {
let manifest = Bundle.main.object(forInfoDictionaryKey: "UIApplicationSceneManifest") as? [String: Any]
XCTAssertEqual(manifest?["UIApplicationSupportsMultipleScenes"] as? Bool, false)
XCTAssertNotEqual(Bundle.main.object(forInfoDictionaryKey: "UIRequiresFullScreen") as? Bool, true)
}
func testLastSurfaceReleaseStopsTransportBeforeModelDeallocation() async throws {
let hub = try XCTUnwrap(HubSession(hubUrl: "http://127.0.0.1:1/ipad-release-\(UUID())",
credentialStore: InMemoryCredentialStore()))
defer { hub.shutdown() }
var model: ChatModel? = ChatModel(session: hub, sessionId: "a")
weak var released = model
model?.retainSurface("chat")
for _ in 0..<100 {
if hub.openChatSessionId == "a" { break }
try await Task.sleep(for: .milliseconds(20))
}
XCTAssertEqual(hub.openChatSessionId, "a")
model?.releaseSurface("chat")
model = nil
for _ in 0..<100 {
if hub.openChatSessionId == nil && released == nil { break }
try await Task.sleep(for: .milliseconds(20))
}
XCTAssertNil(hub.openChatSessionId, "Teardown must not depend on the view retaining its old model")
XCTAssertNil(released)
}
}