Files
Termind/TFMTests/TerminalThemeTests.swift
T

206 lines
7.1 KiB
Swift

import AppKit
import SwiftUI
import TermindApplication
import TermindDomain
import TermindInfrastructure
import TermindPersistence
import TermindPresentation
import TermindRemoteInfrastructure
import Testing
@testable import Termind
struct TerminalThemeTests {
@Test
func appearanceOptionsAreFilteredAndSortedByName() {
let lightNames = TermindTerminalThemeCatalog.lightThemes.map(\.name)
let darkNames = TermindTerminalThemeCatalog.darkThemes.map(\.name)
#expect(lightNames == lightNames.sorted())
#expect(darkNames == darkNames.sorted())
#expect(TermindTerminalThemeCatalog.lightThemes.allSatisfy { !$0.isDark })
#expect(TermindTerminalThemeCatalog.darkThemes.allSatisfy { $0.isDark })
}
@Test
func resolverFallsBackForMissingOrWrongAppearancePreferences() {
let preferences = TerminalPreferences(
darkTheme: SettingsKey.defaultTerminalThemeLight,
lightTheme: "Missing Light Theme"
)
let light = TermindTerminalThemeCatalog.resolvedTheme(named: preferences.lightTheme, isDark: false)
let dark = TermindTerminalThemeCatalog.resolvedTheme(named: preferences.darkTheme, isDark: true)
#expect(light.name == SettingsKey.defaultTerminalThemeLight)
#expect(dark.name == SettingsKey.defaultTerminalThemeDark)
}
@Test
func unavailableThemesFallBackForBothAppearances() {
let light = TermindTerminalThemeCatalog.background(
themeName: "Missing Light Theme",
customEnabled: false,
customText: "",
isDark: false
)
let dark = TermindTerminalThemeCatalog.background(
themeName: "Missing Dark Theme",
customEnabled: false,
customText: "",
isDark: true
)
#expect(light == TermindTerminalPalette.termindLight.background)
#expect(dark == TermindTerminalPalette.termindDark.background)
}
@Test
func customConfigurationParsesGhosttyLinesInOrder() {
let configuration = TerminalCustomConfiguration(
"""
# comment
background = #102030
palette = 1=#AA0000
invalid line
custom-key = value=with=equals
= missing-key
background = 405060
"""
)
#expect(
configuration.entries == [
.init(key: "background", value: "#102030"),
.init(key: "palette", value: "1=#AA0000"),
.init(key: "custom-key", value: "value=with=equals"),
.init(key: "background", value: "405060"),
]
)
#expect(configuration.lastValue(for: "background") == "405060")
}
@Test
func customBackgroundUsesLastValidSetting() {
let background = TermindTerminalThemeCatalog.background(
themeName: SettingsKey.defaultTerminalThemeDark,
customEnabled: true,
customText: "background = #102030\nbackground = A0B0C0",
isDark: true
)
#expect(background.hex == "A0B0C0")
}
@Test
func invalidCustomBackgroundFallsBackToSelectedTheme() {
let background = TermindTerminalThemeCatalog.background(
themeName: SettingsKey.defaultTerminalThemeLight,
customEnabled: true,
customText: "background = transparent",
isDark: false
)
#expect(background == TermindTerminalPalette.termindLight.background)
}
@Test
func disabledCustomConfigurationIgnoresItsBackground() {
let background = TermindTerminalThemeCatalog.background(
themeName: SettingsKey.defaultTerminalThemeDark,
customEnabled: false,
customText: "background = FFFFFF",
isDark: true
)
#expect(background == TermindTerminalPalette.termindDark.background)
}
@Test
func changingBaseThemeWithCustomOverlayPreservesOverrideAndChangesUncoveredColors() throws {
let first = TermindTerminalThemeCatalog.defaultDark
let second = try #require(
TermindTerminalThemeCatalog.darkThemes.first {
$0.name != first.name && $0.foreground != first.foreground
})
let firstConfiguration = TermindTerminalThemeCatalog.terminalConfiguration(
themeName: first.name,
customEnabled: true,
customText: "background = 010203",
isDark: true
)
let secondConfiguration = TermindTerminalThemeCatalog.terminalConfiguration(
themeName: second.name,
customEnabled: true,
customText: "background = 010203",
isDark: true
)
#expect(firstConfiguration.rendered.hasSuffix("background = 010203"))
#expect(secondConfiguration.rendered.hasSuffix("background = 010203"))
#expect(firstConfiguration.rendered != secondConfiguration.rendered)
}
@Test @MainActor
func presentingTerminalSettingsDoesNotRewriteUnavailableThemes() async throws {
let initial = TerminalPreferences(
darkTheme: SettingsKey.defaultTerminalThemeLight,
lightTheme: "Missing Light Theme"
)
let persistence = RecordingTerminalPreferencesPersistence(initial: initial)
let terminalSettings = TerminalSettingsModel(persistence: persistence)
let app = AppModel(hosts: HostLibraryModel(), terminalSettings: terminalSettings)
let windowModel = WindowModel(workspaces: [])
windowModel.openSettings(route: .category(.terminal))
let appearance = AppearanceProbe()
defer { app.shutdownForTermination() }
let view = SettingsPageView()
.environment(app)
.environment(windowModel)
.frame(width: 640, height: 1100)
.onAppear { appearance.count += 1 }
let controller = NSHostingController(rootView: view)
let window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 640, height: 1100),
styleMask: [.borderless], backing: .buffered, defer: false
)
window.isReleasedWhenClosed = false
window.contentViewController = controller
defer {
window.contentViewController = nil
window.close()
}
controller.view.layoutSubtreeIfNeeded()
for _ in 0..<10 where appearance.count == 0 {
try await Task.sleep(for: .milliseconds(10))
controller.view.layoutSubtreeIfNeeded()
}
#expect(appearance.count > 0)
#expect(windowModel.settingsRoute == .category(.terminal))
#expect(terminalSettings.preferences == initial)
#expect(persistence.saveCount == 0)
}
}
@MainActor private final class RecordingTerminalPreferencesPersistence: TerminalPreferencesPersisting {
let initial: TerminalPreferences
var saveCount = 0
init(initial: TerminalPreferences) {
self.initial = initial
}
func loadTerminal() throws -> TerminalPreferences { initial }
func saveTerminal(_ value: TerminalPreferences) throws { saveCount += 1 }
}
@MainActor private final class AppearanceProbe {
var count = 0
}