From 22b6c582b357213534524a02c25d167373c2948e Mon Sep 17 00:00:00 2001 From: Diogo Autilio Date: Sun, 25 Feb 2024 10:40:45 -0300 Subject: [PATCH] Add LoansDetailViewControllerFactory Migrate LoansDetail to VIP --- .../LoansDetailViewController.swift | 68 +++++-------------- .../LoansDetailViewControllerFactory.swift | 34 ++++++++++ .../Navigator/PeopleListNavigator.swift | 2 +- .../LoansDetailViewControllerTests.swift | 38 ++++++++--- .../Doubles/LoansDetailsPresenterSpy.swift | 6 +- ...oansDetailViewControllerFactoryTests.swift | 32 +++++++++ 6 files changed, 115 insertions(+), 65 deletions(-) create mode 100644 SWDestinyTrades/Classes/LoanDetail/Factory/LoansDetailViewControllerFactory.swift create mode 100644 SWDestinyTradesTests/Screens/LoanDetail/Factory/LoansDetailViewControllerFactoryTests.swift diff --git a/SWDestinyTrades/Classes/LoanDetail/Controller/LoansDetailViewController.swift b/SWDestinyTrades/Classes/LoanDetail/Controller/LoansDetailViewController.swift index 1e3ea36b..5fcb346b 100644 --- a/SWDestinyTrades/Classes/LoanDetail/Controller/LoansDetailViewController.swift +++ b/SWDestinyTrades/Classes/LoanDetail/Controller/LoansDetailViewController.swift @@ -9,16 +9,15 @@ import UIKit final class LoansDetailViewController: UIViewController { - private let database: DatabaseProtocol? - private var personDTO: PersonDTO - private lazy var loanDetailView: LoanDetailViewType = LoanDetailTableView(delegate: self) - private lazy var navigator = LoanDetailNavigator(self) + + private let loanDetailView: LoanDetailViewType + + var presenter: LoansDetailPresenterProtocol? // MARK: - Life Cycle - init(database: DatabaseProtocol?, person: PersonDTO) { - self.database = database - personDTO = person + init(with view: LoanDetailViewType) { + loanDetailView = view super.init(nibName: nil, bundle: nil) } @@ -34,66 +33,31 @@ final class LoansDetailViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - loadDataFromRealm() + presenter?.loadDataFromRealm() loanDetailView.didSelectCard = { [weak self] card, destination in - self?.navigateToCardDetailViewController(with: card, destination: destination) + self?.presenter?.navigateToCardDetail(with: card, destination: destination) } loanDetailView.didSelectAddItem = { [weak self] type in - self?.navigateToAddCardViewController(type: type) + self?.presenter?.navigateToAddCard(type: type) } - - NotificationCenter.default.addObserver(self, selector: #selector(reloadTableView), name: NotificationKey.reloadTableViewNotification, object: nil) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - navigationItem.title = "\(personDTO.name) \(personDTO.lastName)" - } - - func loadDataFromRealm() { - loanDetailView.updateTableViewData(person: personDTO) - } - - @objc - private func reloadTableView(_ notification: NSNotification) { - if let person = notification.userInfo?["personDTO"] as? PersonDTO { - personDTO = person - loadDataFromRealm() - } - } - - // MARK: Navigation - - func navigateToCardDetailViewController(with card: CardDTO, destination: AddCardType) { - let source = destination == .lent ? personDTO.lentMe : personDTO.borrowed - navigator.navigate(to: .cardDetail(database: database, with: Array(source), card: card)) - } - - func navigateToAddCardViewController(type: AddCardType) { - navigator.navigate(to: .addCard(database: database, with: personDTO, type: type)) + presenter?.setNavigationTitle() } } -extension LoansDetailViewController: LoansDetailsProtocol { - func stepperValueChanged(newValue: Int, card: CardDTO) { - try? database?.update { - card.quantity = newValue - } +extension LoansDetailViewController: LoansDetailViewControllerProtocol { + + func updateTableViewData(person: PersonDTO) { + loanDetailView.updateTableViewData(person: person) } - func remove(from section: AddCardType, at index: Int) { - try? database?.update { [weak self] in - switch section { - case .lent: - self?.personDTO.lentMe.remove(at: index) - case .borrow: - self?.personDTO.borrowed.remove(at: index) - default: - break - } - } + func setNavigationTitle(_ title: String) { + navigationItem.title = title } } diff --git a/SWDestinyTrades/Classes/LoanDetail/Factory/LoansDetailViewControllerFactory.swift b/SWDestinyTrades/Classes/LoanDetail/Factory/LoansDetailViewControllerFactory.swift new file mode 100644 index 00000000..f92c7e9f --- /dev/null +++ b/SWDestinyTrades/Classes/LoanDetail/Factory/LoansDetailViewControllerFactory.swift @@ -0,0 +1,34 @@ +// +// LoansDetailViewControllerFactory.swift +// SWDestinyTrades +// +// Created by Diogo Autilio on 25/02/24. +// Copyright © 2024 Diogo Autilio. All rights reserved. +// + +import Foundation +import UIKit + +final class LoansDetailViewControllerFactory: ViewControllerFactory { + + private let database: DatabaseProtocol? + private let person: PersonDTO + + init(database: DatabaseProtocol?, person: PersonDTO) { + self.database = database + self.person = person + } + + func createViewController() -> UIViewController { + let view = LoanDetailTableView() + let viewController = LoansDetailViewController(with: view) + let router = LoanDetailNavigator(viewController) + let presenter = LoansDetailPresenter(controller: viewController, + database: database, + person: person, + navigator: router) + viewController.presenter = presenter + view.loansDetailDelegate = presenter + return viewController + } +} diff --git a/SWDestinyTrades/Classes/PeopleList/Navigator/PeopleListNavigator.swift b/SWDestinyTrades/Classes/PeopleList/Navigator/PeopleListNavigator.swift index 8f31abc6..f8c95018 100644 --- a/SWDestinyTrades/Classes/PeopleList/Navigator/PeopleListNavigator.swift +++ b/SWDestinyTrades/Classes/PeopleList/Navigator/PeopleListNavigator.swift @@ -34,7 +34,7 @@ final class PeopleListNavigator: Navigator { private func makeViewController(for destination: Destination) -> UIViewController { switch destination { case let .loanDetail(database, person): - return LoansDetailViewController(database: database, person: person) + return LoansDetailViewControllerFactory(database: database, person: person).createViewController() case let .newPerson(delegate): let viewController = NewPersonViewController() viewController.delegate = delegate diff --git a/SWDestinyTradesTests/Screens/LoanDetail/Controller/LoansDetailViewControllerTests.swift b/SWDestinyTradesTests/Screens/LoanDetail/Controller/LoansDetailViewControllerTests.swift index 47bd2647..56ed336f 100644 --- a/SWDestinyTradesTests/Screens/LoanDetail/Controller/LoansDetailViewControllerTests.swift +++ b/SWDestinyTradesTests/Screens/LoanDetail/Controller/LoansDetailViewControllerTests.swift @@ -14,6 +14,8 @@ import XCTest final class LoansDetailViewControllerTests: XCTestCase { private var sut: LoansDetailViewController! + private var view: LoanDetailViewSpy! + private var presenter: LoansDetailsPresenterSpy! private var navigationController: UINavigationController! private var keyWindow: UIWindow! private var database: RealmDatabase? @@ -22,7 +24,10 @@ final class LoansDetailViewControllerTests: XCTestCase { super.setUp() keyWindow = UIWindow(frame: .testDevice) database = RealmDatabaseHelper.createMemoryDatabase(identifier: #function) - sut = LoansDetailViewController(database: database, person: .stub()) + view = LoanDetailViewSpy() + presenter = LoansDetailsPresenterSpy() + sut = LoansDetailViewController(with: view) + sut.presenter = presenter navigationController = UINavigationControllerMock(rootViewController: sut) keyWindow.showTestWindow(controller: navigationController) } @@ -30,6 +35,7 @@ final class LoansDetailViewControllerTests: XCTestCase { override func tearDown() { navigationController = nil sut = nil + view = nil keyWindow.cleanTestWindow() super.tearDown() } @@ -43,28 +49,42 @@ final class LoansDetailViewControllerTests: XCTestCase { func test_viewDidLoad() { sut.viewDidLoad() - // XCTAssertEqual(presenter.didCallSetupNavigationItemsCount, 1) - // XCTAssertEqual(presenter.didCallLoadDataFromRealmCount, 1) + XCTAssertEqual(presenter.didCallLoadDataFromRealmCount, 1) } func test_didSelectCard() { sut.viewDidLoad() - // view.didSelectCard?(.stub()) + view.didSelectCard?(.stub(), .borrow) - // XCTAssertEqual(presenter.didCallNavigateToDeckBuilder.count, 1) + XCTAssertEqual(presenter.didCallNavigateToCardDetailValues.count, 1) + XCTAssertNotNil(presenter.didCallNavigateToCardDetailValues[0].card) + XCTAssertEqual(presenter.didCallNavigateToCardDetailValues[0].destination, .borrow) } func test_didSelectAddItem() { sut.viewDidLoad() - // view.didSelectCard?(.stub()) + view.didSelectAddItem?(.borrow) - // XCTAssertEqual(presenter.didCallNavigateToDeckBuilder.count, 1) + XCTAssertEqual(presenter.didCallNavigateToAddCardValues.count, 1) + XCTAssertEqual(presenter.didCallNavigateToAddCardValues[0], .borrow) } func test_viewWillAppear() { sut.viewWillAppear(false) - // XCTAssertEqual(presenter.didCallSetNavigationTitleCount, 1) - // XCTAssertEqual(view.didCallReloadDataCount, 1) + XCTAssertEqual(presenter.didCallSetNavigationTitleCount, 1) + } + + func test_updateTableViewData() { + sut.updateTableViewData(person: .stub()) + + XCTAssertEqual(view.didCallUpdateTableViewData.count, 1) + XCTAssertNotNil(view.didCallUpdateTableViewData[0]) + } + + func test_setNavigationTitle() { + sut.setNavigationTitle("Darth Vader") + + XCTAssertEqual(sut.navigationItem.title, "Darth Vader") } } diff --git a/SWDestinyTradesTests/Screens/LoanDetail/Doubles/LoansDetailsPresenterSpy.swift b/SWDestinyTradesTests/Screens/LoanDetail/Doubles/LoansDetailsPresenterSpy.swift index 614f3ee0..8fd5002f 100644 --- a/SWDestinyTradesTests/Screens/LoanDetail/Doubles/LoansDetailsPresenterSpy.swift +++ b/SWDestinyTradesTests/Screens/LoanDetail/Doubles/LoansDetailsPresenterSpy.swift @@ -17,17 +17,17 @@ final class LoansDetailsPresenterSpy: LoansDetailPresenterProtocol, LoansDetails func loadDataFromRealm() { didCallLoadDataFromRealmCount += 1 } - + private(set) var didCallSetNavigationTitleCount = 0 func setNavigationTitle() { didCallSetNavigationTitleCount += 1 } - + private(set) var didCallNavigateToCardDetailValues: [(card: CardDTO, destination: AddCardType)] = [] func navigateToCardDetail(with card: CardDTO, destination: AddCardType) { didCallNavigateToCardDetailValues.append((card, destination)) } - + private(set) var didCallNavigateToAddCardValues: [AddCardType] = [] func navigateToAddCard(type: AddCardType) { didCallNavigateToAddCardValues.append(type) diff --git a/SWDestinyTradesTests/Screens/LoanDetail/Factory/LoansDetailViewControllerFactoryTests.swift b/SWDestinyTradesTests/Screens/LoanDetail/Factory/LoansDetailViewControllerFactoryTests.swift new file mode 100644 index 00000000..cb5ec15b --- /dev/null +++ b/SWDestinyTradesTests/Screens/LoanDetail/Factory/LoansDetailViewControllerFactoryTests.swift @@ -0,0 +1,32 @@ +// +// LoansDetailViewControllerFactoryTests.swift +// SWDestinyTradesTests +// +// Created by Diogo Autilio on 25/02/24. +// Copyright © 2024 Diogo Autilio. All rights reserved. +// + +import Foundation +import XCTest + +@testable import SWDestinyTrades + +final class LoansDetailViewControllerFactoryTests: XCTestCase { + + private var sut: LoansDetailViewControllerFactory! + + override func setUp() { + super.setUp() + sut = LoansDetailViewControllerFactory(database: nil, + person: .stub()) + } + + override func tearDown() { + sut = nil + super.tearDown() + } + + func test_controller_creation() { + XCTAssertNotNil(sut.createViewController()) + } +}