Skip to content

Commit 1be4d08

Browse files
authored
feat: UnitTest 코드 작성 및 Equatable 프로토콜 채택 (#64)
1 parent 6e2edff commit 1be4d08

File tree

7 files changed

+317
-32
lines changed

7 files changed

+317
-32
lines changed

Example/TSAlertController.xcodeproj/project.pbxproj

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; };
1414
607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; };
1515
607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; };
16-
607FACEC1AFB9204008FA782 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* Tests.swift */; };
16+
607FACEC1AFB9204008FA782 /* TSAlertControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* TSAlertControllerTests.swift */; };
1717
B9CB7BB683CE0BF2C0A6D730 /* Pods_TSAlertController_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 01E2986C7734B41FD672F351 /* Pods_TSAlertController_Tests.framework */; };
1818
C7692F1E2D5CB521009AB67F /* Wanderlust.ttf in Resources */ = {isa = PBXBuildFile; fileRef = C7692F1D2D5CB521009AB67F /* Wanderlust.ttf */; };
1919
/* End PBXBuildFile section */
@@ -44,14 +44,25 @@
4444
607FACDF1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
4545
607FACE51AFB9204008FA782 /* TSAlertController_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TSAlertController_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
4646
607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
47-
607FACEB1AFB9204008FA782 /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = "<group>"; };
47+
607FACEB1AFB9204008FA782 /* TSAlertControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAlertControllerTests.swift; sourceTree = "<group>"; };
4848
7C048B6697456CBE0C3CE64E /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; };
4949
C7692F1D2D5CB521009AB67F /* Wanderlust.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Wanderlust.ttf; sourceTree = "<group>"; };
5050
F0B7234F0869C770636141FB /* Pods-TSAlertController_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TSAlertController_Tests.debug.xcconfig"; path = "Target Support Files/Pods-TSAlertController_Tests/Pods-TSAlertController_Tests.debug.xcconfig"; sourceTree = "<group>"; };
5151
F20D66B1383ED02E54413689 /* Pods-TSAlertController_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TSAlertController_Example.release.xcconfig"; path = "Target Support Files/Pods-TSAlertController_Example/Pods-TSAlertController_Example.release.xcconfig"; sourceTree = "<group>"; };
5252
/* End PBXFileReference section */
5353

54+
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
55+
C755164E2D6C6C2E003A34D7 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
56+
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
57+
membershipExceptions = (
58+
MockViewController.swift,
59+
);
60+
target = 607FACCF1AFB9204008FA782 /* TSAlertController_Example */;
61+
};
62+
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
63+
5464
/* Begin PBXFileSystemSynchronizedRootGroup section */
65+
C755164A2D6C6C23003A34D7 /* Mock */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (C755164E2D6C6C2E003A34D7 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = Mock; sourceTree = "<group>"; };
5566
C7C7C55D2D5AD7E00099D5CB /* CustomView */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = CustomView; sourceTree = "<group>"; };
5667
/* End PBXFileSystemSynchronizedRootGroup section */
5768

@@ -130,7 +141,8 @@
130141
607FACE81AFB9204008FA782 /* Tests */ = {
131142
isa = PBXGroup;
132143
children = (
133-
607FACEB1AFB9204008FA782 /* Tests.swift */,
144+
C755164A2D6C6C23003A34D7 /* Mock */,
145+
607FACEB1AFB9204008FA782 /* TSAlertControllerTests.swift */,
134146
607FACE91AFB9204008FA782 /* Supporting Files */,
135147
);
136148
path = Tests;
@@ -230,6 +242,9 @@
230242
dependencies = (
231243
607FACE71AFB9204008FA782 /* PBXTargetDependency */,
232244
);
245+
fileSystemSynchronizedGroups = (
246+
C755164A2D6C6C23003A34D7 /* Mock */,
247+
);
233248
name = TSAlertController_Tests;
234249
productName = Tests;
235250
productReference = 607FACE51AFB9204008FA782 /* TSAlertController_Tests.xctest */;
@@ -378,7 +393,7 @@
378393
isa = PBXSourcesBuildPhase;
379394
buildActionMask = 2147483647;
380395
files = (
381-
607FACEC1AFB9204008FA782 /* Tests.swift in Sources */,
396+
607FACEC1AFB9204008FA782 /* TSAlertControllerTests.swift in Sources */,
382397
);
383398
runOnlyForDeploymentPostprocessing = 0;
384399
};
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//
2+
// MockViewController.swift
3+
// TSAlertController
4+
//
5+
// Created by 김건우 on 2/24/25.
6+
// Copyright © 2025 CocoaPods. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
final class MockViewController: UIViewController {
12+
var presentViewControllerTarget: UIViewController?
13+
14+
override func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
15+
//
16+
viewControllerToPresent.loadViewIfNeeded()
17+
//
18+
viewControllerToPresent.beginAppearanceTransition(true, animated: flag)
19+
viewControllerToPresent.endAppearanceTransition()
20+
21+
//
22+
presentViewControllerTarget = viewControllerToPresent
23+
}
24+
}
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
import XCTest
2+
@testable import TSAlertController
3+
4+
final class TSAlertControllerTests: XCTestCase {
5+
6+
func testTSAlertController_WhenInitialized_ShouldSetTitleMessageAndPreferredStyle() {
7+
// given
8+
let alertController = TSAlertController(
9+
title: "The title of the alert",
10+
message: "Descriptive text that provides more details about the reason for the alert.",
11+
preferredStyle: .alert
12+
)
13+
let mockViewController = MockViewController()
14+
15+
// when
16+
mockViewController.present(alertController, animated: true)
17+
18+
// then
19+
XCTAssertEqual(alertController.title, "The title of the alert")
20+
XCTAssertEqual(alertController.message, "Descriptive text that provides more details about the reason for the alert.")
21+
XCTAssertEqual(alertController.preferredStyle, .alert)
22+
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
23+
}
24+
25+
func testTSAlertController_WhenIntializedWithTextFields_ShouldSetTextFields() {
26+
// given
27+
let alertController = TSAlertController(
28+
title: "The title of the alert",
29+
preferredStyle: .alert
30+
)
31+
let mockViewController = MockViewController()
32+
33+
alertController.addTextField()
34+
alertController.addTextField()
35+
36+
// when
37+
mockViewController.present(alertController, animated: true)
38+
39+
// then
40+
XCTAssertEqual(alertController.textFields?.count, 2)
41+
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
42+
}
43+
44+
func testTSAlertController_WhenInitializedWithTwoButtonsAndAutomaticAxis_ShouldSetCorrectActionsOrderAndCount() {
45+
// given
46+
let alertController = TSAlertController(
47+
title: "The title of the alert",
48+
preferredStyle: .alert
49+
)
50+
let mockViewController = MockViewController()
51+
52+
let ok = TSAlertAction(title: "OK", style: .default)
53+
let cancel = TSAlertAction(title: "Cancel", style: .cancel)
54+
alertController.addAction(ok)
55+
alertController.addAction(cancel)
56+
57+
// when
58+
mockViewController.present(alertController, animated: true)
59+
60+
// then
61+
let actions = alertController.actions
62+
XCTAssertEqual(actions.count, 2)
63+
XCTAssertEqual(actions[0], cancel) // In LTR, the Cancel button is positioned at the far right.
64+
XCTAssertEqual(alertController.viewConfiguration.buttonGroupAxis, .horizontal)
65+
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
66+
}
67+
68+
func testTSAlertController_WhenIntializedWithFourButtonsAndAutomaticAxis_ShouldSetCorrectActionsOrderAndCount() {
69+
// given
70+
let alertController = TSAlertController(
71+
title: "The title of the alert",
72+
preferredStyle: .alert
73+
)
74+
let mockViewController = MockViewController()
75+
76+
let home = TSAlertAction(title: "Go to Home", style: .default)
77+
let profile = TSAlertAction(title: "Go to Profile", style: .default)
78+
let settings = TSAlertAction(title: "Go to Settings", style: .default)
79+
let cancel = TSAlertAction(title: "Cancel", style: .cancel)
80+
alertController.addAction(home)
81+
alertController.addAction(profile)
82+
alertController.addAction(cancel)
83+
alertController.addAction(settings)
84+
85+
// when
86+
mockViewController.present(alertController, animated: true)
87+
88+
// then
89+
let actions = alertController.actions
90+
XCTAssertEqual(actions.count, 4)
91+
XCTAssertEqual(actions[3], cancel) // If the button axis is vertical, the Cancel button is positioned at the very bottom.
92+
XCTAssertEqual(actions, [home, profile, settings, cancel])
93+
XCTAssertEqual(alertController.viewConfiguration.buttonGroupAxis, .vertical)
94+
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
95+
}
96+
97+
func testTSAlertController_WhenInitalizedWithFourButtonsAndAutomaticAxis_ShouldSetCorrectActionsOrderAndCount() {
98+
// given
99+
let alertController = TSAlertController(
100+
title: "The title of the alert",
101+
preferredStyle: .alert
102+
)
103+
let mockViewController = MockViewController()
104+
105+
alertController.addAction(.init(title: "Cancel", style: .cancel))
106+
}
107+
108+
109+
func testTSAlertController_WhenIntlaizedWithAlertStyle_ShouldSetDefaultConfiguration() {
110+
// given
111+
let alertController = TSAlertController(
112+
title: "The title of the alert",
113+
preferredStyle: .alert
114+
)
115+
let mockViewController = MockViewController()
116+
117+
// when
118+
mockViewController.present(alertController, animated: true)
119+
120+
// then
121+
let config = alertController.configuration
122+
XCTAssertEqual(config.enteringTransition, .fadeInAndScaleDown)
123+
XCTAssertEqual(config.exitingTransition, .fadeOut)
124+
XCTAssertEqual(config.headerAnimation, .none)
125+
XCTAssertEqual(config.buttonGroupAnimation, .none)
126+
XCTAssertEqual(config.prefersGrabberVisible, false)
127+
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
128+
}
129+
130+
func testTSAlertController_WhenIntializedWithAlertStyle_SouldSetEnforceCorrectConfiguration() {
131+
// given
132+
let alertController = TSAlertController(
133+
title: "The title of the alert",
134+
preferredStyle: .alert
135+
)
136+
let mockViewController = MockViewController()
137+
138+
// when
139+
alertController.configuration.prefersGrabberVisible = true
140+
mockViewController.present(alertController, animated: true)
141+
142+
// then
143+
let config = alertController.configuration
144+
XCTAssertEqual(config.prefersGrabberVisible, false)
145+
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
146+
}
147+
148+
func testTSAlertController_WhenIntializedWithFloatingSheetStyle_ShouldSetDefaultConfiguration() {
149+
// given
150+
let alertController = TSAlertController(
151+
title: "The title of the alert",
152+
preferredStyle: .floatingSheet
153+
)
154+
let mockViewController = MockViewController()
155+
156+
// when
157+
mockViewController.present(alertController, animated: true)
158+
159+
// then
160+
let config = alertController.configuration
161+
XCTAssertEqual(config.enteringTransition, .slideUp)
162+
XCTAssertEqual(config.exitingTransition, .slideDown)
163+
XCTAssertEqual(config.headerAnimation, .none)
164+
XCTAssertEqual(config.buttonGroupAnimation, .none)
165+
XCTAssertEqual(config.prefersGrabberVisible, true)
166+
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
167+
}
168+
169+
func testTSAlertController_WhenIntilizedWithFloatinSheetStyle_ShouldSetEnforceCorrectConfiguration() {
170+
// given
171+
let alertController = TSAlertController(
172+
title: "The title of the alert",
173+
preferredStyle: .floatingSheet
174+
)
175+
let mockViewController = MockViewController()
176+
177+
// when
178+
mockViewController.present(alertController, animated: true)
179+
180+
// then
181+
XCTAssertTrue(true)
182+
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
183+
}
184+
185+
func testTSAlertController_WhenIntializedWithAlertStyle_ShouldSetDefaultViewConfiguration() {
186+
// given
187+
let alertController = TSAlertController(
188+
title: "The title of the alert",
189+
preferredStyle: .alert
190+
)
191+
let mockViewController = MockViewController()
192+
193+
// when
194+
mockViewController.present(alertController, animated: true)
195+
196+
// then
197+
let viewConfig = alertController.viewConfiguration
198+
XCTAssertEqual(viewConfig.size.width, .proportional(minimumRatio: 0.75, maximumRatio: 0.75))
199+
XCTAssertEqual(viewConfig.spacing.keyboardSpacing, 100)
200+
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
201+
}
202+
203+
func testTSAlertController_WhenInitializedWithFloatingSheetStyle_ShouldSetDefaultViewConfiguration() {
204+
// given
205+
let alertController = TSAlertController(
206+
title: "The title of the alert",
207+
preferredStyle: .floatingSheet
208+
)
209+
let mockViewController = MockViewController()
210+
211+
// when
212+
mockViewController.present(alertController, animated: true)
213+
214+
// then
215+
let viewConfig = alertController.viewConfiguration
216+
XCTAssertEqual(viewConfig.size.width, .proportional(minimumRatio: 0.95, maximumRatio: 0.95))
217+
XCTAssertEqual(viewConfig.spacing.keyboardSpacing, 20)
218+
XCTAssertEqual(mockViewController.presentViewControllerTarget, alertController)
219+
}
220+
221+
}

Example/Tests/Tests.swift

Lines changed: 0 additions & 28 deletions
This file was deleted.

Sources/TSAlert/TSAlertController+AnimationType.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,19 @@ public extension TSAlertController {
7070
}
7171
}
7272
}
73+
74+
75+
// MARK: - Equatable
76+
77+
extension TSAlertController.AnimationType: Equatable {
78+
public static func == (lhs: Self, rhs: Self) -> Bool {
79+
switch (lhs, rhs) {
80+
case (.fadeIn, .fadeIn), (.slideUp, .slideUp):
81+
return true
82+
case let (.custom(lhsTransform, lhsAlpha), .custom(rhsTransform, rhsAlpha)):
83+
return lhsTransform == rhsTransform && lhsAlpha == rhsAlpha
84+
default:
85+
return false
86+
}
87+
}
88+
}

Sources/TSAlert/TSAlertController+TransitionType.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,31 @@ public extension TSAlertController {
7777
}
7878
}
7979
}
80+
81+
82+
// MARK: - Equatable
83+
84+
extension TSAlertController.EnteringTransitionType: Equatable {
85+
public static func == (lhs: Self, rhs: Self) -> Bool {
86+
switch (lhs, rhs) {
87+
case (.fadeInAndScaleDown, .fadeInAndScaleDown), (.slideUp, .slideUp):
88+
return true
89+
case let (.custom(lhsTransition), .custom(rhsTransition)):
90+
return ObjectIdentifier(lhsTransition) == ObjectIdentifier(rhsTransition)
91+
default:
92+
return false
93+
}
94+
}
95+
}
96+
extension TSAlertController.ExitingTransitionType: Equatable {
97+
public static func == (lhs: Self, rhs: Self) -> Bool {
98+
switch (lhs, rhs) {
99+
case (.fadeOut, .fadeOut), (.slideDown, .slideDown):
100+
return true
101+
case let (.custom(lhsTransition), .custom(rhsTransition)):
102+
return ObjectIdentifier(lhsTransition) == ObjectIdentifier(rhsTransition)
103+
default:
104+
return false
105+
}
106+
}
107+
}

0 commit comments

Comments
 (0)