Skip to content

Commit

Permalink
Add KeychainQuerying subscripts to Ephemeral Strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
JacobHearst committed Sep 30, 2024
1 parent 361e798 commit 52a5d96
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 0 deletions.
22 changes: 22 additions & 0 deletions Sources/HaversackMock/HaversackEphemeralStrategy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import Haversack
/// A strategy which uses a simple dictionary to search, store, and delete data instead of hitting an actual keychain.
///
/// The keys of the ``mockData`` dictionary are calculated from the queries that are sent through Haversack.
///
/// You can also use either the untyped ``subscript(_:)-7weqp`` or the typed ``subscript(_:)-6jjzx``
/// accessors to avoid having to hold onto the calculated keys.
open class HaversackEphemeralStrategy: HaversackStrategy {
/// The dictionary that is used for storage of keychain items
///
Expand Down Expand Up @@ -38,6 +41,25 @@ open class HaversackEphemeralStrategy: HaversackStrategy {
/// If the strategy has any problems it will throw `NSError` with this domain.
public static let errorDomain = "haversack.unit_testing.mock"

/// Untyped access to ``mockData`` values via keychain queries instead of `String`s
/// - Parameter query: The keychain query to read/write to
/// - Returns: The ``mockData`` value for the `query`
public subscript(_ query: any KeychainQuerying) -> Any? {
get {
mockData[key(for: query.query)]
}
set {
mockData[key(for: query.query)] = newValue
}
}

/// Typed access to ``mockData`` values via keychain queries instead of `String`s
/// - Parameter query: The keychain query to read the value for
/// - Returns: The ``mockData`` value for the `query`
public subscript<T>(_ query: any KeychainQuerying) -> T? {
self[query] as? T
}

/// Looks through the ``mockData`` dictionary for an entry matching the query.
/// - Parameter querying: An instance of a type that conforms to the `KeychainQuerying` protocol.
/// - Throws: An `NSError` with the ``errorDomain`` domain if no entry is found in the dictionary.
Expand Down
29 changes: 29 additions & 0 deletions Tests/HaversackTests/EphemeralStrategyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,33 @@ final class EphemeralStrategyTests: XCTestCase {
XCTAssertNotNil(mock.certificateImportConfiguration)
}
#endif

func testUntypedSubscript() throws {
// Given
let mock = HaversackEphemeralStrategy()
let query = GenericPasswordQuery()
let mockValue = "test"

// When
mock[query] = mockValue
let storedAny = mock[query]

// Then
let storedString = try XCTUnwrap(storedAny as? String)
XCTAssertEqual(storedString, mockValue)
}

func testTypedSubscript() {
// Given
let mock = HaversackEphemeralStrategy()
let query = GenericPasswordQuery()
let mockValue = "test"

// When
mock[query] = mockValue
let storedString: String? = mock[query]

// Then
XCTAssertEqual(storedString, mockValue)
}
}

0 comments on commit 52a5d96

Please sign in to comment.