pi-remote-ios/Tests/CoreTests/ThemeTests.swift

170 lines
7.3 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ThemeTests.swift
// Unit tests for TerminalTheme, ThemeColor, ThemeStore, and FontStore.
//
// These tests exercise built-in theme validity and store selection logic.
// No UIKit rendering or simulator is required for the pure-struct tests;
// ThemeStore / FontStore tests require @MainActor and a run loop.
import XCTest
@testable import piRemote
final class ThemeTests: XCTestCase {
// =========================================================================
// MARK: 1. TerminalTheme built-in theme invariants
// =========================================================================
func testDark_hasExactly16AnsiColors() {
XCTAssertEqual(TerminalTheme.dark.ansiColors.count, 16,
".dark must have exactly 16 ANSI color entries")
}
func testGitHub_hasExactly16AnsiColors() {
XCTAssertEqual(TerminalTheme.github.ansiColors.count, 16,
".github must have exactly 16 ANSI color entries")
}
// =========================================================================
// MARK: 2. ThemeColor values are in the 0255 range
// =========================================================================
// ThemeColor stores UInt8 components, so they are structurally bounded to
// 0255. These tests make the contract explicit and guard against future
// refactors that might widen the type.
func testDark_allAnsiColorComponents_inRange() {
for (index, color) in TerminalTheme.dark.ansiColors.enumerated() {
assertColorInRange(color, label: "dark[\(index)]")
}
assertColorInRange(TerminalTheme.dark.foreground, label: "dark.foreground")
assertColorInRange(TerminalTheme.dark.background, label: "dark.background")
assertColorInRange(TerminalTheme.dark.cursor, label: "dark.cursor")
}
func testGitHub_allAnsiColorComponents_inRange() {
for (index, color) in TerminalTheme.github.ansiColors.enumerated() {
assertColorInRange(color, label: "github[\(index)]")
}
assertColorInRange(TerminalTheme.github.foreground, label: "github.foreground")
assertColorInRange(TerminalTheme.github.background, label: "github.background")
assertColorInRange(TerminalTheme.github.cursor, label: "github.cursor")
}
private func assertColorInRange(_ color: ThemeColor, label: String) {
// UInt8 is intrinsically 0255; the assertions below make the expectation readable.
XCTAssertLessThanOrEqual(color.r, 255, "\(label).r out of range")
XCTAssertLessThanOrEqual(color.g, 255, "\(label).g out of range")
XCTAssertLessThanOrEqual(color.b, 255, "\(label).b out of range")
}
// =========================================================================
// MARK: 3. .dark and .github are distinct themes
// =========================================================================
func testDarkAndGitHub_haveDistinctIds() {
XCTAssertNotEqual(TerminalTheme.dark.id, TerminalTheme.github.id,
"Built-in themes must have unique IDs")
}
func testDarkAndGitHub_haveDistinctBackgrounds() {
// "Dark (Hacker)" has a pure-black background; GitHub Dark does not.
XCTAssertNotEqual(TerminalTheme.dark.background, TerminalTheme.github.background,
"Background colors must differ between dark and github themes")
}
func testDarkAndGitHub_areNotEqual() {
XCTAssertNotEqual(TerminalTheme.dark, TerminalTheme.github,
".dark and .github must be distinct themes")
}
// =========================================================================
// MARK: 4. TerminalTheme identities
// =========================================================================
func testDark_hasExpectedId() {
XCTAssertEqual(TerminalTheme.dark.id, "dark")
}
func testGitHub_hasExpectedId() {
XCTAssertEqual(TerminalTheme.github.id, "github")
}
func testDark_backgroundIsBlack() {
let bg = TerminalTheme.dark.background
XCTAssertEqual(bg.r, 0x00, "Dark background R must be 0x00")
XCTAssertEqual(bg.g, 0x00, "Dark background G must be 0x00")
XCTAssertEqual(bg.b, 0x00, "Dark background B must be 0x00")
}
func testGitHub_backgroundMatchesSpec() {
// GitHub Dark background: #0d1117
let bg = TerminalTheme.github.background
XCTAssertEqual(bg.r, 0x0D, "GitHub background R must be 0x0D")
XCTAssertEqual(bg.g, 0x11, "GitHub background G must be 0x11")
XCTAssertEqual(bg.b, 0x17, "GitHub background B must be 0x17")
}
// =========================================================================
// MARK: 5. TerminalTheme.toSwiftTermColor conversion
// =========================================================================
func testToSwiftTermColor_white_mapsTo65535() {
// 255 × 257 = 65535 (= UInt16.max)
let white = ThemeColor(r: 255, g: 255, b: 255)
let stColor = TerminalTheme.dark.toSwiftTermColor(white)
XCTAssertEqual(stColor.red, 65535)
XCTAssertEqual(stColor.green, 65535)
XCTAssertEqual(stColor.blue, 65535)
}
func testToSwiftTermColor_black_mapsToZero() {
let black = ThemeColor(r: 0, g: 0, b: 0)
let stColor = TerminalTheme.dark.toSwiftTermColor(black)
XCTAssertEqual(stColor.red, 0)
XCTAssertEqual(stColor.green, 0)
XCTAssertEqual(stColor.blue, 0)
}
func testSwiftTermAnsiColors_has16Entries() {
XCTAssertEqual(TerminalTheme.dark.swiftTermAnsiColors.count, 16)
XCTAssertEqual(TerminalTheme.github.swiftTermAnsiColors.count, 16)
}
// =========================================================================
// MARK: 6. ThemeStore selection and persistence
// =========================================================================
@MainActor
func testThemeStore_available_containsBothBuiltins() {
let store = ThemeStore.shared
let ids = store.available.map(\.id)
XCTAssertTrue(ids.contains("dark"), "Available themes must include 'dark'")
XCTAssertTrue(ids.contains("github"), "Available themes must include 'github'")
}
@MainActor
func testThemeStore_select_updatesCurrent() {
let store = ThemeStore.shared
let before = store.current
// Select whichever theme is NOT currently active.
let next = store.available.first(where: { $0.id != before.id })!
store.select(next)
XCTAssertEqual(store.current.id, next.id,
"select(_:) must update current immediately")
// Restore original selection so we don't bleed state into other tests.
store.select(before)
}
// =========================================================================
// MARK: 7. TerminalTheme Codable round-trip
// =========================================================================
func testTerminalTheme_codable_roundTrips() throws {
let theme = TerminalTheme.dark
let data = try JSONEncoder().encode(theme)
let loaded = try JSONDecoder().decode(TerminalTheme.self, from: data)
XCTAssertEqual(loaded, theme, "TerminalTheme must survive a JSON round-trip")
}
}