Skip to content

Commit 747fa37

Browse files
committed
add unit test; refactor view-controller initialization
1 parent 8cbea8e commit 747fa37

File tree

13 files changed

+118
-155
lines changed

13 files changed

+118
-155
lines changed

Conjugar.xcodeproj/project.pbxproj

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@
1616
038E031E22734800005CFC96 /* URLProtocolStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 038E031D22734800005CFC96 /* URLProtocolStub.swift */; };
1717
038E03202273BF29005CFC96 /* RatingsFetcherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 038E031F2273BF29005CFC96 /* RatingsFetcherTests.swift */; };
1818
038E032222760A40005CFC96 /* UIViewExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 038E032122760A40005CFC96 /* UIViewExtensionsTests.swift */; };
19-
038E0324227617FC005CFC96 /* UIApplicationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 038E0323227617FC005CFC96 /* UIApplicationTests.swift */; };
19+
038E0324227617FC005CFC96 /* UIApplicationExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 038E0323227617FC005CFC96 /* UIApplicationExtensionTests.swift */; };
2020
038E03262279CCCB005CFC96 /* SettingsVCTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 038E03252279CCCB005CFC96 /* SettingsVCTests.swift */; };
2121
038E03282279D034005CFC96 /* URLSessionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 038E03272279D034005CFC96 /* URLSessionExtension.swift */; };
22+
038E032A227CD8B7005CFC96 /* UIAlertControllerExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 038E0329227CD8B7005CFC96 /* UIAlertControllerExtensionTests.swift */; };
2223
E10178021F3F753400F0BC97 /* UIViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10178011F3F753400F0BC97 /* UIViewExtensions.swift */; };
2324
E107B08B1EB66CE6004C5E91 /* verbs.xml in Resources */ = {isa = PBXBuildFile; fileRef = E107B08A1EB66CE6004C5E91 /* verbs.xml */; };
2425
E107B0921EB66F28004C5E91 /* VerbParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = E107B0911EB66F28004C5E91 /* VerbParser.swift */; };
@@ -162,9 +163,10 @@
162163
038E031D22734800005CFC96 /* URLProtocolStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLProtocolStub.swift; sourceTree = "<group>"; };
163164
038E031F2273BF29005CFC96 /* RatingsFetcherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RatingsFetcherTests.swift; sourceTree = "<group>"; };
164165
038E032122760A40005CFC96 /* UIViewExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewExtensionsTests.swift; sourceTree = "<group>"; };
165-
038E0323227617FC005CFC96 /* UIApplicationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIApplicationTests.swift; sourceTree = "<group>"; };
166+
038E0323227617FC005CFC96 /* UIApplicationExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIApplicationExtensionTests.swift; sourceTree = "<group>"; };
166167
038E03252279CCCB005CFC96 /* SettingsVCTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsVCTests.swift; sourceTree = "<group>"; };
167168
038E03272279D034005CFC96 /* URLSessionExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLSessionExtension.swift; sourceTree = "<group>"; };
169+
038E0329227CD8B7005CFC96 /* UIAlertControllerExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIAlertControllerExtensionTests.swift; sourceTree = "<group>"; };
168170
E10178011F3F753400F0BC97 /* UIViewExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewExtensions.swift; sourceTree = "<group>"; };
169171
E107B08A1EB66CE6004C5E91 /* verbs.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = verbs.xml; sourceTree = "<group>"; };
170172
E107B0911EB66F28004C5E91 /* VerbParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerbParser.swift; sourceTree = "<group>"; };
@@ -426,7 +428,8 @@
426428
038E03122270A868005CFC96 /* IntExtensionTests.swift */,
427429
038E031F2273BF29005CFC96 /* RatingsFetcherTests.swift */,
428430
038E03142270A9FB005CFC96 /* TestGameCenterTests.swift */,
429-
038E0323227617FC005CFC96 /* UIApplicationTests.swift */,
431+
038E0329227CD8B7005CFC96 /* UIAlertControllerExtensionTests.swift */,
432+
038E0323227617FC005CFC96 /* UIApplicationExtensionTests.swift */,
430433
038E031922711B76005CFC96 /* UIViewControllerExtensionTests.swift */,
431434
038E032122760A40005CFC96 /* UIViewExtensionsTests.swift */,
432435
);
@@ -849,14 +852,15 @@
849852
isa = PBXSourcesBuildPhase;
850853
buildActionMask = 2147483647;
851854
files = (
852-
038E0324227617FC005CFC96 /* UIApplicationTests.swift in Sources */,
855+
038E0324227617FC005CFC96 /* UIApplicationExtensionTests.swift in Sources */,
853856
038E03182270AC01005CFC96 /* DeviceUtilityTests.swift in Sources */,
854857
E12D06A31F5E85A200CDD54E /* VerbCellTests.swift in Sources */,
855858
038E032222760A40005CFC96 /* UIViewExtensionsTests.swift in Sources */,
856859
038E031A22711B76005CFC96 /* UIViewControllerExtensionTests.swift in Sources */,
857860
038E03132270A868005CFC96 /* IntExtensionTests.swift in Sources */,
858861
E151223121A62AE9008EF307 /* ReviewPrompterTests.swift in Sources */,
859862
E1DC939521B5836400DD4048 /* QuizTests.swift in Sources */,
863+
038E032A227CD8B7005CFC96 /* UIAlertControllerExtensionTests.swift in Sources */,
860864
E198F9051F5D7CB200BAF553 /* ConjugatorTests.swift in Sources */,
861865
E1EC70F22198A10B00872787 /* UIViewControllerExtension.swift in Sources */,
862866
E14589F41F5B7BB000EEF141 /* BrowseInfoVCTests.swift in Sources */,

Conjugar/BrowseInfoVC.swift

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ class BrowseInfoVC: UIViewController, UITableViewDelegate, UITableViewDataSource
1313
private var allInfos: [Info] = []
1414
private var easyModerateInfos: [Info] = []
1515
private var easyInfos: [Info] = []
16-
private var settings: Settings?
17-
private var analyticsService: AnalyticsServiceable?
16+
private let settings: Settings
17+
private let analyticsService: AnalyticsServiceable
1818

1919
private var currentInfos: [Info] {
2020
switch browseInfoView.difficultyControl.selectedSegmentIndex {
@@ -37,10 +37,14 @@ class BrowseInfoVC: UIViewController, UITableViewDelegate, UITableViewDataSource
3737
}
3838
}
3939

40-
convenience init(settings: Settings, analyticsService: AnalyticsServiceable) {
41-
self.init()
40+
init(settings: Settings, analyticsService: AnalyticsServiceable) {
4241
self.settings = settings
4342
self.analyticsService = analyticsService
43+
super.init(nibName: nil, bundle: nil)
44+
}
45+
46+
required init?(coder aDecoder: NSCoder) {
47+
fatalError("init(coder:) has not been implemented")
4448
}
4549

4650
override func loadView() {
@@ -66,13 +70,10 @@ class BrowseInfoVC: UIViewController, UITableViewDelegate, UITableViewDataSource
6670

6771
override func viewWillAppear(_ animated: Bool) {
6872
super.viewWillAppear(animated)
69-
analyticsService?.recordVisitation(viewController: "\(BrowseInfoVC.self)")
73+
analyticsService.recordVisitation(viewController: "\(BrowseInfoVC.self)")
7074
}
7175

7276
private func updateDifficultyControl() {
73-
guard let settings = settings else {
74-
fatalError("settings was nil.")
75-
}
7677
switch settings.infoDifficulty {
7778
case .easy:
7879
browseInfoView.difficultyControl.selectedSegmentIndex = 0
@@ -115,19 +116,11 @@ class BrowseInfoVC: UIViewController, UITableViewDelegate, UITableViewDataSource
115116
}
116117

117118
private func showInfo() {
118-
guard let analyticsService = analyticsService else {
119-
fatalError("analyticsService was nil.")
120-
}
121-
let infoVC = InfoVC(analyticsService: analyticsService)
122-
infoVC.infoString = currentInfos[selectedRow].infoString
123-
infoVC.infoDelegate = self
119+
let infoVC = InfoVC(analyticsService: analyticsService, infoString: currentInfos[selectedRow].infoString, infoDelegate: self)
124120
navigationController?.pushViewController(infoVC, animated: true)
125121
}
126122

127123
@objc func difficultyChanged(_ sender: UISegmentedControl) {
128-
guard let settings = settings else {
129-
fatalError("settings was nil.")
130-
}
131124
let index = browseInfoView.difficultyControl.selectedSegmentIndex
132125
if index == 0 {
133126
settings.infoDifficulty = .easy

Conjugar/BrowseVerbsVC.swift

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ class BrowseVerbsVC: UIViewController, UITableViewDelegate, UITableViewDataSourc
1212
private var allVerbs: [String] = []
1313
private var regularVerbs: [String] = []
1414
private var irregularVerbs: [String] = []
15-
private var settings: Settings?
16-
private var analyticsService: AnalyticsServiceable?
17-
private var reviewPrompter: ReviewPromptable?
15+
private let settings: Settings
16+
private let analyticsService: AnalyticsServiceable
17+
private let reviewPrompter: ReviewPromptable
1818

1919
private var currentVerbs: [String] {
2020
switch browseVerbsView.filterControl.selectedSegmentIndex {
@@ -37,11 +37,15 @@ class BrowseVerbsVC: UIViewController, UITableViewDelegate, UITableViewDataSourc
3737
}
3838
}
3939

40-
convenience init(settings: Settings, analyticsService: AnalyticsServiceable, reviewPrompter: ReviewPromptable) {
41-
self.init()
40+
init(settings: Settings, analyticsService: AnalyticsServiceable, reviewPrompter: ReviewPromptable) {
4241
self.settings = settings
4342
self.analyticsService = analyticsService
4443
self.reviewPrompter = reviewPrompter
44+
super.init(nibName: nil, bundle: nil)
45+
}
46+
47+
required init?(coder aDecoder: NSCoder) {
48+
fatalError("init(coder:) has not been implemented")
4549
}
4650

4751
override func loadView() {
@@ -53,13 +57,13 @@ class BrowseVerbsVC: UIViewController, UITableViewDelegate, UITableViewDataSourc
5357
irregularVerbs = Conjugator.shared.irregularVerbsArray()
5458
navigationItem.titleView = UILabel.titleLabel(title: "Browse")
5559
view = browseVerbsView
56-
reviewPrompter?.promptableActionHappened()
60+
reviewPrompter.promptableActionHappened()
5761
}
5862

5963
override func viewWillAppear(_ animated: Bool) {
6064
super.viewWillAppear(animated)
6165
browseVerbsView.isHidden = false
62-
analyticsService?.recordVisitation(viewController: "\(BrowseVerbsVC.self)")
66+
analyticsService.recordVisitation(viewController: "\(BrowseVerbsVC.self)")
6367
}
6468

6569
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
@@ -75,15 +79,8 @@ class BrowseVerbsVC: UIViewController, UITableViewDelegate, UITableViewDataSourc
7579
}
7680

7781
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
78-
guard let settings = settings else {
79-
fatalError("settings was nil.")
80-
}
81-
guard let analyticsService = analyticsService else {
82-
fatalError("analyticsService was nil.")
83-
}
8482
tableView.deselectRow(at: indexPath, animated: false)
85-
let verbVC = VerbVC(settings: settings, analyticsService: analyticsService)
86-
verbVC.verb = currentVerbs[indexPath.row]
83+
let verbVC = VerbVC(verb: currentVerbs[indexPath.row], settings: settings, analyticsService: analyticsService)
8784
browseVerbsView.isHidden = true
8885
navigationController?.pushViewController(verbVC, animated: true)
8986
}

Conjugar/InfoVC.swift

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
import UIKit
1010

1111
class InfoVC: UIViewController, UITextViewDelegate {
12-
weak var infoDelegate: InfoDelegate?
13-
var infoString: NSAttributedString?
14-
private var analyticsService: AnalyticsServiceable?
12+
private weak var infoDelegate: InfoDelegate?
13+
private let infoString: NSAttributedString
14+
private let analyticsService: AnalyticsServiceable
1515

1616
var infoView: InfoView {
1717
if let castedView = view as? InfoView {
@@ -21,17 +21,20 @@ class InfoVC: UIViewController, UITextViewDelegate {
2121
}
2222
}
2323

24-
convenience init(analyticsService: AnalyticsServiceable) {
25-
self.init()
24+
init(analyticsService: AnalyticsServiceable, infoString: NSAttributedString, infoDelegate: InfoDelegate) {
2625
self.analyticsService = analyticsService
26+
self.infoString = infoString
27+
self.infoDelegate = infoDelegate
28+
super.init(nibName: nil, bundle: nil)
29+
}
30+
31+
required init?(coder aDecoder: NSCoder) {
32+
fatalError("init(coder:) has not been implemented")
2733
}
2834

2935
override func loadView() {
3036
let infoView: InfoView
3137
infoView = InfoView(frame: UIScreen.main.bounds)
32-
guard let infoString = infoString else {
33-
fatalError("InfoVC's infoString property is nil.")
34-
}
3538
infoView.info.attributedText = infoString
3639
infoView.info.delegate = self
3740
infoView.info.contentOffset = CGPoint.zero
@@ -40,7 +43,7 @@ class InfoVC: UIViewController, UITextViewDelegate {
4043

4144
override func viewWillAppear(_ animated: Bool) {
4245
super.viewWillAppear(animated)
43-
analyticsService?.recordVisitation(viewController: "\(InfoVC.self)")
46+
analyticsService.recordVisitation(viewController: "\(InfoVC.self)")
4447
}
4548

4649
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {

Conjugar/QuizVC.swift

Lines changed: 14 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
import UIKit
1010

1111
class QuizVC: UIViewController, UITextFieldDelegate, QuizDelegate {
12-
private var settings: Settings?
13-
private var quiz: Quiz?
14-
private var analyticsService: AnalyticsServiceable?
15-
private var gameCenter: GameCenterable?
12+
private let settings: Settings
13+
private let quiz: Quiz
14+
private let analyticsService: AnalyticsServiceable
15+
private let gameCenter: GameCenterable
1616

1717
var quizView: QuizView {
1818
if let castedView = view as? QuizView {
@@ -22,12 +22,16 @@ class QuizVC: UIViewController, UITextFieldDelegate, QuizDelegate {
2222
}
2323
}
2424

25-
convenience init(settings: Settings, quiz: Quiz, analyticsService: AnalyticsServiceable, gameCenter: GameCenterable) {
26-
self.init()
25+
init(settings: Settings, quiz: Quiz, analyticsService: AnalyticsServiceable, gameCenter: GameCenterable) {
2726
self.settings = settings
2827
self.quiz = quiz
2928
self.analyticsService = analyticsService
3029
self.gameCenter = gameCenter
30+
super.init(nibName: nil, bundle: nil)
31+
}
32+
33+
required init?(coder aDecoder: NSCoder) {
34+
fatalError("init(coder:) has not been implemented")
3135
}
3236

3337
override func loadView() {
@@ -41,9 +45,6 @@ class QuizVC: UIViewController, UITextFieldDelegate, QuizDelegate {
4145

4246
override func viewWillAppear(_ animated: Bool) {
4347
super.viewWillAppear(animated)
44-
guard let quiz = quiz else {
45-
fatalError("quiz was nil.")
46-
}
4748
quiz.delegate = self
4849
switch quiz.quizState {
4950
case .notStarted, .finished:
@@ -68,19 +69,10 @@ class QuizVC: UIViewController, UITextFieldDelegate, QuizDelegate {
6869
}
6970
quizView.startRestartButton.pulsate()
7071
authenticate()
71-
analyticsService?.recordVisitation(viewController: "\(QuizVC.self)")
72+
analyticsService.recordVisitation(viewController: "\(QuizVC.self)")
7273
}
7374

7475
private func authenticate() {
75-
guard let settings = settings else {
76-
fatalError("settings was nil.")
77-
}
78-
guard let analyticsService = analyticsService else {
79-
fatalError("analyticsService was nil.")
80-
}
81-
guard let gameCenter = gameCenter else {
82-
fatalError("gameCenter was nil.")
83-
}
8476
if !gameCenter.isAuthenticated && settings.userRejectedGameCenter {
8577
if !settings.didShowGameCenterDialog {
8678
showGameCenterDialog()
@@ -91,33 +83,21 @@ class QuizVC: UIViewController, UITextFieldDelegate, QuizDelegate {
9183
}
9284

9385
private func showGameCenterDialog() {
94-
guard let settings = settings else {
95-
fatalError("settings was nil.")
96-
}
97-
guard let analyticsService = analyticsService else {
98-
fatalError("analyticsService was nil.")
99-
}
100-
guard let gameCenter = gameCenter else {
101-
fatalError("gameCenter was nil.")
102-
}
10386
settings.didShowGameCenterDialog = true
10487
let gameCenterController = UIAlertController(title: "Game Center", message: "Would you like Conjugar to upload your future scores to Game Center after your quiz? See how you stack up against the global community of conjugators.", preferredStyle: UIAlertController.Style.alert)
10588
let noAction = UIAlertAction(title: "No", style: UIAlertAction.Style.destructive) { _ in
10689
SoundPlayer.play(.sadTrombone)
107-
settings.userRejectedGameCenter = true
90+
self.settings.userRejectedGameCenter = true
10891
}
10992
gameCenterController.addAction(noAction)
11093
let yesAction = UIAlertAction(title: "Yes", style: UIAlertAction.Style.default) { _ in
111-
gameCenter.authenticate(analyticsService: analyticsService, completion: nil)
94+
self.gameCenter.authenticate(analyticsService: self.analyticsService, completion: nil)
11295
}
11396
gameCenterController.addAction(yesAction)
11497
present(gameCenterController, animated: true, completion: nil)
11598
}
11699

117100
@objc func startRestart() {
118-
guard let quiz = quiz else {
119-
fatalError("quiz was nil.")
120-
}
121101
SoundPlayer.play(.gun)
122102
quiz.start()
123103
quizView.startRestartButton.setTitle("Restart", for: .normal)
@@ -127,7 +107,7 @@ class QuizVC: UIViewController, UITextFieldDelegate, QuizDelegate {
127107
quizView.showInProgressUI()
128108
quizView.startRestartButton.pulsate()
129109
quizView.conjugationField.becomeFirstResponder()
130-
analyticsService?.recordQuizStart()
110+
analyticsService.recordQuizStart()
131111
}
132112

133113
func scoreDidChange(newScore: Int) {
@@ -157,12 +137,6 @@ class QuizVC: UIViewController, UITextFieldDelegate, QuizDelegate {
157137
}
158138

159139
func quizDidFinish() {
160-
guard let analyticsService = analyticsService else {
161-
fatalError("analyticsService was nil.")
162-
}
163-
guard let quiz = quiz else {
164-
fatalError("quiz was nil.")
165-
}
166140
quizView.hideInProgressUI()
167141
quizView.startRestartButton.setTitle("Start", for: .normal)
168142
let applauseIndex = Int.random(in: 1...Sound.applauseCount)
@@ -182,9 +156,6 @@ class QuizVC: UIViewController, UITextFieldDelegate, QuizDelegate {
182156
}
183157

184158
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
185-
guard let quiz = quiz else {
186-
fatalError("quiz was nil.")
187-
}
188159
guard let text = quizView.conjugationField.text else { return false }
189160
guard text != "" else { return false }
190161
quizView.conjugationField.resignFirstResponder()

0 commit comments

Comments
 (0)