// // PreferenceStoreTests.swift // TuskerPreferencesTests // // Created by Shadowfacts on 4/12/24. // import XCTest @testable import TuskerPreferences import Combine final class PreferenceStoreTests: XCTestCase { struct TestKey: PreferenceKey { static let defaultValue = false } final class TestStore: Codable, ObservableObject { private var _test = Preference() // the acutal subscript expects the enclosingInstance to be a PreferenceStore, so do it manually var test: Bool { get { Preference.get(enclosingInstance: self, wrapped: \.test, storage: \._test) } set { Preference.set(enclosingInstance: self, wrapped: \.test, storage: \._test, newValue: newValue) } } var testPublisher: some Publisher { _test.projectedValue } init() { } init(from decoder: any Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self._test = try container.decode(Preference.self, forKey: .test) } enum CodingKeys: CodingKey { case test } func encode(to encoder: any Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(self._test, forKey: .test) } } func testDecoding() throws { let decoder = JSONDecoder() let present = try decoder.decode(PreferenceCoding.self, from: Data(""" {"test": true} """.utf8)).wrapped XCTAssertEqual(present.test, true) let absent = try decoder.decode(PreferenceCoding.self, from: Data(""" {} """.utf8)).wrapped XCTAssertEqual(absent.test, false) } func testEncoding() throws { let store = TestStore() let encoder = JSONEncoder() XCTAssertEqual(String(data: try encoder.encode(PreferenceCoding(wrapped: store)), encoding: .utf8)!, """ {} """) store.test = true XCTAssertEqual(String(data: try encoder.encode(PreferenceCoding(wrapped: store)), encoding: .utf8)!, """ {"test":true} """) store.test = false XCTAssertEqual(String(data: try encoder.encode(PreferenceCoding(wrapped: store)), encoding: .utf8)!, """ {"test":false} """) } func testPublisher() { let topLevel = expectation(description: "top level publisher") let specificPref = expectation(description: "preference publisher") // initial and on change specificPref.expectedFulfillmentCount = 2 let store = TestStore() var cancellables = Set() store.objectWillChange.sink { topLevel.fulfill() // fires on will change XCTAssertEqual(store.test, false) }.store(in: &cancellables) store.testPublisher.sink { _ in specificPref.fulfill() }.store(in: &cancellables) store.test = true wait(for: [topLevel, specificPref]) } }