Skip to content

Commit 52a5d96

Browse files
committed
Add KeychainQuerying subscripts to Ephemeral Strategy
1 parent 361e798 commit 52a5d96

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

Sources/HaversackMock/HaversackEphemeralStrategy.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ import Haversack
77
/// A strategy which uses a simple dictionary to search, store, and delete data instead of hitting an actual keychain.
88
///
99
/// The keys of the ``mockData`` dictionary are calculated from the queries that are sent through Haversack.
10+
///
11+
/// You can also use either the untyped ``subscript(_:)-7weqp`` or the typed ``subscript(_:)-6jjzx``
12+
/// accessors to avoid having to hold onto the calculated keys.
1013
open class HaversackEphemeralStrategy: HaversackStrategy {
1114
/// The dictionary that is used for storage of keychain items
1215
///
@@ -38,6 +41,25 @@ open class HaversackEphemeralStrategy: HaversackStrategy {
3841
/// If the strategy has any problems it will throw `NSError` with this domain.
3942
public static let errorDomain = "haversack.unit_testing.mock"
4043

44+
/// Untyped access to ``mockData`` values via keychain queries instead of `String`s
45+
/// - Parameter query: The keychain query to read/write to
46+
/// - Returns: The ``mockData`` value for the `query`
47+
public subscript(_ query: any KeychainQuerying) -> Any? {
48+
get {
49+
mockData[key(for: query.query)]
50+
}
51+
set {
52+
mockData[key(for: query.query)] = newValue
53+
}
54+
}
55+
56+
/// Typed access to ``mockData`` values via keychain queries instead of `String`s
57+
/// - Parameter query: The keychain query to read the value for
58+
/// - Returns: The ``mockData`` value for the `query`
59+
public subscript<T>(_ query: any KeychainQuerying) -> T? {
60+
self[query] as? T
61+
}
62+
4163
/// Looks through the ``mockData`` dictionary for an entry matching the query.
4264
/// - Parameter querying: An instance of a type that conforms to the `KeychainQuerying` protocol.
4365
/// - Throws: An `NSError` with the ``errorDomain`` domain if no entry is found in the dictionary.

Tests/HaversackTests/EphemeralStrategyTests.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,33 @@ final class EphemeralStrategyTests: XCTestCase {
6464
XCTAssertNotNil(mock.certificateImportConfiguration)
6565
}
6666
#endif
67+
68+
func testUntypedSubscript() throws {
69+
// Given
70+
let mock = HaversackEphemeralStrategy()
71+
let query = GenericPasswordQuery()
72+
let mockValue = "test"
73+
74+
// When
75+
mock[query] = mockValue
76+
let storedAny = mock[query]
77+
78+
// Then
79+
let storedString = try XCTUnwrap(storedAny as? String)
80+
XCTAssertEqual(storedString, mockValue)
81+
}
82+
83+
func testTypedSubscript() {
84+
// Given
85+
let mock = HaversackEphemeralStrategy()
86+
let query = GenericPasswordQuery()
87+
let mockValue = "test"
88+
89+
// When
90+
mock[query] = mockValue
91+
let storedString: String? = mock[query]
92+
93+
// Then
94+
XCTAssertEqual(storedString, mockValue)
95+
}
6796
}

0 commit comments

Comments
 (0)