Files
OSGKeyboard/OSGKeyboardTests/SettingsCloudSyncTests.swift
T
Rocky 128aab1b02 feat: iCloud settings sync and cold-start return redesign
- Add iCloud key-value settings sync (engine/language/polish/Flow prefs);
  API keys stay on-device. New "Sync settings via iCloud" toggle.
- Redesign cold-start handoff: bottom-bar left-to-right swipe guidance,
  auto-dismiss on app switch, tap-anywhere to close, retained return link.
- Harden keyboard->app handoff with host-disconnected hint.
- Include prior Unreleased ASR fixes (route-change crash, fallback warning,
  multi-utterance recognition, local ASR diagnostics).

Release 0.5.0 (build 18).
2026-07-07 17:56:01 +08:00

158 lines
5.6 KiB
Swift

// SettingsCloudSyncTests.swift
// OSGKeyboardTests
//
// Hermetic tests for iCloud KVS settings sync + preference toggles.
import XCTest
@testable import OSGKeyboardShared
@MainActor
final class SettingsCloudSyncTests: XCTestCase {
private var suiteName: String!
private var defaults: UserDefaults!
private var store: AppGroupStore!
private var kvs: FakeUbiquitousKeyValueStore!
private var settingsSync: SettingsCloudSync!
override func setUp() {
super.setUp()
suiteName = "group.com.osgkeyboard.shared.tests.settings.\(UUID().uuidString)"
defaults = UserDefaults(suiteName: suiteName)!
defaults.removePersistentDomain(forName: suiteName)
store = AppGroupStore(defaults: defaults)
kvs = FakeUbiquitousKeyValueStore()
settingsSync = SettingsCloudSync(kvs: kvs) { [unowned self] in store }
}
override func tearDown() {
defaults.removePersistentDomain(forName: suiteName)
super.tearDown()
}
func testMergePrefersNewerUpdatedAt() {
let older = SyncedAppSettings(
updatedAt: Date(timeIntervalSince1970: 100),
providerId: "openai",
baseURL: "https://old.example",
model: "gpt-old",
modeId: "polish",
localeId: "auto",
engineMode: "cloud",
hasAcknowledgedCloudSharing: false,
uiLanguage: .english,
translationTargetLocaleId: TranslationLanguageCatalog.offLocaleId,
handednessPreference: .left,
cursorDragNavigationEnabled: true,
polishIntensity: .medium,
flowSkipAppSwitch: true,
flowInactivityDuration: .twelveHours
)
let newer = SyncedAppSettings(
updatedAt: Date(timeIntervalSince1970: 200),
providerId: "openai",
baseURL: "https://new.example",
model: "gpt-new",
modeId: "polish",
localeId: "zh-Hans",
engineMode: "local",
hasAcknowledgedCloudSharing: true,
uiLanguage: .chinese,
translationTargetLocaleId: "en",
handednessPreference: .right,
cursorDragNavigationEnabled: false,
polishIntensity: .light,
flowSkipAppSwitch: false,
flowInactivityDuration: .threeHours
)
let merged = SyncedAppSettings.merge(local: older, remote: newer)
XCTAssertEqual(merged.model, "gpt-new")
XCTAssertEqual(merged.localeId, "zh-Hans")
XCTAssertEqual(merged.engineMode, "local")
}
func testEnableSyncUploadsMergedSettingsAndToggle() async throws {
store.setModeId("polish")
store.setLocaleId("zh-Hans")
let remote = SyncedAppSettings(
updatedAt: Date().addingTimeInterval(3600),
providerId: "openai",
baseURL: "https://remote.example",
model: "remote-model",
modeId: "polish",
localeId: "en",
engineMode: "cloud",
hasAcknowledgedCloudSharing: true,
uiLanguage: .english,
translationTargetLocaleId: TranslationLanguageCatalog.offLocaleId,
handednessPreference: .right,
cursorDragNavigationEnabled: true,
polishIntensity: .medium,
flowSkipAppSwitch: true,
flowInactivityDuration: .twelveHours
)
try settingsSync.push(remote)
try await settingsSync.enableSync()
XCTAssertTrue(store.settingsICloudSyncEnabled)
XCTAssertEqual(kvs.object(forKey: ICloudSyncPreferences.settingsEnabledKey) as? Bool, true)
XCTAssertEqual(settingsSync.loadRemote()?.localeId, "en")
}
func testPullAndMergeAppliesRemoteSettingsToAppGroup() async throws {
store.setSettingsICloudSyncEnabled(true)
store.setLocaleId("auto")
let remote = SyncedAppSettings(
updatedAt: Date(timeIntervalSince1970: 900),
providerId: "openai",
baseURL: "https://remote.example",
model: "remote-model",
modeId: "polish",
localeId: "ja",
engineMode: "cloud",
hasAcknowledgedCloudSharing: false,
uiLanguage: .english,
translationTargetLocaleId: TranslationLanguageCatalog.offLocaleId,
handednessPreference: .left,
cursorDragNavigationEnabled: true,
polishIntensity: .medium,
flowSkipAppSwitch: true,
flowInactivityDuration: .twelveHours
)
try settingsSync.push(remote)
await settingsSync.pullAndMerge(store: store)
XCTAssertEqual(store.localeId, "ja")
XCTAssertEqual(store.settingsCloudUpdatedAt?.timeIntervalSince1970, 900, accuracy: 1)
}
func testPushLocalIfEnabledSkipsWhenDisabled() async throws {
store.setSettingsICloudSyncEnabled(false)
store.setLocaleId("ko")
try await settingsSync.pushLocalIfEnabled()
XCTAssertNil(settingsSync.loadRemote())
}
func testICloudSyncPreferencesMigrateLegacyToggles() {
store.setSettingsICloudSyncEnabled(false)
store.setPersonalDictionaryICloudSyncEnabled(true)
ICloudSyncPreferences.migrateLegacyTogglesIfNeeded(kvs: kvs, store: store)
XCTAssertEqual(kvs.object(forKey: ICloudSyncPreferences.settingsEnabledKey) as? Bool, false)
XCTAssertEqual(kvs.object(forKey: ICloudSyncPreferences.dictionaryEnabledKey) as? Bool, true)
}
func testAppGroupConfigurationDefaultsSettingsICloudSyncToOn() {
let config = AppGroupConfiguration.load(fromAvailable: defaults)
XCTAssertTrue(config.settingsICloudSyncEnabled)
}
}