Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kishikawakatsumi committed Oct 27, 2019
1 parent d022492 commit 046b2c7
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 38 deletions.
56 changes: 18 additions & 38 deletions Lib/KeychainAccess/Keychain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -511,24 +511,12 @@ public final class Keychain {

// MARK:

public func get(_ key: String) throws -> String? {
return try getString(key, exactly: false)
public func get(_ key: String, ignoringAttributeSynchronizable: Bool = true) throws -> String? {
return try getString(key, ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
}

public func get(exactly key: String) throws -> String? {
return try getString(key, exactly: true)
}

public func getString(_ key: String) throws -> String? {
return try getString(key, exactly: false)
}

public func getString(exactly key: String) throws -> String? {
return try getString(key, exactly: true)
}

private func getString(_ key: String, exactly: Bool = false) throws -> String? {
guard let data = try getData(key, exactly: exactly) else {
public func getString(_ key: String, ignoringAttributeSynchronizable: Bool = true) throws -> String? {
guard let data = try getData(key, ignoringAttributeSynchronizable: ignoringAttributeSynchronizable) else {
return nil
}
guard let string = String(data: data, encoding: .utf8) else {
Expand All @@ -538,16 +526,8 @@ public final class Keychain {
return string
}

public func getData(_ key: String) throws -> Data? {
return try getData(key, exactly: false)
}

public func getData(exactly key: String) throws -> Data? {
return try getData(key, exactly: true)
}

private func getData(_ key: String, exactly: Bool = false) throws -> Data? {
var query = options.query(exactly: exactly)
public func getData(_ key: String, ignoringAttributeSynchronizable: Bool = true) throws -> Data? {
var query = options.query(ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)

query[MatchLimit] = MatchLimitOne
query[ReturnData] = kCFBooleanTrue
Expand All @@ -570,8 +550,8 @@ public final class Keychain {
}
}

public func get<T>(_ key: String, handler: (Attributes?) -> T) throws -> T {
var query = options.query()
public func get<T>(_ key: String, ignoringAttributeSynchronizable: Bool = true, handler: (Attributes?) -> T) throws -> T {
var query = options.query(ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)

query[MatchLimit] = MatchLimitOne

Expand Down Expand Up @@ -600,16 +580,16 @@ public final class Keychain {

// MARK:

public func set(_ value: String, key: String) throws {
public func set(_ value: String, key: String, ignoringAttributeSynchronizable: Bool = true) throws {
guard let data = value.data(using: .utf8, allowLossyConversion: false) else {
print("failed to convert string to data")
throw Status.conversionError
}
try set(data, key: key)
try set(data, key: key, ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
}

public func set(_ value: Data, key: String) throws {
var query = options.query()
public func set(_ value: Data, key: String, ignoringAttributeSynchronizable: Bool = true) throws {
var query = options.query(ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
query[AttributeAccount] = key
#if os(iOS)
if #available(iOS 9.0, *) {
Expand Down Expand Up @@ -738,8 +718,8 @@ public final class Keychain {

// MARK:

public func remove(_ key: String) throws {
var query = options.query()
public func remove(_ key: String, ignoringAttributeSynchronizable: Bool = true) throws {
var query = options.query(ignoringAttributeSynchronizable: ignoringAttributeSynchronizable)
query[AttributeAccount] = key

let status = SecItemDelete(query as CFDictionary)
Expand Down Expand Up @@ -1219,17 +1199,17 @@ extension Keychain: CustomStringConvertible, CustomDebugStringConvertible {

extension Options {

func query(exactly: Bool = false) -> [String: Any] {
func query(ignoringAttributeSynchronizable: Bool = true) -> [String: Any] {
var query = [String: Any]()

query[Class] = itemClass.rawValue
if let accessGroup = self.accessGroup {
query[AttributeAccessGroup] = accessGroup
}
if exactly {
query[AttributeSynchronizable] = attributes[AttributeSynchronizable] ?? SynchronizableAny
} else {
if ignoringAttributeSynchronizable {
query[AttributeSynchronizable] = SynchronizableAny
} else {
query[AttributeSynchronizable] = synchronizable ? kCFBooleanTrue : kCFBooleanFalse
}

switch itemClass {
Expand Down
83 changes: 83 additions & 0 deletions Lib/KeychainAccessTests/KeychainAccessTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1618,4 +1618,87 @@ class KeychainAccessTests: XCTestCase {
}
#endif
}

func testIgnoringAttributeSynchronizable() {
let keychain = Keychain(service: "Twitter").synchronizable(false)
let keychainSynchronizable = Keychain(service: "Twitter").synchronizable(true)

XCTAssertNil(try! keychain.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertNil(try! keychain.get("password", ignoringAttributeSynchronizable: false), "not stored password")
XCTAssertNil(try! keychainSynchronizable.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertNil(try! keychainSynchronizable.get("password", ignoringAttributeSynchronizable: false), "not stored password")

do { try keychain.set("kishikawakatsumi", key: "username", ignoringAttributeSynchronizable: false) } catch {}
do { try keychainSynchronizable.set("kishikawakatsumi_synchronizable", key: "username", ignoringAttributeSynchronizable: false) } catch {}
XCTAssertEqual(try! keychain.get("username", ignoringAttributeSynchronizable: false), "kishikawakatsumi", "stored username")
XCTAssertEqual(try! keychainSynchronizable.get("username", ignoringAttributeSynchronizable: false), "kishikawakatsumi_synchronizable", "stored username")
XCTAssertNil(try! keychain.get("password", ignoringAttributeSynchronizable: false), "not stored password")
XCTAssertNil(try! keychainSynchronizable.get("password", ignoringAttributeSynchronizable: false), "not stored password")

do { try keychain.set("password1234", key: "password", ignoringAttributeSynchronizable: false) } catch {}
do { try keychainSynchronizable.set("password1234_synchronizable", key: "password", ignoringAttributeSynchronizable: false) } catch {}
XCTAssertEqual(try! keychain.get("username", ignoringAttributeSynchronizable: false), "kishikawakatsumi", "stored username")
XCTAssertEqual(try! keychainSynchronizable.get("username", ignoringAttributeSynchronizable: false), "kishikawakatsumi_synchronizable", "stored username")
XCTAssertEqual(try! keychain.get("password", ignoringAttributeSynchronizable: false), "password1234", "stored password")
XCTAssertEqual(try! keychainSynchronizable.get("password", ignoringAttributeSynchronizable: false), "password1234_synchronizable", "stored password")

do { try keychain.remove("username", ignoringAttributeSynchronizable: false) } catch {}
XCTAssertNil(try! keychain.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertEqual(try! keychainSynchronizable.get("username", ignoringAttributeSynchronizable: false), "kishikawakatsumi_synchronizable", "stored username")

do { try keychainSynchronizable.remove("username", ignoringAttributeSynchronizable: false) } catch {}
XCTAssertNil(try! keychain.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertNil(try! keychainSynchronizable.get("username", ignoringAttributeSynchronizable: false), "not stored username")

XCTAssertEqual(try! keychain.get("password", ignoringAttributeSynchronizable: false), "password1234", "stored password")
XCTAssertEqual(try! keychainSynchronizable.get("password", ignoringAttributeSynchronizable: false), "password1234_synchronizable", "stored password")

do { try keychain.removeAll() } catch {}
XCTAssertNil(try! keychain.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertNil(try! keychainSynchronizable.get("username", ignoringAttributeSynchronizable: false), "not stored username")
XCTAssertNil(try! keychain.get("password", ignoringAttributeSynchronizable: false), "not stored password")
XCTAssertNil(try! keychainSynchronizable.get("password", ignoringAttributeSynchronizable: false), "not stored password")
}

func testIgnoringAttributeSynchronizableBackwardCompatibility() {
let keychain = Keychain(service: "Twitter").synchronizable(false)
let keychainSynchronizable = Keychain(service: "Twitter").synchronizable(true)

XCTAssertNil(try! keychain.get("username"), "not stored username")
XCTAssertNil(try! keychain.get("password"), "not stored password")
XCTAssertNil(try! keychainSynchronizable.get("username"), "not stored username")
XCTAssertNil(try! keychainSynchronizable.get("password"), "not stored password")

do { try keychain.set("kishikawakatsumi", key: "username") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi", "stored username")
XCTAssertEqual(try! keychainSynchronizable.get("username"), "kishikawakatsumi", "stored username")

do { try keychainSynchronizable.set("kishikawakatsumi_synchronizable", key: "username") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi_synchronizable", "stored username")
XCTAssertEqual(try! keychainSynchronizable.get("username"), "kishikawakatsumi_synchronizable", "stored username")
XCTAssertNil(try! keychain.get("password"), "not stored password")
XCTAssertNil(try! keychainSynchronizable.get("password"), "not stored password")

do { try keychain.set("password1234", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("password"), "password1234", "stored password")
XCTAssertEqual(try! keychainSynchronizable.get("password"), "password1234", "stored password")

do { try keychainSynchronizable.set("password1234_synchronizable", key: "password") } catch {}
XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi_synchronizable", "stored username")
XCTAssertEqual(try! keychainSynchronizable.get("username"), "kishikawakatsumi_synchronizable", "stored username")
XCTAssertEqual(try! keychain.get("password"), "password1234_synchronizable", "stored password")
XCTAssertEqual(try! keychainSynchronizable.get("password"), "password1234_synchronizable", "stored password")

do { try keychain.remove("username") } catch {}
XCTAssertNil(try! keychain.get("username"), "not stored username")
XCTAssertNil(try! keychainSynchronizable.get("username"), "not stored username")
XCTAssertEqual(try! keychain.get("password"), "password1234_synchronizable", "stored password")
XCTAssertEqual(try! keychainSynchronizable.get("password"), "password1234_synchronizable", "stored password")

do { try keychain.removeAll() } catch {}
XCTAssertNil(try! keychain.get("username"), "not stored username")
XCTAssertNil(try! keychainSynchronizable.get("username"), "not stored username")
XCTAssertNil(try! keychain.get("password"), "not stored password")
XCTAssertNil(try! keychainSynchronizable.get("password"), "not stored password")
}
}

0 comments on commit 046b2c7

Please sign in to comment.