Skip to content

Commit

Permalink
Add AccountService & OTPService tests
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexCatch committed Sep 12, 2021
1 parent 2e2441b commit 107f6d9
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import CoreData

public class MockPersistentStore: PersistentStore {
private var persistentContainer: NSPersistentContainer!

public var viewContext: NSManagedObjectContext {
return persistentContainer.viewContext
}
Expand Down
14 changes: 10 additions & 4 deletions OakOTPCommon/Sources/OakOTPCommon/Services/OTPService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ import SwiftOTP

public protocol OTPService {
func parseSetupURI(uri: String) throws -> ParsedURI
func generateCode(account: Account) throws -> String
func generateCode(account: Account, date: Date) throws -> String
}

public extension OTPService {
func generateCode(account: Account, date: Date = Date()) throws -> String {
return try generateCode(account: account, date: date)
}
}

public struct ParsedURI {
Expand All @@ -27,7 +33,7 @@ public struct ParsedURI {
}

public class RealOTPService: OTPService {

public func parseSetupURI(uri: String) throws -> ParsedURI {
guard let url = URL(string: uri), let queryComponents = url.queryDictionary else {
throw OTPServiceError.invalidURI
Expand All @@ -53,9 +59,9 @@ public class RealOTPService: OTPService {
return parsedURI
}

public func generateCode(account: Account) throws -> String {
public func generateCode(account: Account, date: Date = Date()) throws -> String {
return account.type == .totp ?
try generateTOTP(account: account) :
try generateTOTP(account: account, date: date) :
try generateHOTP(account: account)
}

Expand Down
106 changes: 106 additions & 0 deletions OakOTPCommon/Tests/OakOTPCommonTests/AccountServiceTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import XCTest
import Resolver
@testable import OakOTPCommon

class InitalFetchSpy: AccountServiceDelegate {
let expectedAccounts: [Account]

var accountsChangedCalled = false

init(expectedAccounts: [Account]) {
self.expectedAccounts = expectedAccounts
}

func accountsChanged(accounts: [Account]) {
accountsChangedCalled = true
XCTAssertEqual(accounts.count, expectedAccounts.count)
}
}

class FilterSpy: AccountServiceDelegate {
var expectedAccounts: [Account]
var hasFiltered = false

init(expectedAccounts: [Account]) {
self.expectedAccounts = expectedAccounts
}

func accountsChanged(accounts: [Account]) {
XCTAssertEqual(accounts.count, expectedAccounts.count)

if hasFiltered {
XCTAssertEqual(accounts, expectedAccounts)
}
}
}

final class AccountServiceTests: OakOTPCommonTestCase {

/**
Scope for our mocked persistent store is shared
so to keep the same instance between our test and our account service
we need to keep a reference here
*/
var persistent: PersistentStore!

override func setUp() {
super.setUp()
persistent = Resolver.resolve(PersistentStore.self, name: nil, args: nil)
}

override func tearDown() {
super.tearDown()
persistent = nil
}

private func createAccounts() throws -> [Account] {
let persistent: PersistentStore = Resolver.resolve()
let account1 = Account(context: persistent.viewContext)
account1.issuer = "Google"
account1.name = "john@doe.co.uk"
account1.secret = "helloworld"
account1.algorithm = .sha1
account1.type = .totp
account1.createdAt = Date()
account1.digits = Int16(6)
account1.period = Int16(30)

let account2 = Account(context: persistent.viewContext)
account2.issuer = "Facebook"
account2.name = "john@doe.co.uk"
account2.secret = "helloworld123"
account2.algorithm = .sha1
account2.type = .totp
account2.createdAt = Date()
account2.digits = Int16(6)
account2.period = Int16(30)

try persistent.save()

return [account1, account2]
}

func testInitialFetch() throws {
let createdAccounts = try createAccounts()
let service = RealAccountService()

let initialFetchSpy = InitalFetchSpy(expectedAccounts: createdAccounts)
service.delegate = initialFetchSpy

XCTAssertTrue(initialFetchSpy.accountsChangedCalled)
}

func testFilter() throws {
let createdAccounts = try createAccounts()
let service = RealAccountService()

let filterSpy = FilterSpy(expectedAccounts: createdAccounts)
service.delegate = filterSpy

let predicate = NSPredicate(format: "name CONTAINS[cd] %@ OR issuer CONTAINS[cd] %@", "Facebook", "Facebook")
filterSpy.expectedAccounts = [createdAccounts.last!]
filterSpy.hasFiltered = true
try service.filter(predicate: predicate)

}
}
32 changes: 31 additions & 1 deletion OakOTPCommon/Tests/OakOTPCommonTests/OTPServiceTests.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
import XCTest
import Resolver
@testable import OakOTPCommon

final class OakOTPCommonTests: XCTestCase {
final class OTPServiceTests: OakOTPCommonTestCase {

private func createTOTPAccount() throws -> Account {
let persistent: PersistentStore = Resolver.resolve()
let account1 = Account(context: persistent.viewContext)
account1.issuer = "Google"
account1.name = "john@doe.co.uk"
account1.secret = "helloworld"
account1.algorithm = .sha1
account1.type = .totp
account1.createdAt = Date()
account1.digits = Int16(6)
account1.period = Int16(30)

try persistent.save()

return account1
}

func testTOTPBasicParseURISuccess() throws {
let testString = "otpauth://totp/alex%40alexcatchpoledev.me?secret=helloworld&issuer=Github"
let service = RealOTPService()
Expand Down Expand Up @@ -61,4 +80,15 @@ final class OakOTPCommonTests: XCTestCase {

XCTAssertNil(parsedURI.period)
}

func testTOTPCodeGeneration() throws {
let service = RealOTPService()
let account = try createTOTPAccount()

let date = Date(timeIntervalSinceReferenceDate: 653070472.957172)
let rightCodeForDate = "518279"
let code = try service.generateCode(account: account, date: date)

XCTAssertEqual(code, rightCodeForDate)
}
}
12 changes: 12 additions & 0 deletions OakOTPCommon/Tests/OakOTPCommonTests/OakOTPCommonTestCase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import XCTest
import Resolver

class OakOTPCommonTestCase: XCTestCase {
override func setUp() {
Resolver.resetUnitTestRegistrations()
}

override func tearDown() {
Resolver.root = .test
}
}
21 changes: 21 additions & 0 deletions OakOTPCommon/Tests/OakOTPCommonTests/Setup.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// Setup.swift
// OakTests
//
// Created by Alex Catchpole on 16/05/2021.
//

import Foundation
import OakOTPCommon
import Resolver

extension Resolver {
static var test: Resolver!

static func resetUnitTestRegistrations() {
Resolver.test = Resolver(parent: .main)
Resolver.root = .test

Resolver.test.register { MockPersistentStore() as PersistentStore }.scope(.shared)
}
}

0 comments on commit 107f6d9

Please sign in to comment.