From 330d796442b217473875a96ca62c5d35119f7075 Mon Sep 17 00:00:00 2001 From: Justin Mazzocchi <2831158+jzzocc@users.noreply.github.com> Date: Sat, 8 Aug 2020 18:29:05 -0700 Subject: [PATCH] Refactoring --- Development Assets/DevelopmentModels.swift | 4 +-- Development Assets/FakeKeychain.swift | 16 +++++---- Development Assets/MockKeychainService.swift | 21 +++++++++++ ...rDefaults.swift => MockUserDefaults.swift} | 6 ++-- Metatext.xcodeproj/project.pbxproj | 36 +++++++++---------- Shared/MetatextApp.swift | 2 +- Shared/Model/Secrets.swift | 14 ++++---- .../KeychainService.swift} | 20 +++++------ 8 files changed, 72 insertions(+), 47 deletions(-) create mode 100644 Development Assets/MockKeychainService.swift rename Development Assets/{FakeUserDefaults.swift => MockUserDefaults.swift} (74%) rename Shared/{Model/Keychain.swift => Services/KeychainService.swift} (75%) diff --git a/Development Assets/DevelopmentModels.swift b/Development Assets/DevelopmentModels.swift index 19eb217..964d696 100644 --- a/Development Assets/DevelopmentModels.swift +++ b/Development Assets/DevelopmentModels.swift @@ -11,7 +11,7 @@ private let devIdentityID = UUID(uuidString: "E621E1F8-C36C-495A-93FC-0C247A3E6E private let devAccessToken = "DEVELOPMENT_ACCESS_TOKEN" extension Secrets { - static func fresh() -> Secrets { Secrets(keychain: FakeKeychain()) } + static func fresh() -> Secrets { Secrets(keychainService: MockKeychainService()) } static let development: Secrets = { let secrets = Secrets.fresh() @@ -25,7 +25,7 @@ extension Secrets { } extension Defaults { - static func fresh() -> Defaults { Defaults(userDefaults: FakeUserDefaults()) } + static func fresh() -> Defaults { Defaults(userDefaults: MockUserDefaults()) } static let development: Defaults = { let preferences = Defaults.fresh() diff --git a/Development Assets/FakeKeychain.swift b/Development Assets/FakeKeychain.swift index 467f182..cdaa093 100644 --- a/Development Assets/FakeKeychain.swift +++ b/Development Assets/FakeKeychain.swift @@ -2,18 +2,20 @@ import Foundation -typealias FakeKeychain = [String: Data] +class MockKeychainService { + private var guts = [String: Data]() +} -extension FakeKeychain: KeychainType { - mutating func set(data: Data, forKey key: String) throws { - self[key] = data +extension MockKeychainService: KeychainServiceType { + func set(data: Data, forKey key: String) throws { + guts[key] = data } - mutating func deleteData(key: String) throws { - self[key] = nil + func deleteData(key: String) throws { + guts[key] = nil } func getData(key: String) throws -> Data? { - self[key] + guts[key] } } diff --git a/Development Assets/MockKeychainService.swift b/Development Assets/MockKeychainService.swift new file mode 100644 index 0000000..4bd1987 --- /dev/null +++ b/Development Assets/MockKeychainService.swift @@ -0,0 +1,21 @@ +// Copyright © 2020 Metabolist. All rights reserved. + +import Foundation + +class MockKeychainService { + private var items = [String: Data]() +} + +extension MockKeychainService: KeychainServiceType { + func set(data: Data, forKey key: String) throws { + items[key] = data + } + + func deleteData(key: String) throws { + items[key] = nil + } + + func getData(key: String) throws -> Data? { + items[key] + } +} diff --git a/Development Assets/FakeUserDefaults.swift b/Development Assets/MockUserDefaults.swift similarity index 74% rename from Development Assets/FakeUserDefaults.swift rename to Development Assets/MockUserDefaults.swift index b9236f0..6990b20 100644 --- a/Development Assets/FakeUserDefaults.swift +++ b/Development Assets/MockUserDefaults.swift @@ -2,7 +2,7 @@ import Foundation -class FakeUserDefaults: UserDefaults { +class MockUserDefaults: UserDefaults { convenience init() { self.init(suiteName: Self.suiteName)! } @@ -16,6 +16,6 @@ class FakeUserDefaults: UserDefaults { } } -private extension FakeUserDefaults { - private static let suiteName = "com.metatext.metabolist.fake-user-defaults" +private extension MockUserDefaults { + private static let suiteName = "com.metatext.metabolist.mock-user-defaults" } diff --git a/Metatext.xcodeproj/project.pbxproj b/Metatext.xcodeproj/project.pbxproj index 2ce138b..677eea2 100644 --- a/Metatext.xcodeproj/project.pbxproj +++ b/Metatext.xcodeproj/project.pbxproj @@ -55,8 +55,8 @@ D04FD74224D4AA34007D572D /* DevelopmentModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04FD74124D4AA34007D572D /* DevelopmentModels.swift */; }; D04FD74324D4AA34007D572D /* DevelopmentModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04FD74124D4AA34007D572D /* DevelopmentModels.swift */; }; D052BBC724D749C800A80A7A /* RootViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBC624D749C800A80A7A /* RootViewModelTests.swift */; }; - D052BBCA24D74C9200A80A7A /* FakeUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBC824D74B6400A80A7A /* FakeUserDefaults.swift */; }; - D052BBCB24D74C9300A80A7A /* FakeUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBC824D74B6400A80A7A /* FakeUserDefaults.swift */; }; + D052BBCA24D74C9200A80A7A /* MockUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBC824D74B6400A80A7A /* MockUserDefaults.swift */; }; + D052BBCB24D74C9300A80A7A /* MockUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBC824D74B6400A80A7A /* MockUserDefaults.swift */; }; D052BBCF24D750C000A80A7A /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBCE24D750C000A80A7A /* Defaults.swift */; }; D052BBD024D750C000A80A7A /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBCE24D750C000A80A7A /* Defaults.swift */; }; D052BBD124D750CA00A80A7A /* AppEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D052BBCC24D750A100A80A7A /* AppEnvironment.swift */; }; @@ -134,12 +134,12 @@ D0DC175C24D0154F00A75C65 /* MastodonAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC175A24D0154F00A75C65 /* MastodonAPI.swift */; }; D0DC175F24D016EA00A75C65 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = D0DC175E24D016EA00A75C65 /* Alamofire */; }; D0DC176124D0171800A75C65 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = D0DC176024D0171800A75C65 /* Alamofire */; }; - D0DC177424D0B58800A75C65 /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC177324D0B58800A75C65 /* Keychain.swift */; }; - D0DC177524D0B58800A75C65 /* Keychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC177324D0B58800A75C65 /* Keychain.swift */; }; - D0DC177724D0CF2600A75C65 /* FakeKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC177624D0CF2600A75C65 /* FakeKeychain.swift */; }; - D0DC177824D0CF2600A75C65 /* FakeKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC177624D0CF2600A75C65 /* FakeKeychain.swift */; }; + D0DC177724D0CF2600A75C65 /* MockKeychainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC177624D0CF2600A75C65 /* MockKeychainService.swift */; }; + D0DC177824D0CF2600A75C65 /* MockKeychainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DC177624D0CF2600A75C65 /* MockKeychainService.swift */; }; D0EC8DC224DF7D9C00A08489 /* IdentityService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EC8DC124DF7D9C00A08489 /* IdentityService.swift */; }; D0EC8DC324DF7D9C00A08489 /* IdentityService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EC8DC124DF7D9C00A08489 /* IdentityService.swift */; }; + D0EC8DC524DF842700A08489 /* KeychainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EC8DC424DF842700A08489 /* KeychainService.swift */; }; + D0EC8DC624DF842700A08489 /* KeychainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EC8DC424DF842700A08489 /* KeychainService.swift */; }; D0ED1B6E24CE100C00B4899C /* AddIdentityViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED1B6D24CE100C00B4899C /* AddIdentityViewModelTests.swift */; }; D0ED1BB724CE47F400B4899C /* WebAuthSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED1BB624CE47F400B4899C /* WebAuthSession.swift */; }; D0ED1BB824CE47F400B4899C /* WebAuthSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED1BB624CE47F400B4899C /* WebAuthSession.swift */; }; @@ -204,7 +204,7 @@ D04FD73B24D4A83A007D572D /* InstanceEndpoint+Stubbing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InstanceEndpoint+Stubbing.swift"; sourceTree = ""; }; D04FD74124D4AA34007D572D /* DevelopmentModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevelopmentModels.swift; sourceTree = ""; }; D052BBC624D749C800A80A7A /* RootViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootViewModelTests.swift; sourceTree = ""; }; - D052BBC824D74B6400A80A7A /* FakeUserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FakeUserDefaults.swift; sourceTree = ""; }; + D052BBC824D74B6400A80A7A /* MockUserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUserDefaults.swift; sourceTree = ""; }; D052BBCC24D750A100A80A7A /* AppEnvironment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppEnvironment.swift; sourceTree = ""; }; D052BBCE24D750C000A80A7A /* Defaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Defaults.swift; sourceTree = ""; }; D065F53A24D3B33A00741304 /* View+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Extensions.swift"; sourceTree = ""; }; @@ -242,9 +242,9 @@ D0DC175424D00F0A00A75C65 /* AccessTokenEndpoint+Stubbing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccessTokenEndpoint+Stubbing.swift"; sourceTree = ""; }; D0DC175724D0130800A75C65 /* HTTPStubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPStubs.swift; sourceTree = ""; }; D0DC175A24D0154F00A75C65 /* MastodonAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonAPI.swift; sourceTree = ""; }; - D0DC177324D0B58800A75C65 /* Keychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keychain.swift; sourceTree = ""; }; - D0DC177624D0CF2600A75C65 /* FakeKeychain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FakeKeychain.swift; sourceTree = ""; }; + D0DC177624D0CF2600A75C65 /* MockKeychainService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockKeychainService.swift; sourceTree = ""; }; D0EC8DC124DF7D9C00A08489 /* IdentityService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IdentityService.swift; sourceTree = ""; }; + D0EC8DC424DF842700A08489 /* KeychainService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainService.swift; sourceTree = ""; }; D0ED1B6D24CE100C00B4899C /* AddIdentityViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddIdentityViewModelTests.swift; sourceTree = ""; }; D0ED1BB624CE47F400B4899C /* WebAuthSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebAuthSession.swift; sourceTree = ""; }; D0ED1BC024CED48800B4899C /* HTTPClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTTPClient.swift; sourceTree = ""; }; @@ -350,6 +350,7 @@ isa = PBXGroup; children = ( D0EC8DC124DF7D9C00A08489 /* IdentityService.swift */, + D0EC8DC424DF842700A08489 /* KeychainService.swift */, ); path = Services; sourceTree = ""; @@ -437,7 +438,6 @@ D0666A5324C6C3E500F3F04B /* Emoji.swift */, D0666A4A24C6C37700F3F04B /* Identity.swift */, D0666A4D24C6C39600F3F04B /* Instance.swift */, - D0DC177324D0B58800A75C65 /* Keychain.swift */, D0ED1BE224CFA84400B4899C /* MastodonError.swift */, D0CD847224DBDEC700CF380C /* MastodonPreferences.swift */, D0666A7124C6E0D300F3F04B /* Secrets.swift */, @@ -536,8 +536,8 @@ isa = PBXGroup; children = ( D04FD74124D4AA34007D572D /* DevelopmentModels.swift */, - D0DC177624D0CF2600A75C65 /* FakeKeychain.swift */, - D052BBC824D74B6400A80A7A /* FakeUserDefaults.swift */, + D0DC177624D0CF2600A75C65 /* MockKeychainService.swift */, + D052BBC824D74B6400A80A7A /* MockUserDefaults.swift */, D0DC175724D0130800A75C65 /* HTTPStubs.swift */, D0DC174824CFF13700A75C65 /* Mastodon API Stubs */, D0DC174C24CFF1F100A75C65 /* Stubbing.swift */, @@ -783,13 +783,14 @@ D0DC175524D00F0A00A75C65 /* AccessTokenEndpoint+Stubbing.swift in Sources */, D0B23F0D24D210E90066F411 /* NSError+Extensions.swift in Sources */, D019E6D924DF728400697C7D /* MastodonDecoder.swift in Sources */, - D052BBCA24D74C9200A80A7A /* FakeUserDefaults.swift in Sources */, + D052BBCA24D74C9200A80A7A /* MockUserDefaults.swift in Sources */, D0DC175224D008E300A75C65 /* MastodonTarget+Stubbing.swift in Sources */, D0BEC94A24CA231200E864C4 /* TimelineView.swift in Sources */, D0BEC93B24C96FD500E864C4 /* RootView.swift in Sources */, D04FD74224D4AA34007D572D /* DevelopmentModels.swift in Sources */, + D0EC8DC524DF842700A08489 /* KeychainService.swift in Sources */, D0DC175824D0130800A75C65 /* HTTPStubs.swift in Sources */, - D0DC177724D0CF2600A75C65 /* FakeKeychain.swift in Sources */, + D0DC177724D0CF2600A75C65 /* MockKeychainService.swift in Sources */, D0EC8DC224DF7D9C00A08489 /* IdentityService.swift in Sources */, D0C963FB24CC359D003BD330 /* AlertItem.swift in Sources */, D0DC174624CFEC2000A75C65 /* StubbingURLProtocol.swift in Sources */, @@ -802,7 +803,6 @@ D0091B6E24DD68090040E8D2 /* PreferencesView.swift in Sources */, D0159F8F24DE743700E78478 /* IdentitiesView.swift in Sources */, D0DB6EF424C5228A00D965FE /* AddIdentityView.swift in Sources */, - D0DC177424D0B58800A75C65 /* Keychain.swift in Sources */, D074577724D29006004758DB /* StubbingWebAuthSession.swift in Sources */, D0159FA524DE989700E78478 /* NSMutableAttributedString+Extensions.swift in Sources */, D0ED1BCE24CF768200B4899C /* MastodonEndpoint.swift in Sources */, @@ -855,7 +855,7 @@ D019E6E424DF72E700697C7D /* PreferencesEndpoint.swift in Sources */, D0DC175624D00F0A00A75C65 /* AccessTokenEndpoint+Stubbing.swift in Sources */, D0B23F0E24D210E90066F411 /* NSError+Extensions.swift in Sources */, - D052BBCB24D74C9300A80A7A /* FakeUserDefaults.swift in Sources */, + D052BBCB24D74C9300A80A7A /* MockUserDefaults.swift in Sources */, D0DC175324D008E300A75C65 /* MastodonTarget+Stubbing.swift in Sources */, D0BEC94B24CA231200E864C4 /* TimelineView.swift in Sources */, D0BEC93C24C96FD500E864C4 /* RootView.swift in Sources */, @@ -863,7 +863,7 @@ D04FD74324D4AA34007D572D /* DevelopmentModels.swift in Sources */, D0DC175924D0130800A75C65 /* HTTPStubs.swift in Sources */, D019E6DA24DF728400697C7D /* MastodonDecoder.swift in Sources */, - D0DC177824D0CF2600A75C65 /* FakeKeychain.swift in Sources */, + D0DC177824D0CF2600A75C65 /* MockKeychainService.swift in Sources */, D0C963FC24CC359D003BD330 /* AlertItem.swift in Sources */, D019E6E224DF72E700697C7D /* AppAuthorizationEndpoint.swift in Sources */, D0DC174724CFEC2000A75C65 /* StubbingURLProtocol.swift in Sources */, @@ -874,7 +874,6 @@ D0091B6F24DD68090040E8D2 /* PreferencesView.swift in Sources */, D0DB6EF524C5233E00D965FE /* AddIdentityView.swift in Sources */, D019E6EA24DF72E700697C7D /* InstanceEndpoint.swift in Sources */, - D0DC177524D0B58800A75C65 /* Keychain.swift in Sources */, D0159F9C24DE748C00E78478 /* SidebarNavigationView.swift in Sources */, D019E6F124DF7C2F00697C7D /* DatabaseError.swift in Sources */, D074577824D29006004758DB /* StubbingWebAuthSession.swift in Sources */, @@ -889,6 +888,7 @@ D04FD73D24D4A83A007D572D /* InstanceEndpoint+Stubbing.swift in Sources */, D0DC175C24D0154F00A75C65 /* MastodonAPI.swift in Sources */, D0ED1BD224CF779B00B4899C /* MastodonTarget.swift in Sources */, + D0EC8DC624DF842700A08489 /* KeychainService.swift in Sources */, D0CD847D24DBEA9F00CF380C /* Unknowable.swift in Sources */, D0666A7024C6DFB300F3F04B /* AccessToken.swift in Sources */, D0ED1BCC24CF744200B4899C /* MastodonClient.swift in Sources */, diff --git a/Shared/MetatextApp.swift b/Shared/MetatextApp.swift index 2944a73..19c6480 100644 --- a/Shared/MetatextApp.swift +++ b/Shared/MetatextApp.swift @@ -19,7 +19,7 @@ struct MetatextApp: App { URLSessionConfiguration: .default, identityDatabase: identityDatabase, defaults: Defaults(userDefaults: .standard), - secrets: Secrets(keychain: Keychain(service: "com.metabolist.metatext")), + secrets: Secrets(keychainService: KeychainService(serviceName: "com.metabolist.metatext")), webAuthSessionType: RealWebAuthSession.self) } diff --git a/Shared/Model/Secrets.swift b/Shared/Model/Secrets.swift index df16b40..b3f097a 100644 --- a/Shared/Model/Secrets.swift +++ b/Shared/Model/Secrets.swift @@ -12,10 +12,10 @@ enum SecretsStorableError: Error { } class Secrets { - private var keychain: KeychainType + private let keychainService: KeychainServiceType - init(keychain: KeychainType) { - self.keychain = keychain + init(keychainService: KeychainServiceType) { + self.keychainService = keychainService } } @@ -29,17 +29,19 @@ extension Secrets { extension Secrets { func set(_ data: SecretsStorable, forItem item: Item, forIdentityID identityID: UUID) throws { - try keychain.set(data: data.dataStoredInSecrets, forKey: Self.key(item: item, identityID: identityID)) + try keychainService.set(data: data.dataStoredInSecrets, forKey: Self.key(item: item, identityID: identityID)) } func item(_ item: Item, forIdentityID identityID: UUID) throws -> T? { - guard let data = try keychain.getData(key: Self.key(item: item, identityID: identityID)) else { return nil } + guard let data = try keychainService.getData(key: Self.key(item: item, identityID: identityID)) else { + return nil + } return try T.fromDataStoredInSecrets(data) } func delete(_ item: Item, forIdentityID identityID: UUID) throws { - try keychain.deleteData(key: Self.key(item: item, identityID: identityID)) + try keychainService.deleteData(key: Self.key(item: item, identityID: identityID)) } } diff --git a/Shared/Model/Keychain.swift b/Shared/Services/KeychainService.swift similarity index 75% rename from Shared/Model/Keychain.swift rename to Shared/Services/KeychainService.swift index 196fdfd..7b88b64 100644 --- a/Shared/Model/Keychain.swift +++ b/Shared/Services/KeychainService.swift @@ -2,18 +2,18 @@ import Foundation -protocol KeychainType { - mutating func set(data: Data, forKey key: String) throws - mutating func deleteData(key: String) throws +protocol KeychainServiceType { + func set(data: Data, forKey key: String) throws + func deleteData(key: String) throws func getData(key: String) throws -> Data? } -struct Keychain { - let service: String +struct KeychainService { + let serviceName: String } -extension Keychain: KeychainType { - mutating func set(data: Data, forKey key: String) throws { +extension KeychainService: KeychainServiceType { + func set(data: Data, forKey key: String) throws { var query = queryDictionary(key: key) query[kSecValueData as String] = data @@ -25,7 +25,7 @@ extension Keychain: KeychainType { } } - mutating func deleteData(key: String) throws { + func deleteData(key: String) throws { let status = SecItemDelete(queryDictionary(key: key) as CFDictionary) if status != errSecSuccess { @@ -53,10 +53,10 @@ extension Keychain: KeychainType { } } -private extension Keychain { +private extension KeychainService { private func queryDictionary(key: String) -> [String: Any] { [ - kSecAttrService as String: service, + kSecAttrService as String: serviceName, kSecAttrAccount as String: key, kSecClass as String: kSecClassGenericPassword ]