141 lines
7.9 KiB
Swift
141 lines
7.9 KiB
Swift
// SPDX-FileCopyrightText: 2026 Kaede Akino
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
import Foundation
|
|
import SwiftData
|
|
import TermindApplication
|
|
import TermindDomain
|
|
import TermindPersistence
|
|
import Testing
|
|
|
|
@Suite @MainActor
|
|
struct TerminalFontPreferencesTests {
|
|
@Test func defaultAndUnavailableFamiliesFollowThemeWithoutChangingSize() {
|
|
#expect(TerminalFontPreferences() == .init(family: "", size: 12, sizeFollowsTheme: true))
|
|
let selected = TerminalFontPreferences(family: "Missing Font", size: 19, sizeFollowsTheme: false)
|
|
let resolved = selected.resolvingFamily(in: ["Menlo"])
|
|
#expect(resolved == .init(family: "", size: 19, sizeFollowsTheme: false))
|
|
#expect(selected.family == "Missing Font")
|
|
#expect(selected.resolvingFamily(in: ["Missing Font"]) == selected)
|
|
}
|
|
|
|
@Test func upgradePreservesLocalTypographyAndIgnoresFutureLegacyRemoteValues() throws {
|
|
let domain = "TerminalFontMigration.\(UUID())"
|
|
let defaults = try #require(UserDefaults(suiteName: domain))
|
|
defer { defaults.removePersistentDomain(forName: domain) }
|
|
let container = try TermindPersistence.makeContainer(inMemory: true)
|
|
let row = try PersistentTerminalPreferences(.init())
|
|
row.data = try legacyData(size: 19, followsTheme: false)
|
|
container.mainContext.insert(row)
|
|
try container.mainContext.save()
|
|
let store = SettingsSyncPersistence(context: container.mainContext, defaults: defaults)
|
|
try store.prepare()
|
|
#expect(defaults.double(forKey: SettingsKey.terminalFontSize) == 19)
|
|
#expect(!defaults.bool(forKey: SettingsKey.terminalFontFollowTheme))
|
|
|
|
let legacy = try JSONDecoder().decode(TerminalPreferences.self, from: legacyData(size: 30, followsTheme: true))
|
|
var remote = legacy
|
|
remote.lightTheme = "GitHub Light"
|
|
let payload = SettingsRecordPayload.terminal(remote)
|
|
let envelope = SettingsEnvelope(
|
|
key: payload.key, version: .next(after: nil, writerID: UUID(), now: .now), payload: payload)
|
|
_ = try store.applyRemote([envelope])
|
|
try store.prepare()
|
|
#expect(try store.loadTerminal().lightTheme == "GitHub Light")
|
|
#expect(defaults.double(forKey: SettingsKey.terminalFontSize) == 19)
|
|
#expect(!defaults.bool(forKey: SettingsKey.terminalFontFollowTheme))
|
|
}
|
|
|
|
@Test func existingDeviceDefaultsWinOverOldLocalBlob() throws {
|
|
let domain = "TerminalFontDefaults.\(UUID())"
|
|
let defaults = try #require(UserDefaults(suiteName: domain))
|
|
defer { defaults.removePersistentDomain(forName: domain) }
|
|
defaults.set(15.0, forKey: SettingsKey.terminalFontSize)
|
|
defaults.set(true, forKey: SettingsKey.terminalFontFollowTheme)
|
|
defaults.set("Menlo", forKey: SettingsKey.terminalFontFamily)
|
|
try TerminalFontPreferences.migrateLegacySettings(
|
|
from: legacyData(size: 23, followsTheme: false), defaults: defaults)
|
|
#expect(defaults.double(forKey: SettingsKey.terminalFontSize) == 15)
|
|
#expect(defaults.bool(forKey: SettingsKey.terminalFontFollowTheme))
|
|
#expect(defaults.string(forKey: SettingsKey.terminalFontFamily) == "Menlo")
|
|
}
|
|
|
|
@Test func partialAndFreshDefaultsAreInitializedOnce() throws {
|
|
let domain = "TerminalFontPartialDefaults.\(UUID())"
|
|
let defaults = try #require(UserDefaults(suiteName: domain))
|
|
defer { defaults.removePersistentDomain(forName: domain) }
|
|
defaults.set(16.0, forKey: SettingsKey.terminalFontSize)
|
|
try TerminalFontPreferences.migrateLegacySettings(
|
|
from: legacyData(size: 23, followsTheme: false), defaults: defaults)
|
|
#expect(defaults.double(forKey: SettingsKey.terminalFontSize) == 16)
|
|
#expect(!defaults.bool(forKey: SettingsKey.terminalFontFollowTheme))
|
|
defaults.removePersistentDomain(forName: domain)
|
|
try TerminalFontPreferences.migrateLegacySettings(from: nil, defaults: defaults)
|
|
try TerminalFontPreferences.migrateLegacySettings(
|
|
from: legacyData(size: 23, followsTheme: false), defaults: defaults)
|
|
#expect(defaults.double(forKey: SettingsKey.terminalFontSize) == 12)
|
|
#expect(defaults.bool(forKey: SettingsKey.terminalFontFollowTheme))
|
|
}
|
|
|
|
@Test func twoDevicesKeepIndependentTypographyAcrossSyncAndRestart() throws {
|
|
let names = ["TerminalFontSource.\(UUID())", "TerminalFontDestination.\(UUID())"]
|
|
let sourceDefaults = try #require(UserDefaults(suiteName: names[0]))
|
|
let destinationDefaults = try #require(UserDefaults(suiteName: names[1]))
|
|
defer {
|
|
sourceDefaults.removePersistentDomain(forName: names[0])
|
|
destinationDefaults.removePersistentDomain(forName: names[1])
|
|
}
|
|
let sourceContainer = try TermindPersistence.makeContainer(inMemory: true)
|
|
let destinationContainer = try TermindPersistence.makeContainer(inMemory: true)
|
|
let source = SettingsSyncPersistence(context: sourceContainer.mainContext, defaults: sourceDefaults)
|
|
let destination = SettingsSyncPersistence(
|
|
context: destinationContainer.mainContext, defaults: destinationDefaults)
|
|
try source.prepare()
|
|
try destination.prepare()
|
|
let originalEnvelopes = try source.journal.pendingEnvelopes()
|
|
sourceDefaults.set("Menlo", forKey: SettingsKey.terminalFontFamily)
|
|
sourceDefaults.set(18.0, forKey: SettingsKey.terminalFontSize)
|
|
sourceDefaults.set(false, forKey: SettingsKey.terminalFontFollowTheme)
|
|
destinationDefaults.set("Courier", forKey: SettingsKey.terminalFontFamily)
|
|
destinationDefaults.set(22.0, forKey: SettingsKey.terminalFontSize)
|
|
#expect(try source.journal.pendingEnvelopes() == originalEnvelopes)
|
|
|
|
try source.saveTerminal(.init(lightTheme: "GitHub Light"))
|
|
let records = try source.journal.pendingEnvelopes().filter { $0.key.kind == .terminal }
|
|
_ = try destination.applyRemote(records)
|
|
let restarted = SettingsSyncPersistence(
|
|
context: destinationContainer.mainContext, defaults: destinationDefaults)
|
|
try restarted.prepare()
|
|
#expect(try restarted.loadTerminal().lightTheme == "GitHub Light")
|
|
#expect(destinationDefaults.string(forKey: SettingsKey.terminalFontFamily) == "Courier")
|
|
#expect(destinationDefaults.double(forKey: SettingsKey.terminalFontSize) == 22)
|
|
#expect(destinationDefaults.bool(forKey: SettingsKey.terminalFontFollowTheme))
|
|
#expect(sourceDefaults.string(forKey: SettingsKey.terminalFontFamily) == "Menlo")
|
|
#expect(sourceDefaults.double(forKey: SettingsKey.terminalFontSize) == 18)
|
|
#expect(!sourceDefaults.bool(forKey: SettingsKey.terminalFontFollowTheme))
|
|
let encoded = try String(decoding: SettingsSyncCodec.encode(#require(records.first)), as: UTF8.self)
|
|
for key in ["fontFamily", "fontSize", "fontFollowTheme"] { #expect(!encoded.contains(key)) }
|
|
}
|
|
|
|
@Test func legacyTypographyIsDiscardedWhenRecordsAreReencodedForUpload() throws {
|
|
let preferences = try JSONDecoder().decode(
|
|
TerminalPreferences.self, from: legacyData(size: 28, followsTheme: false))
|
|
let payload = SettingsRecordPayload.terminal(preferences)
|
|
let envelope = SettingsEnvelope(
|
|
key: payload.key, version: .baseline(writerID: UUID()), payload: payload)
|
|
let data = try SettingsSyncCodec.encode(envelope)
|
|
let encoded = String(decoding: data, as: UTF8.self)
|
|
#expect(!encoded.contains("fontSize"))
|
|
#expect(!encoded.contains("fontFollowTheme"))
|
|
#expect(try SettingsSyncCodec.decode(data) == envelope)
|
|
}
|
|
|
|
private func legacyData(size: Double, followsTheme: Bool) throws -> Data {
|
|
let encoded = try JSONEncoder().encode(TerminalPreferences())
|
|
var object = try #require(JSONSerialization.jsonObject(with: encoded) as? [String: Any])
|
|
object["fontSize"] = size
|
|
object["fontFollowTheme"] = followsTheme
|
|
return try JSONSerialization.data(withJSONObject: object)
|
|
}
|
|
}
|