mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 22:25:20 +00:00
Injectable UserDefaults to fix race condition in tests (#741)
This commit is contained in:
@@ -20,8 +20,11 @@ final class GeohashBookmarksStore: ObservableObject {
|
|||||||
private let geocoder = CLGeocoder()
|
private let geocoder = CLGeocoder()
|
||||||
private var resolving: Set<String> = []
|
private var resolving: Set<String> = []
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
private let storage: UserDefaults
|
||||||
|
|
||||||
private init() {
|
init(storage: UserDefaults = .standard) {
|
||||||
|
self.storage = storage
|
||||||
load()
|
load()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +67,7 @@ final class GeohashBookmarksStore: ObservableObject {
|
|||||||
|
|
||||||
// MARK: - Persistence
|
// MARK: - Persistence
|
||||||
private func load() {
|
private func load() {
|
||||||
guard let data = UserDefaults.standard.data(forKey: storeKey) else { return }
|
guard let data = storage.data(forKey: storeKey) else { return }
|
||||||
if let arr = try? JSONDecoder().decode([String].self, from: data) {
|
if let arr = try? JSONDecoder().decode([String].self, from: data) {
|
||||||
// Sanitize, normalize, dedupe while preserving order (first occurrence wins)
|
// Sanitize, normalize, dedupe while preserving order (first occurrence wins)
|
||||||
var seen = Set<String>()
|
var seen = Set<String>()
|
||||||
@@ -81,7 +84,7 @@ final class GeohashBookmarksStore: ObservableObject {
|
|||||||
membership = seen
|
membership = seen
|
||||||
}
|
}
|
||||||
// Load any saved names
|
// Load any saved names
|
||||||
if let namesData = UserDefaults.standard.data(forKey: namesStoreKey),
|
if let namesData = storage.data(forKey: namesStoreKey),
|
||||||
let dict = try? JSONDecoder().decode([String: String].self, from: namesData) {
|
let dict = try? JSONDecoder().decode([String: String].self, from: namesData) {
|
||||||
bookmarkNames = dict
|
bookmarkNames = dict
|
||||||
}
|
}
|
||||||
@@ -89,13 +92,13 @@ final class GeohashBookmarksStore: ObservableObject {
|
|||||||
|
|
||||||
private func persist() {
|
private func persist() {
|
||||||
if let data = try? JSONEncoder().encode(bookmarks) {
|
if let data = try? JSONEncoder().encode(bookmarks) {
|
||||||
UserDefaults.standard.set(data, forKey: storeKey)
|
storage.set(data, forKey: storeKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func persistNames() {
|
private func persistNames() {
|
||||||
if let data = try? JSONEncoder().encode(bookmarkNames) {
|
if let data = try? JSONEncoder().encode(bookmarkNames) {
|
||||||
UserDefaults.standard.set(data, forKey: namesStoreKey)
|
storage.set(data, forKey: namesStoreKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,23 +3,25 @@ import XCTest
|
|||||||
|
|
||||||
final class GeohashBookmarksStoreTests: XCTestCase {
|
final class GeohashBookmarksStoreTests: XCTestCase {
|
||||||
let storeKey = "locationChannel.bookmarks"
|
let storeKey = "locationChannel.bookmarks"
|
||||||
|
var storage: UserDefaults!
|
||||||
|
var store: GeohashBookmarksStore!
|
||||||
|
|
||||||
override func setUp() {
|
override func setUp() {
|
||||||
super.setUp()
|
super.setUp()
|
||||||
// Clear persisted state before each test
|
// Unique instance for each test to avoid race condition
|
||||||
UserDefaults.standard.removeObject(forKey: storeKey)
|
storage = UserDefaults(suiteName: UUID().uuidString)
|
||||||
GeohashBookmarksStore.shared._resetForTesting()
|
store = GeohashBookmarksStore(storage: storage!)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDown() {
|
override func tearDown() {
|
||||||
// Clean after each test
|
storage.removeObject(forKey: storeKey)
|
||||||
UserDefaults.standard.removeObject(forKey: storeKey)
|
store._resetForTesting()
|
||||||
GeohashBookmarksStore.shared._resetForTesting()
|
store = nil
|
||||||
|
storage = nil
|
||||||
super.tearDown()
|
super.tearDown()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testToggleAndNormalize() {
|
func testToggleAndNormalize() {
|
||||||
let store = GeohashBookmarksStore.shared
|
|
||||||
// Start clean
|
// Start clean
|
||||||
XCTAssertTrue(store.bookmarks.isEmpty)
|
XCTAssertTrue(store.bookmarks.isEmpty)
|
||||||
|
|
||||||
@@ -35,12 +37,11 @@ final class GeohashBookmarksStoreTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testPersistenceWritten() throws {
|
func testPersistenceWritten() throws {
|
||||||
let store = GeohashBookmarksStore.shared
|
|
||||||
store.toggle("ezs42")
|
store.toggle("ezs42")
|
||||||
store.toggle("u4pruy")
|
store.toggle("u4pruy")
|
||||||
|
|
||||||
// Verify persisted JSON contains both (order not enforced here)
|
// Verify persisted JSON contains both (order not enforced here)
|
||||||
guard let data = UserDefaults.standard.data(forKey: storeKey) else {
|
guard let data = storage.data(forKey: storeKey) else {
|
||||||
XCTFail("No persisted data found")
|
XCTFail("No persisted data found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user