2024-04-13 22:44:43 +00:00
|
|
|
//
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2024-04-15 14:50:08 +00:00
|
|
|
final class TestStore<Key: PreferenceKey>: Codable, ObservableObject {
|
|
|
|
private var _test = Preference<Key>()
|
2024-04-13 22:44:43 +00:00
|
|
|
|
|
|
|
// the acutal subscript expects the enclosingInstance to be a PreferenceStore, so do it manually
|
2024-04-15 14:50:08 +00:00
|
|
|
var test: Key.Value {
|
2024-04-13 22:44:43 +00:00
|
|
|
get {
|
2024-04-14 02:36:42 +00:00
|
|
|
Preference.get(enclosingInstance: self, storage: \._test)
|
2024-04-13 22:44:43 +00:00
|
|
|
}
|
|
|
|
set {
|
2024-04-14 02:36:42 +00:00
|
|
|
Preference.set(enclosingInstance: self, storage: \._test, newValue: newValue)
|
2024-04-13 22:44:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-15 14:50:08 +00:00
|
|
|
var testPublisher: some Publisher<Key.Value, Never> {
|
2024-04-13 22:44:43 +00:00
|
|
|
_test.projectedValue
|
|
|
|
}
|
|
|
|
|
|
|
|
init() {
|
|
|
|
}
|
|
|
|
|
|
|
|
init(from decoder: any Decoder) throws {
|
|
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
2024-04-15 14:50:08 +00:00
|
|
|
self._test = try container.decode(Preference<Key>.self, forKey: .test)
|
2024-04-13 22:44:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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()
|
2024-04-15 14:50:08 +00:00
|
|
|
let present = try decoder.decode(PreferenceCoding<TestStore<TestKey>>.self, from: Data("""
|
2024-04-13 22:44:43 +00:00
|
|
|
{"test": true}
|
|
|
|
""".utf8)).wrapped
|
|
|
|
XCTAssertEqual(present.test, true)
|
2024-04-15 14:50:08 +00:00
|
|
|
let absent = try decoder.decode(PreferenceCoding<TestStore<TestKey>>.self, from: Data("""
|
2024-04-13 22:44:43 +00:00
|
|
|
{}
|
|
|
|
""".utf8)).wrapped
|
|
|
|
XCTAssertEqual(absent.test, false)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testEncoding() throws {
|
2024-04-15 14:50:08 +00:00
|
|
|
let store = TestStore<TestKey>()
|
2024-04-13 22:44:43 +00:00
|
|
|
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
|
2024-04-15 14:50:08 +00:00
|
|
|
let store = TestStore<TestKey>()
|
2024-04-13 22:44:43 +00:00
|
|
|
var cancellables = Set<AnyCancellable>()
|
|
|
|
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])
|
|
|
|
}
|
2024-04-15 14:50:08 +00:00
|
|
|
|
|
|
|
func testCustomCodable() throws {
|
|
|
|
struct Key: CustomCodablePreferenceKey {
|
|
|
|
static let defaultValue = 1
|
|
|
|
static func encode(value: Int, to encoder: any Encoder) throws {
|
|
|
|
var container = encoder.singleValueContainer()
|
|
|
|
try container.encode(2)
|
|
|
|
}
|
|
|
|
static func decode(from decoder: any Decoder) throws -> Int? {
|
|
|
|
3
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let store = TestStore<Key>()
|
|
|
|
store.test = 123
|
|
|
|
let encoder = JSONEncoder()
|
|
|
|
XCTAssertEqual(String(data: try encoder.encode(PreferenceCoding(wrapped: store)), encoding: .utf8)!, """
|
|
|
|
{"test":2}
|
|
|
|
""")
|
|
|
|
let decoder = JSONDecoder()
|
|
|
|
let present = try decoder.decode(PreferenceCoding<TestStore<Key>>.self, from: Data("""
|
|
|
|
{"test":2}
|
|
|
|
""".utf8)).wrapped
|
|
|
|
XCTAssertEqual(present.test, 3)
|
|
|
|
let absent = try decoder.decode(PreferenceCoding<TestStore<Key>>.self, from: Data("""
|
|
|
|
{}
|
|
|
|
""".utf8)).wrapped
|
|
|
|
XCTAssertEqual(absent.test, 1)
|
|
|
|
}
|
2024-04-13 22:44:43 +00:00
|
|
|
|
|
|
|
}
|